Пример #1
0
/*!
   This function returns a rasterized image of the glyph at the given
   \a glyphIndex in the underlying font, using the \a transform specified.
   If the QRawFont is not valid, this function will return an invalid QImage.

   If \a antialiasingType is set to QRawFont::SubPixelAntialiasing, then the resulting image will be
   in QImage::Format_RGB32 and the RGB values of each pixel will represent the subpixel opacities of
   the pixel in the rasterization of the glyph. Otherwise, the image will be in the format of
   QImage::Format_Indexed8 and each pixel will contain the opacity of the pixel in the
   rasterization.

   \sa pathForGlyph(), QPainter::drawGlyphRun()
*/
QImage QRawFont::alphaMapForGlyph(quint32 glyphIndex, AntialiasingType antialiasingType,
                                  const QTransform &transform) const
{
    if (!d->isValid())
        return QImage();

    if (antialiasingType == SubPixelAntialiasing)
        return d->fontEngine->alphaRGBMapForGlyph(glyphIndex, QFixed(), transform);

    return d->fontEngine->alphaMapForGlyph(glyphIndex, QFixed(), transform);
}
Пример #2
0
void QFontEngineWin::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
{
    HGDIOBJ oldFont = 0;
    HDC hdc = shared_dc();
    if (ttf && (flags & QTextEngine::DesignMetrics)) {
        for(int i = 0; i < glyphs->numGlyphs; i++) {
            unsigned int glyph = glyphs->glyphs[i];
            if(int(glyph) >= designAdvancesSize) {
                int newSize = (glyph + 256) >> 8 << 8;
                designAdvances = q_check_ptr((QFixed *)realloc(designAdvances,
                            newSize*sizeof(QFixed)));
                for(int i = designAdvancesSize; i < newSize; ++i)
                    designAdvances[i] = -1000000;
                designAdvancesSize = newSize;
            }
            if (designAdvances[glyph] < -999999) {
                if (!oldFont)
                    oldFont = selectDesignFont();

                int width = 0;
                calculateTTFGlyphWidth(hdc, glyph, width);
                designAdvances[glyph] = QFixed(width) / designToDevice;
            }
            glyphs->advances_x[i] = designAdvances[glyph];
            glyphs->advances_y[i] = 0;
        }
        if(oldFont)
            DeleteObject(SelectObject(hdc, oldFont));
    } else {
Пример #3
0
void QFontEngineWin::getCMap()
{
    ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE);
    HDC hdc = shared_dc();
    SelectObject(hdc, hfont);
    bool symb = false;
    if (ttf) {
        cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p')));
        int size = 0;
        cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
                       cmapTable.size(), &symb, &size);
    }
    if (!cmap) {
        ttf = false;
        symb = false;
    }
    symbol = symb;
    designToDevice = 1;
    _faceId.index = 0;
    if(cmap) {
        OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
        designToDevice = QFixed((int)otm->otmEMSquare)/int(otm->otmTextMetrics.tmHeight);
        unitsPerEm = otm->otmEMSquare;
        x_height = (int)otm->otmsXHeight;
        loadKerningPairs(designToDevice);
        _faceId.filename = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFullName)).toLatin1();
        lineWidth = otm->otmsUnderscoreSize;
        fsType = otm->otmfsType;
        free(otm);
    } else {
        unitsPerEm = tm.tmHeight;
    }
}
Пример #4
0
void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
{
    HGDIOBJ oldFont = 0;
    HDC hdc = m_fontEngineData->hdc;
    if (ttf && (flags & DesignMetrics)) {
        for(int i = 0; i < glyphs->numGlyphs; i++) {
            unsigned int glyph = glyphs->glyphs[i];
            if(int(glyph) >= designAdvancesSize) {
                const int newSize = int(glyph + 256) >> 8 << 8;
                designAdvances = reinterpret_cast<QFixed *>(realloc(designAdvances, size_t(newSize) * sizeof(QFixed)));
                Q_CHECK_PTR(designAdvances);
                for(int i = designAdvancesSize; i < newSize; ++i)
                    designAdvances[i] = -1000000;
                designAdvancesSize = newSize;
            }
            if (designAdvances[glyph] < -999999) {
                if (!oldFont)
                    oldFont = selectDesignFont();

                int width = 0;
                calculateTTFGlyphWidth(hdc, glyph, width);
                designAdvances[glyph] = QFixed(width) / designToDevice;
            }
            glyphs->advances[i] = designAdvances[glyph];
        }
        if(oldFont)
            DeleteObject(SelectObject(hdc, oldFont));
    } else {
        for(int i = 0; i < glyphs->numGlyphs; i++) {
Пример #5
0
void QPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
{
    const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
    if (ti.glyphs.numGlyphs == 0)
        return;

    if (ti.fontEngine->glyphFormat == QFontEngine::Format_ARGB) {
        QVarLengthArray<QFixedPoint> positions;
        QVarLengthArray<glyph_t> glyphs;
        QTransform matrix = QTransform::fromTranslate(p.x(), p.y() - ti.fontEngine->ascent().toReal());
        ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
        painter()->save();
        painter()->setRenderHint(QPainter::SmoothPixmapTransform,
                                 bool((painter()->renderHints() & QPainter::TextAntialiasing)
                                      && !(painter()->font().styleStrategy() & QFont::NoAntialias)));
        for (int i = 0; i < ti.glyphs.numGlyphs; ++i) {
            QImage glyph = ti.fontEngine->bitmapForGlyph(glyphs[i], QFixed(), QTransform());
            painter()->drawImage(positions[i].x.toReal(), positions[i].y.toReal(), glyph);
        }
        painter()->restore();
        return;
    }

    QPainterPath path;
    path.setFillRule(Qt::WindingFill);
    ti.fontEngine->addOutlineToPath(0, 0, ti.glyphs, &path, ti.flags);
    if (!path.isEmpty()) {
        painter()->save();
        painter()->setRenderHint(QPainter::Antialiasing,
                                 bool((painter()->renderHints() & QPainter::TextAntialiasing)
                                      && !(painter()->font().styleStrategy() & QFont::NoAntialias)));
        painter()->translate(p.x(), p.y());
        painter()->fillPath(path, painter()->pen().brush());
        painter()->restore();
    }
}
Пример #6
0
bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
                                                const QFixedPoint *positions)
{
#ifdef CACHE_DEBUG
    printf("Populating with %d glyphs\n", numGlyphs);
    qDebug() << " -> current transformation: " << m_transform;
#endif

    m_current_fontengine = fontEngine;
    const int margin = m_current_fontengine->glyphMargin(m_type);
    const int paddingDoubled = glyphPadding() * 2;

    bool supportsSubPixelPositions = fontEngine->supportsSubPixelPositions();
    if (fontEngine->m_subPixelPositionCount == 0) {
        if (!supportsSubPixelPositions) {
            fontEngine->m_subPixelPositionCount = 1;
        } else {
            int i = 0;
            while (fontEngine->m_subPixelPositionCount == 0 && i < numGlyphs)
                fontEngine->m_subPixelPositionCount = calculateSubPixelPositionCount(glyphs[i++]);
        }
    }

    QHash<GlyphAndSubPixelPosition, Coord> listItemCoordinates;
    int rowHeight = 0;

    QFontEngine::GlyphFormat format;
    switch (m_type) {
    case Raster_A8: format = QFontEngine::Format_A8; break;
    case Raster_RGBMask: format = QFontEngine::Format_A32; break;
    default: format = QFontEngine::Format_Mono; break;
    }

    // check each glyph for its metrics and get the required rowHeight.
    for (int i=0; i < numGlyphs; ++i) {
        const glyph_t glyph = glyphs[i];

        QFixed subPixelPosition;
        if (supportsSubPixelPositions) {
            QFixed x = positions != 0 ? positions[i].x : QFixed();
            subPixelPosition = fontEngine->subPixelPositionForX(x);
        }

        if (coords.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
            continue;
        if (listItemCoordinates.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
            continue;
        glyph_metrics_t metrics = fontEngine->alphaMapBoundingBox(glyph, subPixelPosition, m_transform, format);

#ifdef CACHE_DEBUG
        printf("(%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f\n",
               glyph,
               metrics.width.toReal(),
               metrics.height.toReal(),
               metrics.xoff.toReal(),
               metrics.yoff.toReal(),
               metrics.x.toReal(),
               metrics.y.toReal());
#endif        
        GlyphAndSubPixelPosition key(glyph, subPixelPosition);
        int glyph_width = metrics.width.ceil().toInt();
        int glyph_height = metrics.height.ceil().toInt();
        if (glyph_height == 0 || glyph_width == 0) {
            // Avoid multiple calls to boundingBox() for non-printable characters
            Coord c = { 0, 0, 0, 0, 0, 0 };
            coords.insert(key, c);
            continue;
        }
        glyph_width += margin * 2 + 4;
        glyph_height += margin * 2 + 4;
        // align to 8-bit boundary
        if (m_type == QFontEngineGlyphCache::Raster_Mono)
            glyph_width = (glyph_width+7)&~7;

        Coord c = { 0, 0, // will be filled in later
                    glyph_width,
                    glyph_height, // texture coords
                    metrics.x.truncate(),
                    -metrics.y.truncate() }; // baseline for horizontal scripts

        listItemCoordinates.insert(key, c);
        rowHeight = qMax(rowHeight, glyph_height);
    }
    if (listItemCoordinates.isEmpty())
        return true;

    rowHeight += margin * 2 + paddingDoubled;

    if (m_w == 0) {
        if (fontEngine->maxCharWidth() <= QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH)
            m_w = QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH;
        else
            m_w = qt_next_power_of_two(fontEngine->maxCharWidth());
    }

    // now actually use the coords and paint the wanted glyps into cache.
    QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = listItemCoordinates.begin();
    int requiredWidth = m_w;
    while (iter != listItemCoordinates.end()) {
        Coord c = iter.value();

        m_currentRowHeight = qMax(m_currentRowHeight, c.h + margin * 2);

        if (m_cx + c.w > requiredWidth) {
            int new_width = requiredWidth*2;
            while (new_width < m_cx + c.w)
                new_width *= 2;
            if (new_width <= maxTextureWidth()) {
                requiredWidth = new_width;
            } else {
                // no room on the current line, start new glyph strip
                m_cx = 0;
                m_cy += m_currentRowHeight + paddingDoubled;
                m_currentRowHeight = c.h + margin * 2; // New row
            }
        }

        if (maxTextureHeight() > 0 && m_cy + c.h > maxTextureHeight()) {
            // We can't make a cache of the required size, so we bail out
            return false;
        }

        c.x = m_cx;
        c.y = m_cy;

        coords.insert(iter.key(), c);
        m_pendingGlyphs.insert(iter.key(), c);

        m_cx += c.w + paddingDoubled;
        ++iter;
    }
    return true;

}
Пример #7
0
	void parseWords(QFixed minResizeWidth, int32 blockFrom) {
		LineBreakHelper lbh;

		lbh.maxGlyphs = INT_MAX;

		int item = -1;
		int newItem = eng->findItem(0);

		style::align alignment = eng->option.alignment();

		const QCharAttributes *attributes = eng->attributes();
		if (!attributes)
			return;
		lbh.currentPosition = 0;
		int end = 0;
		lbh.logClusters = eng->layoutData->logClustersPtr;
		lbh.previousGlyph = 0;

		block->_lpadding = 0;
		block->_words.clear();

		int wordStart = lbh.currentPosition;

		bool addingEachGrapheme = false;
		int lastGraphemeBoundaryPosition = -1;
		ScriptLine lastGraphemeBoundaryLine;

		while (newItem < eng->layoutData->items.size()) {
			if (newItem != item) {
				item = newItem;
				const QScriptItem &current = eng->layoutData->items[item];
				if (!current.num_glyphs) {
					eng->shape(item);
					attributes = eng->attributes();
					if (!attributes)
						return;
					lbh.logClusters = eng->layoutData->logClustersPtr;
				}
				lbh.currentPosition = current.position;
				end = current.position + eng->length(item);
				lbh.glyphs = eng->shapedGlyphs(&current);
				QFontEngine *fontEngine = eng->fontEngine(current);
				if (lbh.fontEngine != fontEngine) {
					lbh.fontEngine = fontEngine;
				}
			}
			const QScriptItem &current = eng->layoutData->items[item];

			if (attributes[lbh.currentPosition].whiteSpace) {
				while (lbh.currentPosition < end && attributes[lbh.currentPosition].whiteSpace)
					addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount,
						current, lbh.logClusters, lbh.glyphs);

				if (block->_words.isEmpty()) {
					block->_lpadding = lbh.spaceData.textWidth;
				} else {
					block->_words.back().rpadding += lbh.spaceData.textWidth;
					block->_width += lbh.spaceData.textWidth;
				}
				lbh.spaceData.length = 0;
				lbh.spaceData.textWidth = 0;

				wordStart = lbh.currentPosition;

				addingEachGrapheme = false;
				lastGraphemeBoundaryPosition = -1;
				lastGraphemeBoundaryLine = ScriptLine();
			} else {
				do {
					addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
						current, lbh.logClusters, lbh.glyphs);

					if (lbh.currentPosition >= eng->layoutData->string.length()
						|| attributes[lbh.currentPosition].whiteSpace
						|| isLineBreak(attributes, lbh.currentPosition)) {
						lbh.adjustRightBearing();
						block->_words.push_back(TextWord(wordStart + blockFrom, lbh.tmpData.textWidth, qMin(QFixed(), lbh.rightBearing)));
						block->_width += lbh.tmpData.textWidth;
						lbh.tmpData.textWidth = 0;
						lbh.tmpData.length = 0;
						wordStart = lbh.currentPosition;
						break;
					} else if (attributes[lbh.currentPosition].graphemeBoundary) {
						if (!addingEachGrapheme && lbh.tmpData.textWidth > minResizeWidth) {
							if (lastGraphemeBoundaryPosition >= 0) {
								lbh.adjustPreviousRightBearing();
								block->_words.push_back(TextWord(wordStart + blockFrom, -lastGraphemeBoundaryLine.textWidth, qMin(QFixed(), lbh.rightBearing)));
								block->_width += lastGraphemeBoundaryLine.textWidth;
								lbh.tmpData.textWidth -= lastGraphemeBoundaryLine.textWidth;
								lbh.tmpData.length -= lastGraphemeBoundaryLine.length;
								wordStart = lastGraphemeBoundaryPosition;
							}
							addingEachGrapheme = true;
						}
						if (addingEachGrapheme) {
							lbh.adjustRightBearing();
							block->_words.push_back(TextWord(wordStart + blockFrom, -lbh.tmpData.textWidth, qMin(QFixed(), lbh.rightBearing)));
							block->_width += lbh.tmpData.textWidth;
							lbh.tmpData.textWidth = 0;
							lbh.tmpData.length = 0;
							wordStart = lbh.currentPosition;
						} else {
							lastGraphemeBoundaryPosition = lbh.currentPosition;
							lastGraphemeBoundaryLine = lbh.tmpData;
							lbh.saveCurrentGlyph();
						}
					}
				} while (lbh.currentPosition < end);
			}
			if (lbh.currentPosition == end)
				newItem = item + 1;
		}
		if (block->_words.isEmpty()) {
			block->_rpadding = 0;
		} else {
			block->_rpadding = block->_words.back().rpadding;
			block->_width -= block->_rpadding;
			block->_words.squeeze();
		}
	}