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; }
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; }
glyph_metrics_t QFontEngineMac::boundingBox(const QGlyphLayout *glyphs, int numGlyphs) { QFixed w; const QGlyphLayout *end = glyphs + numGlyphs; while(end > glyphs) w += (--end)->advance.x; return glyph_metrics_t(0, -(ascent()), w, ascent()+descent(), w, 0); }
glyph_metrics_t QFontEngineS60::boundingBox(const QGlyphLayout &glyphs) { if (glyphs.numGlyphs == 0) return glyph_metrics_t(); QFixed w = 0; for (int i = 0; i < glyphs.numGlyphs; ++i) w += glyphs.effectiveAdvance(i); return glyph_metrics_t(0, -ascent(), w, ascent()+descent()+1, w, 0); }
void Font::drawComplexText(GraphicsContext* graphicsContext, const TextRun& run, const FloatPoint& point, int from, int to) const { PlatformGraphicsContext* context = graphicsContext->platformContext(); UniscribeHelperTextRun state(run, *this); SkColor color = graphicsContext->platformContext()->effectiveFillColor(); unsigned char alpha = SkColorGetA(color); // Skip 100% transparent text; no need to draw anything. if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke) return; TransparencyAwareUniscribePainter painter(graphicsContext, this, run, from, to, point); HDC hdc = painter.hdc(); if (windowsCanHandleTextDrawing(graphicsContext) && !hdc) return; // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency. // Enforce non-transparent color. color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); if (hdc) { SetTextColor(hdc, skia::SkColorToCOLORREF(color)); SetBkMode(hdc, TRANSPARENT); } // If there is a non-blur shadow and both the fill color and shadow color // are opaque, handle without skia. IntSize shadowSize; int shadowBlur; Color shadowColor; if (graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor) && windowsCanHandleDrawTextShadow(graphicsContext)) { COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue())); COLORREF savedTextColor = GetTextColor(hdc); SetTextColor(hdc, textColor); state.draw(graphicsContext, hdc, static_cast<int>(point.x()) + shadowSize.width(), static_cast<int>(point.y() - ascent()) + shadowSize.height(), from, to); SetTextColor(hdc, savedTextColor); } // Uniscribe counts the coordinates from the upper left, while WebKit uses // the baseline, so we have to subtract off the ascent. state.draw(graphicsContext, hdc, static_cast<int>(point.x()), static_cast<int>(point.y() - ascent()), from, to); context->canvas()->endPlatformPaint(); }
float SVGFontFaceElement::verticalOriginY() const { if (!m_fontElement) return 0.0f; // Spec: The default Y-coordinate in the font coordinate system of the origin of a glyph to be used when // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute // were set to the position specified by the font's ascent attribute. const AtomicString& value = m_fontElement->fastGetAttribute(vert_origin_yAttr); if (value.isEmpty()) return ascent(); return value.toFloat(); }
GlyphMetrics ScFace::ScFaceData::glyphBBox(gid_type gl, qreal sz) const { GlyphMetrics res; if (gl == 0 || gl >= CONTROL_GLYPHS) { res.width = glyphWidth(gl, sz); res.ascent = (gl == 0? ascent(sz) : 0); res.descent = 0; return res; } else if (! m_glyphWidth.contains(gl)) { loadGlyph(gl); } const struct GlyphData & data(m_glyphOutline[gl]); res.width = data.bbox_width * sz; res.ascent = data.bbox_ascent * sz; res.descent = data.bbox_descent * sz; return res; }
void KoTextCustomItem::draw(QPainter* p, int _x, int _y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected ) { KoTextZoomHandler *zh=textDocument()->paintingZoomHandler(); //kdDebug(32500)<<" x :"<<_x<<" y :"<<_y<<" cx :"<<cx<<" cy :"<<cy<<" ch :"<<ch<<" cw :"<<cw<<endl; // Calculate index only once // Hmm, should pass it to drawCustomItem... int charIndex = index(); KoTextStringChar* stringChar = paragraph()->at( charIndex ); // Convert x, y, cx, cy, cw and ch from Layout Units to pixels. int x = zh->layoutUnitToPixelX(_x) /*+ stringChar->pixelxadj*/; int y = zh->layoutUnitToPixelY(_y); cx = zh->layoutUnitToPixelX(cx); cy = zh->layoutUnitToPixelY(cy); cw = zh->layoutUnitToPixelX(_x,cw); ch = zh->layoutUnitToPixelY(_y,ch); int wpix = zh->layoutUnitToPixelX(_x,width); int hpix = zh->layoutUnitToPixelX(_y,height); //kdDebug(32500)<<"After x :"<<x<<" y :"<<y<<" cx :"<<cx<<" cy :"<<cy<<" ch :"<<ch<<" cw :"<<cw<<endl; int ascentpix = zh->layoutUnitToPixelY( _y, ascent() ); KoTextFormat * fmt = stringChar->format(); //bool forPrint = ( p->device()->devType() == QInternal::Printer ); p->setFont( fmt->screenFont( zh ) ); int offset=0; if ( fmt->vAlign() == KoTextFormat::AlignSuperScript ) offset = -( hpix - p->fontMetrics().height() ); if ( fmt->shadowDistanceX() != 0 || fmt->shadowDistanceY() != 0 ) { int sx = fmt->shadowX( zh ); int sy = fmt->shadowY( zh ); if ( sx != 0 || sy != 0 ) { p->save(); p->translate( sx, sy ); drawCustomItem(p, x, y, wpix, hpix, ascentpix, cx, cy, cw, ch, cg, selected, offset, true); p->restore(); } } drawCustomItem(p, x, y, wpix, hpix, ascentpix, cx, cy, cw, ch, cg, selected, offset, false); }
/*! \overload Returns the bounding rectangle that contains the first \a len characters of string \a str. */ QRect QFontMetrics::boundingRect( const QString &str, int len ) const { return QRect( 0,-(ascent()),width(str,len),height()); }
void KstLabel::draw(QPainter &p, int px, int py, bool bJustify, bool doDraw) { int w; int h; int s; unsigned i; double dRotationRadians = 3.1415926535897932333796 * Rotation / 180.0; double x; double y; double y_upper; double y_lower; double x0; int i_g; bool is_greek; bool bTerminate = false; unsigned uiLength; QChar C; QRect rect; QRegion rgn; QString str; QString strOut; QString subProcessedText; QString processedText; QFont TextFont(FontName, fontSize(p), QFont::Normal, false); QFont SymbolFont(SymbolFontName, fontSize(p), QFont::Normal, false); int i_fp = 0; FPType fP[MAX_DEPTH_SUB_SUPER]; static const GreekCharType GC[] = {{"\\Alpha", "A"}, {"\\alpha", "a"}, {"\\Beta", "B"}, {"\\beta", "b"}, {"\\Chi", "C"}, {"\\chi", "c"}, {"\\Delta", "D"}, {"\\delta", "d"}, {"\\Epsilon", "E"}, {"\\epsilon", "e"}, {"\\Phi", "F"}, {"\\phi", "f"}, {"\\Gamma", "G"}, {"\\gamma", "g"}, {"\\Eta", "H"}, {"\\eta", "h"}, {"\\Iota", "I"}, {"\\iota", "i"}, {"\\Kappa", "K"}, {"\\kappa", "k"}, {"\\Lambda", "L"}, {"\\lambda", "l"}, {"\\Mu", "M"}, {"\\mu", "m"}, {"\\Nu", "N"}, {"\\nu", "n"}, {"\\Pi", "P"}, {"\\pi", "p"}, {"\\Theta", "Q"}, {"\\theta", "q"}, {"\\Rho", "R"}, {"\\rho", "r"}, {"\\Sigma", "S"}, {"\\sigma", "s"}, {"\\Tau", "T"}, {"\\tau", "t"}, {"\\Omega", "W"}, {"\\omega", "w"}, {"\\Psi", "Y"}, {"\\psi", "y"}, {"\\Zeta", "Z"}, {"\\zeta", "z"}, {"\\sum", "�"}, {"\\int", "�"} }; static const int N_GREEK = sizeof( GC ) / sizeof( GreekCharType ); p.save(); p.setFont(TextFont); p.translate(px, py); p.rotate(Rotation); p.setClipping(false); if(doDraw) { w = width(p); h = ascent(p); } else { w = h = 0; } fP[0].locked = true; fP[0].dy = 0; fP[0].size = 0; fP[0].x = 0; x = y = 0; if(bJustify) { switch (Justify) { case CxBy: x = -w/2; break; case CxTy: x = -w/2; y = h; break; case CxCy: x = -w/2; y = h/2; break; case LxBy: break; case LxTy: y = h; break; case LxCy: y = h/2; break; case RxBy: x = -w; break; case RxTy: x = -w; y = h; break; case RxCy: x = -w; y = h/2; break; default: KstDebug::self()->log(i18n("Undefined justification %1 in label \"%2\".").arg(Justify).arg(Text), KstDebug::Debug); break; } } y_upper = y; y_lower = y; x0 = x; processedText = Text; if (doScalarReplacement) { ScalarsUsed.clear(); KST::scalarList.lock().readLock(); for (KstScalarList::iterator it = KST::scalarList.begin(); it != KST::scalarList.end(); ++it) { if (processedText.contains((*it)->tagLabel())) { ScalarsUsed.append(*it); processedText.replace((*it)->tagLabel(), (*it)->label()); } } KST::scalarList.lock().readUnlock(); } uiLength = processedText.length(); for (i = 0; i < uiLength; i++) { C = processedText[i]; if( _interpret && (C == '^' || C == '_' || C == '{' || C == '}' || C == '\\') ) { if( !strOut.isEmpty() ) { p.setFont( TextFont ); if( doDraw ) { p.drawText(int(x),int(y + fP[i_fp].dy), strOut); } x += p.fontMetrics().width(strOut); if( y + fP[i_fp].dy - (double)p.fontMetrics().ascent() < y_upper ) { y_upper = y + fP[i_fp].dy - (double)p.fontMetrics().ascent(); } if( y + fP[i_fp].dy + (double)p.fontMetrics().descent() > y_lower ) { y_lower = y + fP[i_fp].dy + (double)p.fontMetrics().descent(); } strOut = QString::null; } if (C == '^') { // Superscript if (i_fp+1 < MAX_DEPTH_SUB_SUPER) { i_fp++; bTerminate = false; fP[i_fp].locked = false; fP[i_fp].size = fP[i_fp-1].size - 1; fP[i_fp].dy = fP[i_fp-1].dy - p.fontMetrics().ascent()*0.4; fP[i_fp].x = x; if (p.fontMetrics().rightBearing(C) < 0) { x -= 2.0 * p.fontMetrics().rightBearing(C); } s = int(double(fontSize(p))*pow(1.3, double(fP[i_fp].size))); if (s < 5) { s = 5; // no smaller than 5pt font! } TextFont.setPointSize(s); } } else if (processedText[i] == '_') { // Subscript if (i_fp+1 < MAX_DEPTH_SUB_SUPER) { i_fp++; bTerminate = false; fP[i_fp].locked = false; fP[i_fp].size = fP[i_fp-1].size-1; fP[i_fp].dy = fP[i_fp-1].dy + p.fontMetrics().height()*0.2; fP[i_fp].x = x; s = int(double(fontSize(p))*pow(1.3, double(fP[i_fp].size))); if (s < 5) { s = 5; // no smaller than 5pt font! } TextFont.setPointSize(s); } } else if (processedText[i] == '{') { fP[i_fp].locked = true; } else if (processedText[i] == '}') { if (i_fp > 0) { if (processedText[i+1] == '_' || processedText[i+1] == '^') { x = fP[i_fp].x; } i_fp--; } } else if( processedText[i] == '\\' ) { is_greek = false; subProcessedText = processedText.mid(i); for (i_g = 0; i_g < N_GREEK; i_g++) { if (subProcessedText.startsWith(GC[i_g].label)) { is_greek = true; str = GC[i_g].c; i += GC[i_g].label.length()-1; if (processedText[i+1] == ' ') { i++; } break; } } if (is_greek) { s = int(double(fontSize(p))*pow(1.3, double(fP[i_fp].size))); if (s < 5) { s = 5; // no smaller than 5pt font! } SymbolFont.setPointSize(s); p.setFont(SymbolFont); bTerminate = true; if( doDraw ) { p.drawText(int(x),int(y + fP[i_fp].dy), str); } x += p.fontMetrics().width(str); if( y + fP[i_fp].dy - (double)p.fontMetrics().ascent() < y_upper ) { y_upper = y + fP[i_fp].dy - (double)p.fontMetrics().ascent(); } if( y + fP[i_fp].dy + (double)p.fontMetrics().descent() > y_lower ) { y_lower = y + fP[i_fp].dy + (double)p.fontMetrics().descent(); } } else { if (processedText.find( "it", i+1, FALSE ) == (int)i+1 ) { TextFont.setItalic(true); i += 2; if (processedText.at(i+1) == ' ') { i++; } } else if (processedText.find( "rm", i+1, FALSE ) == (int)i+1 ) { TextFont.setItalic(false); i += 2; if (processedText.at(i+1) == ' ') { i++; } } else { i++; bTerminate = true; strOut += processedText.at( i ); } } } } else { bTerminate = true; strOut += processedText[i]; } // // do we need to terminate a superscript or subscript? // if (_interpret && i_fp > 0 && fP[i_fp].locked == false && bTerminate ) { if( !strOut.isEmpty( ) ) { p.setFont( TextFont ); if( doDraw ) { p.drawText(int(x),int(y + fP[i_fp].dy), strOut); } x += p.fontMetrics().width(strOut); if( y + fP[i_fp].dy - (double)p.fontMetrics().ascent() < y_upper ) { y_upper = y + fP[i_fp].dy - (double)p.fontMetrics().ascent(); } if( y + fP[i_fp].dy + (double)p.fontMetrics().descent() > y_lower ) { y_lower = y + fP[i_fp].dy + (double)p.fontMetrics().descent(); } strOut = QString::null; } if (processedText.at(i+1) == '_' || processedText.at(i+1) == '^') { x = fP[i_fp].x; } i_fp--; s = int(double(fontSize(p))*pow(1.3, double(fP[i_fp].size))); if (s < 5) { s = 5; // no smaller than 5pt font! } TextFont.setPointSize(s); } } if( !strOut.isEmpty( ) ) { p.setFont( TextFont ); if( doDraw ) { p.drawText(int(x),int(y + fP[i_fp].dy), strOut); } x += p.fontMetrics().width(strOut); if( y + fP[i_fp].dy - (double)p.fontMetrics().ascent() < y_upper ) { y_upper = y + fP[i_fp].dy - (double)p.fontMetrics().ascent(); } if( y + fP[i_fp].dy + (double)p.fontMetrics().descent() > y_lower ) { y_lower = y + fP[i_fp].dy + (double)p.fontMetrics().descent(); } } p.restore(); Width = x - x0; rect.setRect((int)(px + x0), (int)(py + y_upper), (int)Width, (int)(y_lower - y_upper + 1)); rect.normalize( ); v_offset = (int)(y - y_upper); if( Rotation == 0.0 ) { QRegion rgn( rect ); extents = rgn; } else { QPointArray points( 5 ); int ixBase = 0; int iyBase = 0; int ixOld = 0; int iyOld = 0; int ix; int iy; switch( Justify ){ case CxBy: ixBase = rect.left() + rect.width()/2; iyBase = rect.bottom(); break; case CxTy: ixBase = rect.left() + rect.width()/2; iyBase = rect.top(); break; case CxCy: ixBase = rect.left() + rect.width()/2; iyBase = rect.top() + rect.height()/2; break; case LxBy: ixBase = rect.left(); iyBase = rect.bottom(); break; case LxTy: ixBase = rect.left(); iyBase = rect.top(); break; case LxCy: ixBase = rect.left(); iyBase = rect.top() + rect.height()/2; break; case RxBy: ixBase = rect.right(); iyBase = rect.bottom(); break; case RxTy: ixBase = rect.right(); iyBase = rect.top(); break; case RxCy: ixBase = rect.right(); iyBase = rect.top() + rect.height()/2; break; default: ixBase = rect.left(); iyBase = rect.bottom(); break; } for( i=0; i<5; i++ ) { switch( i ) { case 0: case 4: ixOld = rect.left(); iyOld = rect.top(); break; case 1: ixOld = rect.right(); iyOld = rect.top(); break; case 2: ixOld = rect.right(); iyOld = rect.bottom(); break; case 3: ixOld = rect.left(); iyOld = rect.bottom(); break; } ix = ixBase + (int)((double)( ixOld - ixBase )*cos( -dRotationRadians ) + (double)( iyOld - iyBase)*sin( -dRotationRadians )); iy = iyBase + (int)((double)( ixOld - ixBase )*sin( dRotationRadians ) + (double)( iyOld - iyBase)*cos( -dRotationRadians )); points.setPoint( i, ix, iy ); } QRegion rgn( points ); extents = rgn; } }
float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { WidthIterator it(this, run, fallbackFonts, glyphOverflow); it.advance(run.length(), glyphBuffer); if (glyphOverflow) { glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - ascent()); glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - descent()); glyphOverflow->left = ceilf(it.firstGlyphOverflow()); glyphOverflow->right = ceilf(it.lastGlyphOverflow()); } return it.m_runWidthSoFar; }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { ComplexTextController controller(this, run, true, fallbackFonts); if (glyphOverflow) { glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - ascent()); glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - descent()); glyphOverflow->left = max<int>(0, ceilf(-controller.minGlyphBoundingBoxX())); glyphOverflow->right = max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.totalWidth())); } return controller.totalWidth(); }
// SDL ttf implementation may be lighter ??? void Font::drawSimpleText(BIGraphicsContext* context, const TextRun& run, const TextStyle& style, const FloatPoint& point) const { WebCore::Color text_color = context->strokeColor(); BINativeImage* text_surface; IntRect dst_rect; IntPoint intPoint; static int oldx = 0; int text_width, text_height; bool init = false; int numSpaces = 0; int padPerSpace = 0; FloatPoint wordPoint(point); // Process normal, bold, italic styles if (m_fontDescription.italic()) { if (m_fontDescription.bold()) { // Bold && italic d->m_ttfFont->style = FT_STYLE_BOLD | FT_STYLE_ITALIC; d->flushCache(d->m_ttfFont); } else { // Only italic d->m_ttfFont->style = FT_STYLE_ITALIC; d->flushCache(d->m_ttfFont); } } else if (m_fontDescription.bold()) { // Only bold d->m_ttfFont->style = FT_STYLE_BOLD; d->flushCache(d->m_ttfFont); } else { d->m_ttfFont->style = FT_STYLE_NORMAL; d->flushCache(d->m_ttfFont); } // Draw font int wordSize = run.length() - run.from(); UChar word[wordSize]; copyTextRunTo(run, word); for (int i = 0; i <= wordSize; i++) { if (Font::treatAsSpace(word[i])) numSpaces++;; } if (numSpaces == 0) padPerSpace = 0; else padPerSpace = static_cast<int> (ceil(style.padding() / numSpaces)); UChar text[wordSize + 1]; int j = 0; for (int i = 0; i <= wordSize; i++) { if (Font::treatAsSpace(word[i]) || i == wordSize) { text[j] = ' '; text[++j] = '\0'; d->sizeUnicode(d->m_ttfFont, text, &text_width, &text_height); text_surface = d->renderUnicodeBlended(d->m_ttfFont, text, text_color, context->alphaLayer()); if (text_surface) { intPoint.setX(static_cast<uint16_t> (wordPoint.x())); intPoint.setY(static_cast<uint16_t> (wordPoint.y()) - ascent()); dst_rect.setX(0); dst_rect.setY(0); dst_rect.setWidth(text_surface->size().width()); dst_rect.setHeight(text_surface->size().height()); getBIGraphicsDevice()->copy(*(context->widget()), *text_surface, dst_rect, intPoint, context->alphaLayer()); delete text_surface; } wordPoint = wordPoint + FloatSize(padPerSpace + text_width,0); j = 0; } else { text[j] = word[i]; j++; } } }