void QFontEngineQPF::ensureGlyphsLoaded(const QGlyphLayout *glyphs, int len) { if (readOnly) return; bool locked = false; for (int i = 0; i < len; ++i) { if (!glyphs[i].glyph) continue; const Glyph *g = findGlyph(glyphs[i].glyph); if (g) continue; if (!locked) { if (!lockFile()) return; locked = true; g = findGlyph(glyphs[i].glyph); if (g) continue; } loadGlyph(glyphs[i].glyph); } if (locked) { unlockFile(); #if defined(DEBUG_FONTENGINE) qDebug() << "Finished rendering glyphs\n"; #endif } }
glyph_metrics_t QFontEngineQPF::boundingBox(const QGlyphLayout *glyphs, int numGlyphs) { #ifndef QT_NO_FREETYPE const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(glyphs, numGlyphs); #endif glyph_metrics_t overall; // initialize with line height, we get the same behaviour on all platforms overall.y = -ascent(); overall.height = ascent() + descent() + 1; QFixed ymax = 0; QFixed xmax = 0; for (int i = 0; i < numGlyphs; i++) { const Glyph *g = findGlyph(glyphs[i].glyph); if (!g) continue; QFixed x = overall.xoff + glyphs[i].offset.x + g->x; QFixed y = overall.yoff + glyphs[i].offset.y + g->y; overall.x = qMin(overall.x, x); overall.y = qMin(overall.y, y); xmax = qMax(xmax, x + g->width); ymax = qMax(ymax, y + g->height); overall.xoff += g->advance; } overall.height = qMax(overall.height, ymax - overall.y); overall.width = xmax - overall.x; return overall; }
void QFontEngineQPF::draw(QPaintEngine *p, qreal _x, qreal _y, const QTextItemInt &si) { QPaintEngineState *pState = p->state; QRasterPaintEngine *paintEngine = static_cast<QRasterPaintEngine*>(p); QTransform matrix = pState->transform(); matrix.translate(_x, _y); QFixed x = QFixed::fromReal(matrix.dx()); QFixed y = QFixed::fromReal(matrix.dy()); QVarLengthArray<QFixedPoint> positions; QVarLengthArray<glyph_t> glyphs; getGlyphPositions(si.glyphs, si.num_glyphs, matrix, si.flags, glyphs, positions); if (glyphs.size() == 0) return; for(int i = 0; i < glyphs.size(); i++) { const Glyph *glyph = findGlyph(glyphs[i]); if (!glyph) continue; const bool mono = false; // ### paintEngine->alphaPenBlt(reinterpret_cast<const uchar *>(glyph) + sizeof(Glyph), glyph->bytesPerLine, mono, qRound(positions[i].x) + glyph->x, qRound(positions[i].y) + glyph->y, glyph->width, glyph->height); } }
glyph_metrics_t QFontEngineQPA::boundingBox(const QGlyphLayout &glyphs) { glyph_metrics_t overall; // initialize with line height, we get the same behaviour on all platforms overall.y = -ascent(); overall.height = ascent() + descent() + 1; QFixed ymax = 0; QFixed xmax = 0; for (int i = 0; i < glyphs.numGlyphs; i++) { const Glyph *g = findGlyph(glyphs.glyphs[i]); if (!g) continue; QFixed x = overall.xoff + glyphs.offsets[i].x + g->x; QFixed y = overall.yoff + glyphs.offsets[i].y + g->y; overall.x = qMin(overall.x, x); overall.y = qMin(overall.y, y); xmax = qMax(xmax, x + g->width); ymax = qMax(ymax, y + g->height); overall.xoff += g->advance; } overall.height = qMax(overall.height, ymax - overall.y); overall.width = xmax - overall.x; return overall; }
void Font::setGlyphToPath(unsigned int index, VGPath path, bool isHinted, const Vector2& origin, const Vector2& escapement) { Glyph* g = findGlyph(index); if(g) { //glyph exists, replace clearGlyph(g); } else { //glyph doesn't exist, allocate a new one g = newGlyph(); } g->m_index = index; g->m_state = Glyph::GLYPH_PATH; g->m_path = path; g->m_image = VG_INVALID_HANDLE; g->m_isHinted = isHinted; g->m_origin = origin; g->m_escapement = escapement; if(path != VG_INVALID_HANDLE) { Path* p = (Path*)path; p->addReference(); } }
RenderedGlyphContainer::RenderedGlyph RenderedGlyphContainer::getGlyph(glyph_char glyph, void*fontptr, void*renderer, unsigned int size, int fontstyle, bool antialiasing) { size_t index = ARRAYLIST_NOTFOUND; for(size_t i=0; i<glyphs.size(); i++) { if(glyphs.get(i).first == glyph) { index = i; i = glyphs.size(); } } if(index == ARRAYLIST_NOTFOUND) { RenderedGlyphStyles* glyphStyles = new RenderedGlyphStyles(); glyphs.add(Pair<glyph_char, RenderedGlyphStyles*>(glyph, glyphStyles)); RenderedGlyph renderedGlyph = renderGlyph(glyph, fontptr, renderer, size, fontstyle, antialiasing); glyphStyles->styles.add(renderedGlyph); return renderedGlyph; } else { RenderedGlyphStyles* glyphStyles = glyphs.get(index).second; ArrayList<RenderedGlyph>& renderedGlyphs = glyphStyles->styles; RenderedGlyph renderedGlyph = findGlyph(renderedGlyphs, size, fontstyle, antialiasing); if(renderedGlyph.texture == nullptr) { renderedGlyph = renderGlyph(glyph, fontptr, renderer, size, fontstyle, antialiasing); glyphStyles->styles.add(renderedGlyph); } return renderedGlyph; } }
void Font::setGlyphToImage(unsigned int index, VGImage image, const Vector2& origin, const Vector2& escapement) { Glyph* g = findGlyph(index); if(g) { //glyph exists, replace clearGlyph(g); } else { //glyph doesn't exist, allocate a new one g = newGlyph(); } g->m_index = index; g->m_state = Glyph::GLYPH_IMAGE; g->m_path = VG_INVALID_HANDLE; g->m_image = image; g->m_isHinted = false; g->m_origin = origin; g->m_escapement = escapement; if(image != VG_INVALID_HANDLE) { Image* p = (Image*)image; p->addReference(); p->addInUse(); } }
const glyph* Font::getGlyph(int code) const { const glyph* g = findGlyph(code); if (g) return g; glyph gl; Font* fn = const_cast<Font*>(this); if (fn->loadGlyph(code, gl)) { fn->_glyphs.insert(gl); g = findGlyph(code); OX_ASSERT(g); } return g; }
void QFontEngineQPF2::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const { for (int i = 0; i < glyphs->numGlyphs; ++i) { const Glyph *g = findGlyph(glyphs->glyphs[i]); if (!g) continue; glyphs->advances[i] = g->advance; } }
glyph_t QFontEngineQPF2::glyphIndex(uint ucs4) const { glyph_t glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4); if (glyph == 0 && symbol && ucs4 < 0x100) glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000); if (!findGlyph(glyph)) glyph = 0; return glyph; }
QImage QFontEngineQPA::alphaMapForGlyph(glyph_t g) { const Glyph *glyph = findGlyph(g); if (!glyph) return QImage(); const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph); QImage image(bits,glyph->width, glyph->height, glyph->bytesPerLine, QImage::Format_Indexed8); return image; }
glyph_metrics_t QFontEngineQPA::boundingBox(glyph_t glyph) { glyph_metrics_t overall; const Glyph *g = findGlyph(glyph); if (!g) return overall; overall.x = g->x; overall.y = g->y; overall.width = g->width; overall.height = g->height; overall.xoff = g->advance; return overall; }
bool QFontEngineQPF::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const { if (!externalCMap && !cmapOffset && renderingFontEngine) { if (!renderingFontEngine->stringToCMap(str, len, glyphs, nglyphs, flags)) return false; #ifndef QT_NO_FREETYPE const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(glyphs, *nglyphs); #endif return true; } if (*nglyphs < len) { *nglyphs = len; return false; } #if defined(DEBUG_FONTENGINE) QSet<QChar> seenGlyphs; #endif const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset); int glyph_pos = 0; if (symbol) { for (int i = 0; i < len; ++i) { unsigned int uc = getChar(str, i, len); glyphs[glyph_pos].glyph = getTrueTypeGlyphIndex(cmap, uc); if(!glyphs[glyph_pos].glyph && uc < 0x100) glyphs[glyph_pos].glyph = getTrueTypeGlyphIndex(cmap, uc + 0xf000); ++glyph_pos; } } else { for (int i = 0; i < len; ++i) { unsigned int uc = getChar(str, i, len); glyphs[glyph_pos].glyph = getTrueTypeGlyphIndex(cmap, uc); #if 0 && defined(DEBUG_FONTENGINE) QChar c(uc); if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c)) qDebug() << "glyph for character" << c << "/" << hex << uc << "is" << dec << glyphs[glyph_pos].glyph; seenGlyphs.insert(c); #endif ++glyph_pos; } } *nglyphs = glyph_pos; recalcAdvances(*nglyphs, glyphs, flags); return true; }
void QFontEngineQPF::recalcAdvances(int len, QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const { #ifndef QT_NO_FREETYPE const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(glyphs, len); #endif for (int i = 0; i < len; ++i) { const Glyph *g = findGlyph(glyphs[i].glyph); if (!g) { glyphs[i].glyph = 0; continue; } glyphs[i].advance.x = g->advance; glyphs[i].advance.y = 0; } }
bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const { if (*nglyphs < len) { *nglyphs = len; return false; } #if defined(DEBUG_FONTENGINE) QSet<QChar> seenGlyphs; #endif const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset); bool mirrored = flags & QTextEngine::RightToLeft; int glyph_pos = 0; if (symbol) { for (int i = 0; i < len; ++i) { unsigned int uc = getChar(str, i, len); if (mirrored) uc = QChar::mirroredChar(uc); glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); if(!glyphs->glyphs[glyph_pos] && uc < 0x100) glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000); ++glyph_pos; } } else { for (int i = 0; i < len; ++i) { unsigned int uc = getChar(str, i, len); if (mirrored) uc = QChar::mirroredChar(uc); glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); #if 0 && defined(DEBUG_FONTENGINE) QChar c(uc); if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c)) qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph; seenGlyphs.insert(c); #endif ++glyph_pos; } } *nglyphs = glyph_pos; glyphs->numGlyphs = glyph_pos; recalcAdvances(glyphs, flags); return true; }
bool QFontEngineQPF2::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const { Q_ASSERT(glyphs->numGlyphs >= *nglyphs); if (*nglyphs < len) { *nglyphs = len; return false; } #if defined(DEBUG_FONTENGINE) QSet<QChar> seenGlyphs; #endif int glyph_pos = 0; if (symbol) { QStringIterator it(str, str + len); while (it.hasNext()) { const uint uc = it.next(); glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); if(!glyphs->glyphs[glyph_pos] && uc < 0x100) glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000); ++glyph_pos; } } else { QStringIterator it(str, str + len); while (it.hasNext()) { const uint uc = it.next(); glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); #if 0 && defined(DEBUG_FONTENGINE) QChar c(uc); if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c)) qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph; seenGlyphs.insert(c); #endif ++glyph_pos; } } *nglyphs = glyph_pos; glyphs->numGlyphs = glyph_pos; if (!(flags & GlyphIndicesOnly)) recalcAdvances(glyphs, flags); return true; }
Rect Font::boundsOf(const char* text) { vec2 pen; Rect bounds; const size_t length = std::strlen(text); for (const char* c = text; *c != '\0'; ) { const uint32 codepoint = utf8::next<const char*>(c, text + length); if (const Glyph* glyph = findGlyph(codepoint)) { bounds.envelop(Rect(glyph->bearing + pen, glyph->size)); pen = round(pen + vec2(glyph->advance, 0.f)); } } bounds.envelop(pen); return bounds; }
std::vector<Rect> Font::layoutOf(const char* text) { vec2 pen; const size_t length = std::strlen(text); std::vector<Rect> layout; layout.reserve(length); for (const char* c = text; *c != '\0'; ) { const uint32 codepoint = utf8::next<const char*>(c, text + length); if (const Glyph* glyph = findGlyph(codepoint)) { layout.push_back(Rect(glyph->bearing + pen, glyph->size)); pen = round(pen + vec2(glyph->advance, 0.f)); } } return layout; }
glyph_metrics_t QFontEngineQPF::boundingBox(glyph_t glyph) { #ifndef QT_NO_FREETYPE { QGlyphLayout tmp; tmp.glyph = glyph; const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(&tmp, 1); } #endif glyph_metrics_t overall; const Glyph *g = findGlyph(glyph); if (!g) return overall; overall.x = g->x; overall.y = g->y; overall.width = g->width; overall.height = g->height; overall.xoff = g->advance; return overall; }
float font_get_glyph_texture_bottom(int fnt, uint32_t character) { enigma::fontglyph* glyph = findGlyph(enigma::fontstructarray[fnt], character); return glyph->ty2; }
void Font::drawText(vec2 pen, vec4 color, const char* text) { uint vertexCount = 0; // Realize vertices for glyphs { const size_t length = std::strlen(text); m_vertices.resize(length * 6); for (const char* c = text; *c != '\0'; ) { const uint32 codepoint = utf8::next<const char*>(c, text + length); const Glyph* glyph = findGlyph(codepoint); if (!glyph) { glyph = findGlyph(0xfffd); if (!glyph) continue; } pen = round(pen); if (all(greaterThan(glyph->size, vec2(0.f)))) { const Rect pa(pen + glyph->bearing - vec2(0.5f), glyph->size); const Rect ta(glyph->offset + vec2(0.5f), glyph->size); m_vertices[vertexCount + 0].texcoord = ta.position; m_vertices[vertexCount + 0].position = pa.position; m_vertices[vertexCount + 1].texcoord = ta.position + vec2(ta.size.x, 0.f); m_vertices[vertexCount + 1].position = pa.position + vec2(pa.size.x, 0.f); m_vertices[vertexCount + 2].texcoord = ta.position + ta.size; m_vertices[vertexCount + 2].position = pa.position + pa.size; m_vertices[vertexCount + 3] = m_vertices[vertexCount + 2]; m_vertices[vertexCount + 4].texcoord = ta.position + vec2(0.f, ta.size.y); m_vertices[vertexCount + 4].position = pa.position + vec2(0.f, pa.size.y); m_vertices[vertexCount + 5] = m_vertices[vertexCount + 0]; vertexCount += 6; } pen += vec2(glyph->advance, 0.f); } } if (!vertexCount) return; VertexRange range = m_context.allocateVertices(vertexCount, Vertex2ft2fv::format); if (range.isEmpty()) { logError("Failed to allocate vertices for text drawing"); return; } range.copyFrom(m_vertices.data()); m_pass.setUniformState(m_colorIndex, color); m_pass.apply(); m_context.render(PrimitiveRange(TRIANGLE_LIST, range)); }