float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const { WidthIterator it(this, run, 0, false, forTextEmphasis); GlyphBuffer localGlyphBuffer; it.advance(run.length(), &localGlyphBuffer); if (localGlyphBuffer.isEmpty()) return 0; float totalWidth = it.m_runWidthSoFar; float beforeWidth = 0; int glyphPos = 0; for (; glyphPos < localGlyphBuffer.size() && it.m_characterIndexOfGlyph[glyphPos] < from; ++glyphPos) beforeWidth += localGlyphBuffer.advanceAt(glyphPos).width(); int glyphFrom = glyphPos; float afterWidth = totalWidth; glyphPos = localGlyphBuffer.size() - 1; for (; glyphPos >= glyphFrom && it.m_characterIndexOfGlyph[glyphPos] >= to; --glyphPos) afterWidth -= localGlyphBuffer.advanceAt(glyphPos).width(); int glyphTo = glyphPos + 1; glyphBuffer.add(&localGlyphBuffer, glyphFrom, glyphTo - glyphFrom); if (run.rtl()) { glyphBuffer.reverse(0, glyphBuffer.size()); return totalWidth - afterWidth; } return beforeWidth; }
FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const { GlyphBuffer glyphBuffer; WidthIterator it(this, run); it.advance(run.length(), &glyphBuffer); float totalWidth = it.m_runWidthSoFar; float beforeWidth = 0; int glyphPos = 0; for (; glyphPos < glyphBuffer.size() && it.m_characterIndexOfGlyph[glyphPos] < from; ++glyphPos) beforeWidth += glyphBuffer.advanceAt(glyphPos).width(); int glyphFrom = glyphPos; float afterWidth = totalWidth; glyphPos = glyphBuffer.size() - 1; for (; glyphPos >= glyphFrom && it.m_characterIndexOfGlyph[glyphPos] >= to; --glyphPos) afterWidth -= glyphBuffer.advanceAt(glyphPos).width(); // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning. if (run.rtl()) { return FloatRect(floorf(point.x() + totalWidth - afterWidth), point.y(), roundf(point.x() + totalWidth - beforeWidth) - floorf(point.x() + totalWidth - afterWidth), h); } return FloatRect(floorf(point.x() + beforeWidth), point.y(), roundf(point.x() + afterWidth) - floorf(point.x() + beforeWidth), h); }
void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { 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 && !graphicsContext->hasShadow()) return; // We draw the glyphs in chunks to avoid having to do a heap allocation for // the arrays of characters and advances. const int kMaxBufferLength = 256; Vector<WORD, kMaxBufferLength> glyphs; Vector<int, kMaxBufferLength> advances; int glyphIndex = 0; // The starting glyph of the current chunk. // In order to round all offsets to the correct pixel boundary, this code keeps track of the absolute position // of each glyph in floating point units and rounds to integer advances at the last possible moment. float horizontalOffset = point.x(); // The floating point offset of the left side of the current glyph. int lastHorizontalOffsetRounded = lroundf(horizontalOffset); // The rounded offset of the left side of the last glyph rendered. while (glyphIndex < numGlyphs) { // How many chars will be in this chunk? int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex); glyphs.resize(curLen); advances.resize(curLen); float currentWidth = 0; for (int i = 0; i < curLen; ++i, ++glyphIndex) { glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex); horizontalOffset += glyphBuffer.advanceAt(from + glyphIndex); advances[i] = lroundf(horizontalOffset) - lastHorizontalOffsetRounded; lastHorizontalOffsetRounded += advances[i]; currentWidth += glyphBuffer.advanceAt(from + glyphIndex); // Bug 26088 - very large positive or negative runs can fail to // render so we clamp the size here. In the specs, negative // letter-spacing is implementation-defined, so this should be // fine, and it matches Safari's implementation. The call actually // seems to crash if kMaxNegativeRun is set to somewhere around // -32830, so we give ourselves a little breathing room. const int maxNegativeRun = -32768; const int maxPositiveRun = 32768; if ((currentWidth + advances[i] < maxNegativeRun) || (currentWidth + advances[i] > maxPositiveRun)) advances[i] = 0; } SkPoint origin = point; origin.fX += SkFloatToScalar(horizontalOffset - point.x() - currentWidth); paintSkiaText(graphicsContext, font->platformData(), curLen, &glyphs[0], &advances[0], 0, &origin); } }
void Font::drawGlyphBuffer(GraphicsContext* context, const TextRun& run, const GlyphBuffer& glyphBuffer, FloatPoint& point) const { #if !ENABLE(SVG_FONTS) UNUSED_PARAM(run); #endif // Draw each contiguous run of glyphs that use the same font data. const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); FloatSize offset = glyphBuffer.offsetAt(0); FloatPoint startPoint(point.x(), point.y() - glyphBuffer.initialAdvance().height()); float nextX = startPoint.x() + glyphBuffer.advanceAt(0).width(); float nextY = startPoint.y() + glyphBuffer.advanceAt(0).height(); int lastFrom = 0; int nextGlyph = 1; #if ENABLE(SVG_FONTS) TextRun::RenderingContext* renderingContext = run.renderingContext(); #endif while (nextGlyph < glyphBuffer.size()) { const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph); if (nextFontData != fontData || nextOffset != offset) { #if ENABLE(SVG_FONTS) if (renderingContext && fontData->isSVGFont()) renderingContext->drawSVGGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); else #endif drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); lastFrom = nextGlyph; fontData = nextFontData; offset = nextOffset; startPoint.setX(nextX); startPoint.setY(nextY); } nextX += glyphBuffer.advanceAt(nextGlyph).width(); nextY += glyphBuffer.advanceAt(nextGlyph).height(); nextGlyph++; } #if ENABLE(SVG_FONTS) if (renderingContext && fontData->isSVGFont()) renderingContext->drawSVGGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); else { #endif drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); point.setX(nextX); #if ENABLE(SVG_FONTS) } #endif }
void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const { // Draw each contiguous run of glyphs that use the same font data. const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); FloatSize offset = glyphBuffer.offsetAt(0); FloatPoint startPoint(point); float nextX = startPoint.x(); int lastFrom = 0; int nextGlyph = 0; while (nextGlyph < glyphBuffer.size()) { const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph); if (nextFontData != fontData || nextOffset != offset) { drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); lastFrom = nextGlyph; fontData = nextFontData; offset = nextOffset; startPoint.setX(nextX); } nextX += glyphBuffer.advanceAt(nextGlyph); nextGlyph++; } drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); }
void Font::drawGlyphs(GraphicsContext* graphicsContext, const FontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { cairo_t* context = graphicsContext->platformContext(); // Set the text color to use for drawing. float red, green, blue, alpha; Color penColor = graphicsContext->pen().color(); penColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(context, red, green, blue, alpha); // Select the scaled font. font->setFont(context); GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); float offset = point.x(); for (unsigned i = 0; i < numGlyphs; i++) { glyphs[i].x = offset; glyphs[i].y = point.y(); offset += glyphBuffer.advanceAt(from + i); } cairo_show_glyphs(context, glyphs, numGlyphs); }
void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { #if USE(WXGC) wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext()); #else wxDC* dc = graphicsContext->platformContext(); #endif wxFont* wxfont = font->getWxFont(); if (wxfont->IsOk()) dc->SetFont(*wxfont); dc->SetTextForeground(color); // convert glyphs to wxString GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from)); int offset = point.x(); wxString text = wxEmptyString; for (unsigned i = 0; i < numGlyphs; i++) { text = text.Append((wxChar)glyphs[i]); offset += glyphBuffer.advanceAt(from + i); } // NOTE: The wx API actually adds the ascent to the y value internally, // so we have to subtract it from the y point here so that the ascent // isn't added twice. dc->DrawText(text, (wxCoord)point.x(), int(point.y() - font->ascent())); }
void Font::drawGlyphs(GraphicsContext* graphicsContext, const FontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { cairo_t* context = graphicsContext->platformContext(); // Set the text color to use for drawing. float red, green, blue, alpha; Color penColor = graphicsContext->fillColor(); penColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(context, red, green, blue, alpha); // This was commented out as it made "some text invisible" but seems to work now. font->setFont(context); GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*) glyphBuffer.glyphs(from); float offset = point.x(); for (int i = 0; i < numGlyphs; i++) { glyphs[i].x = offset; glyphs[i].y = point.y(); offset += glyphBuffer.advanceAt(from + i); } cairo_show_glyphs(context, glyphs, numGlyphs); }
void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { #if USE(WXGC) wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext()); #else wxDC* dc = graphicsContext->platformContext(); #endif wxFont wxfont = font->getWxFont(); if (wxfont.IsOk()) dc->SetFont(wxfont); dc->SetTextForeground(color); // convert glyphs to wxString GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from)); int offset = point.x(); wxString text = wxEmptyString; for (unsigned i = 0; i < numGlyphs; i++) { text = text.Append((wxChar)glyphs[i]); offset += glyphBuffer.advanceAt(from + i); } // the y point is actually the bottom point of the text, turn it into the top float height = font->ascent() - font->descent(); wxCoord ypoint = (wxCoord) (point.y() - height); dc->DrawText(text, (wxCoord)point.x(), ypoint); }
void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const { FontCachePurgePreventer purgePreventer; GlyphData markGlyphData; if (!getEmphasisMarkGlyphData(mark, markGlyphData)) return; const SimpleFontData* markFontData = markGlyphData.fontData; ASSERT(markFontData); if (!markFontData) return; Glyph markGlyph = markGlyphData.glyph; Glyph spaceGlyph = markFontData->spaceGlyph(); float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0); FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y()); GlyphBuffer markBuffer; for (int i = 0; i + 1 < glyphBuffer.size(); ++i) { float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1); float advance = glyphBuffer.advanceAt(i).width() - middleOfLastGlyph + middleOfNextGlyph; markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance); middleOfLastGlyph = middleOfNextGlyph; } markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0); drawGlyphBuffer(context, run, markBuffer, startPoint); }
int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const { GlyphBuffer glyphBuffer; WidthIterator it(this, run); it.advance(run.length(), &glyphBuffer); int characterOffset = 0; if (run.rtl()) { float currentX = it.m_runWidthSoFar; for (int glyphPosition = 0; glyphPosition <= glyphBuffer.size(); ++glyphPosition) { if (glyphPosition == glyphBuffer.size()) { characterOffset = run.length(); break; } characterOffset = it.m_characterIndexOfGlyph[glyphPosition]; float glyphWidth = glyphBuffer.advanceAt(glyphPosition).width(); if (includePartialGlyphs) { if (currentX - glyphWidth / 2.0f <= x) break; } else { if (currentX - glyphWidth <= x) break; } currentX -= glyphWidth; } } else { float currentX = 0; for (int glyphPosition = 0; glyphPosition <= glyphBuffer.size(); ++glyphPosition) { if (glyphPosition == glyphBuffer.size()) { characterOffset = run.length(); break; } characterOffset = it.m_characterIndexOfGlyph[glyphPosition]; float glyphWidth = glyphBuffer.advanceAt(glyphPosition).width(); if (includePartialGlyphs) { if (currentX + glyphWidth / 2.0f >= x) break; } else { if (currentX + glyphWidth >= x) break; } currentX += glyphWidth; } } return characterOffset; }
bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer& glyphBuffer) { int oldSize = glyphBuffer.size(); advance(m_currentCharacter + 1, &glyphBuffer); float w = 0; for (int i = oldSize; i < glyphBuffer.size(); ++i) w += glyphBuffer.advanceAt(i); width = w; return glyphBuffer.size() > oldSize; }
void Font::drawGlyphBuffer(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const { // Draw each contiguous run of glyphs that use the same font data. const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); FloatPoint startPoint(point); float nextX = startPoint.x() + glyphBuffer.advanceAt(0); unsigned lastFrom = 0; unsigned nextGlyph = 1; #if ENABLE(SVG_FONTS) TextRun::RenderingContext* renderingContext = runInfo.run.renderingContext(); #endif while (nextGlyph < glyphBuffer.size()) { const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); if (nextFontData != fontData) { #if ENABLE(SVG_FONTS) if (renderingContext && fontData->isSVGFont()) renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); else #endif drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds); lastFrom = nextGlyph; fontData = nextFontData; startPoint.setX(nextX); } nextX += glyphBuffer.advanceAt(nextGlyph); nextGlyph++; } #if ENABLE(SVG_FONTS) if (renderingContext && fontData->isSVGFont()) renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); else #endif drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds); }
void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* sfont, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { int i = 0; FloatPoint pos(point); float w=0, h=0; UChar c=0; void* dc = (void *)graphicsContext->platformContext(); WKCPeerFont pf; WKCFloatRect clip; WKCFloatPoint pp; if (!dc) return; pf.fFont = sfont->platformData().Font(); if (!pf.fFont) return; const FontPlatformData& pd(sfont->platformData()); pf.fRequestedSize = pd.requestSize(); pf.fCreatedSize = pd.createdSize(); pf.fWeight = pd.weight(); pf.fItalic = pd.isItalic(); pf.fScale = pd.scale(); pf.fiScale = pd.iscale(); pf.fCanScale = pd.canScale(); pf.fFontId = (void *)pd.hash(); pos.setY(pos.y() - (float)pd.ascent()*pd.scale()); h = (pd.lineSpacing()) * pd.scale(); for (i=0; i<numGlyphs; i++) { float advance = 0.f; c = fixedChar(glyphBuffer.glyphAt(from + i)); if (!c) continue; advance = glyphBuffer.advanceAt(from + i); w = wkcFontGetClipWidthPeer(pf.fFont, c) * pd.scale(); clip.fX = pos.x(); clip.fY = pos.y(); clip.fWidth = w; clip.fHeight = h; pp.fX = pos.x(); pp.fY = pos.y(); wkcDrawContextDrawCharPeer(dc, (unsigned int)c, &pp, &clip, &pf); pos.move(advance, 0); } }
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { if (context->paintingDisabled()) return; bool shouldFill = context->textDrawingMode() & TextModeFill; bool shouldStroke = context->textDrawingMode() & TextModeStroke; // Stroking text should always take the complex path. ASSERT(!shouldStroke); // Shadowed text should always take the complex path. ASSERT(context->contextShadow()->m_type == ContextShadow::NoShadow); if (!shouldFill && !shouldStroke) return; QVector<quint32> glyphIndexes; QVector<QPointF> positions; glyphIndexes.reserve(numGlyphs); positions.reserve(numGlyphs); float x = 0; for (int i = 0; i < numGlyphs; ++i) { Glyph glyph = glyphBuffer.glyphAt(from + i); float advance = glyphBuffer.advanceAt(from + i); if (!glyph) continue; glyphIndexes.append(glyph); positions.append(QPointF(x, 0)); x += advance; } QGlyphs qtGlyphs; qtGlyphs.setGlyphIndexes(glyphIndexes); qtGlyphs.setPositions(positions); qtGlyphs.setFont(fontData->platformData().rawFont()); QPainter* painter = context->platformContext(); QPen previousPen = painter->pen(); painter->setPen(fillPenForContext(context)); painter->drawGlyphs(point, qtGlyphs); painter->setPen(previousPen); }
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { if (!font->platformData().size()) return; GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from)); float offset = point.x(); for (int i = 0; i < numGlyphs; i++) { glyphs[i].x = offset; glyphs[i].y = point.y(); offset += glyphBuffer.advanceAt(from + i).width(); } PlatformContextCairo* platformContext = context->platformContext(); drawGlyphsShadow(context, point, font, glyphs, numGlyphs); cairo_t* cr = platformContext->cr(); cairo_save(cr); if (context->textDrawingMode() & TextModeFill) { platformContext->prepareForFilling(context->state(), PlatformContextCairo::AdjustPatternForGlobalAlpha); drawGlyphsToContext(cr, font, glyphs, numGlyphs); } // Prevent running into a long computation within cairo. If the stroke width is // twice the size of the width of the text we will not ask cairo to stroke // the text as even one single stroke would cover the full wdth of the text. // See https://bugs.webkit.org/show_bug.cgi?id=33759. if (context->textDrawingMode() & TextModeStroke && context->strokeThickness() < 2 * offset) { platformContext->prepareForStroking(context->state()); cairo_set_line_width(cr, context->strokeThickness()); // This may disturb the CTM, but we are going to call cairo_restore soon after. cairo_set_scaled_font(cr, font->platformData().scaledFont()); cairo_glyph_path(cr, glyphs, numGlyphs); cairo_stroke(cr); } cairo_restore(cr); }
static void drawGlyphsWin(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { TransparencyAwareGlyphPainter painter(graphicsContext, font, glyphBuffer, from, numGlyphs, point); // We draw the glyphs in chunks to avoid having to do a heap allocation for // the arrays of characters and advances. Since ExtTextOut is the // lowest-level text output function on Windows, there should be little // penalty for splitting up the text. On the other hand, the buffer cannot // be bigger than 4094 or the function will fail. const int kMaxBufferLength = 256; Vector<WORD, kMaxBufferLength> glyphs; Vector<int, kMaxBufferLength> advances; int glyphIndex = 0; // The starting glyph of the current chunk. // In order to round all offsets to the correct pixel boundary, this code keeps track of the absolute position // of each glyph in floating point units and rounds to integer advances at the last possible moment. float horizontalOffset = point.x(); // The floating point offset of the left side of the current glyph. int lastHorizontalOffsetRounded = lroundf(horizontalOffset); // The rounded offset of the left side of the last glyph rendered. while (glyphIndex < numGlyphs) { // How many chars will be in this chunk? int curLen = min(kMaxBufferLength, numGlyphs - glyphIndex); glyphs.resize(curLen); advances.resize(curLen); float currentWidth = 0; for (int i = 0; i < curLen; ++i, ++glyphIndex) { glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex); horizontalOffset += glyphBuffer.advanceAt(from + glyphIndex); advances[i] = lroundf(horizontalOffset) - lastHorizontalOffsetRounded; lastHorizontalOffsetRounded += advances[i]; currentWidth += glyphBuffer.advanceAt(from + glyphIndex); // Bug 26088 - very large positive or negative runs can fail to // render so we clamp the size here. In the specs, negative // letter-spacing is implementation-defined, so this should be // fine, and it matches Safari's implementation. The call actually // seems to crash if kMaxNegativeRun is set to somewhere around // -32830, so we give ourselves a little breathing room. const int maxNegativeRun = -32768; const int maxPositiveRun = 32768; if ((currentWidth + advances[i] < maxNegativeRun) || (currentWidth + advances[i] > maxPositiveRun)) advances[i] = 0; } // Actually draw the glyphs (with retry on failure). bool success = false; for (int executions = 0; executions < 2; ++executions) { success = painter.drawGlyphs(curLen, &glyphs[0], &advances[0], horizontalOffset - point.x() - currentWidth); if (!success && !executions) { // Ask the browser to load the font for us and retry. PlatformSupport::ensureFontLoaded(font->platformData().hfont()); continue; } break; } if (!success) LOG_ERROR("Unable to draw the glyphs after second attempt"); } }
void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const TextRun& run, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { SVGFontElement* fontElement = 0; SVGFontFaceElement* fontFaceElement = 0; const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement); if (!fontElement || !fontFaceElement) return; // We can only paint SVGFonts if a context is available. RenderObject* renderObject = renderObjectFromRun(run); ASSERT(renderObject); bool isVerticalText = false; if (RenderObject* parentRenderObject = firstParentRendererForNonTextNode(renderObject)) { RenderStyle* parentRenderObjectStyle = parentRenderObject->style(); ASSERT(parentRenderObjectStyle); isVerticalText = parentRenderObjectStyle->svgStyle().isVerticalWritingMode(); } float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm()); FloatPoint glyphOrigin; glyphOrigin.setX(svgFontData->horizontalOriginX() * scale); glyphOrigin.setY(svgFontData->horizontalOriginY() * scale); unsigned short resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode; FloatPoint currentPoint = point; for (int i = 0; i < numGlyphs; ++i) { Glyph glyph = glyphBuffer.glyphAt(from + i); if (!glyph) continue; float advance = glyphBuffer.advanceAt(from + i); SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph); ASSERT(!svgGlyph.isPartOfLigature); ASSERT(svgGlyph.tableEntry == glyph); SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, svgFontData); // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations). if (svgGlyph.pathData.isEmpty()) { if (isVerticalText) currentPoint.move(0, advance); else currentPoint.move(advance, 0); continue; } if (isVerticalText) { glyphOrigin.setX(svgGlyph.verticalOriginX * scale); glyphOrigin.setY(svgGlyph.verticalOriginY * scale); } AffineTransform glyphPathTransform; glyphPathTransform.translate(currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y()); glyphPathTransform.scale(scale, -scale); Path glyphPath = svgGlyph.pathData; glyphPath.transform(glyphPathTransform); SVGRenderSupport::fillOrStrokePath(context, resourceMode, glyphPath); if (isVerticalText) currentPoint.move(0, advance); else currentPoint.move(advance, 0); } }
static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { Color fillColor = graphicsContext->fillColor(); bool drawIntoBitmap = false; TextDrawingModeFlags drawingMode = graphicsContext->textDrawingMode(); if (drawingMode == TextModeFill) { if (!fillColor.alpha()) return; drawIntoBitmap = fillColor.alpha() != 255 || graphicsContext->inTransparencyLayer(); if (!drawIntoBitmap) { FloatSize offset; float blur; Color color; ColorSpace shadowColorSpace; graphicsContext->getShadow(offset, blur, color, shadowColorSpace); drawIntoBitmap = offset.width() || offset.height() || blur; } } // We have to convert CG's two-dimensional floating point advances to just horizontal integer advances. Vector<int, 2048> gdiAdvances; int totalWidth = 0; for (int i = 0; i < numGlyphs; i++) { gdiAdvances.append(lroundf(glyphBuffer.advanceAt(from + i))); totalWidth += gdiAdvances[i]; } HDC hdc = 0; OwnPtr<GraphicsContext::WindowsBitmap> bitmap; IntRect textRect; if (!drawIntoBitmap) hdc = graphicsContext->getWindowsContext(textRect, true, false); if (!hdc) { drawIntoBitmap = true; // We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges. // FIXME: Can get glyphs' optical bounds (even from CG) to get this right. const FontMetrics& fontMetrics = font->fontMetrics(); int lineGap = fontMetrics.lineGap(); textRect = IntRect(point.x() - (fontMetrics.ascent() + fontMetrics.descent()) / 2, point.y() - fontMetrics.ascent() - lineGap, totalWidth + fontMetrics.ascent() + fontMetrics.descent(), fontMetrics.lineSpacing()); bitmap = graphicsContext->createWindowsBitmap(textRect.size()); memset(bitmap->buffer(), 255, bitmap->bufferLength()); hdc = bitmap->hdc(); XFORM xform; xform.eM11 = 1.0f; xform.eM12 = 0.0f; xform.eM21 = 0.0f; xform.eM22 = 1.0f; xform.eDx = -textRect.x(); xform.eDy = -textRect.y(); SetWorldTransform(hdc, &xform); } SelectObject(hdc, font->platformData().hfont()); // Set the correct color. if (drawIntoBitmap) SetTextColor(hdc, RGB(0, 0, 0)); else SetTextColor(hdc, RGB(fillColor.red(), fillColor.green(), fillColor.blue())); SetBkMode(hdc, TRANSPARENT); SetTextAlign(hdc, TA_LEFT | TA_BASELINE); // Uniscribe gives us offsets to help refine the positioning of combining glyphs. FloatSize translation = glyphBuffer.offsetAt(from); if (translation.width() || translation.height()) { XFORM xform; xform.eM11 = 1.0; xform.eM12 = 0; xform.eM21 = 0; xform.eM22 = 1.0; xform.eDx = translation.width(); xform.eDy = translation.height(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); } if (drawingMode == TextModeFill) { XFORM xform; xform.eM11 = 1.0; xform.eM12 = 0; xform.eM21 = font->platformData().syntheticOblique() ? -tanf(syntheticObliqueAngle * piFloat / 180.0f) : 0; xform.eM22 = 1.0; xform.eDx = point.x(); xform.eDy = point.y(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); if (font->syntheticBoldOffset()) { xform.eM21 = 0; xform.eDx = font->syntheticBoldOffset(); xform.eDy = 0; ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); } } else { XFORM xform; GetWorldTransform(hdc, &xform); AffineTransform hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy); CGAffineTransform initialGlyphTransform = hdcTransform.isInvertible() ? hdcTransform.inverse() : CGAffineTransformIdentity; if (font->platformData().syntheticOblique()) initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0)); initialGlyphTransform.tx = 0; initialGlyphTransform.ty = 0; CGContextRef cgContext = graphicsContext->platformContext(); CGContextSaveGState(cgContext); BOOL fontSmoothingEnabled = false; SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0); CGContextSetShouldAntialias(cgContext, fontSmoothingEnabled); CGContextScaleCTM(cgContext, 1.0, -1.0); CGContextTranslateCTM(cgContext, point.x() + glyphBuffer.offsetAt(from).width(), -(point.y() + glyphBuffer.offsetAt(from).height())); for (unsigned i = 0; i < numGlyphs; ++i) { RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i))); CGContextSaveGState(cgContext); CGContextConcatCTM(cgContext, initialGlyphTransform); if (drawingMode & TextModeFill) { CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); if (font->syntheticBoldOffset()) { CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } if (drawingMode & TextModeStroke) { CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); if (font->syntheticBoldOffset()) { CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } CGContextRestoreGState(cgContext); CGContextTranslateCTM(cgContext, gdiAdvances[i], 0); } CGContextRestoreGState(cgContext); } if (drawIntoBitmap) { UInt8* buffer = bitmap->buffer(); unsigned bufferLength = bitmap->bufferLength(); for (unsigned i = 0; i < bufferLength; i += 4) { // Use green, which is always in the middle. UInt8 alpha = (255 - buffer[i + 1]) * fillColor.alpha() / 255; buffer[i] = fillColor.blue(); buffer[i + 1] = fillColor.green(); buffer[i + 2] = fillColor.red(); buffer[i + 3] = alpha; } graphicsContext->drawWindowsBitmap(bitmap.get(), textRect.location()); } else graphicsContext->releaseWindowsContext(hdc, textRect, true, false); }
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { cairo_t* cr = context->platformContext(); cairo_save(cr); font->setFont(cr); GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from); float offset = point.x(); for (int i = 0; i < numGlyphs; i++) { glyphs[i].x = offset; glyphs[i].y = point.y(); offset += glyphBuffer.advanceAt(from + i); } Color fillColor = context->fillColor(); // Text shadow, inspired by FontMac IntSize shadowSize; int shadowBlur = 0; Color shadowColor; bool hasShadow = context->textDrawingMode() == cTextFill && context->getShadow(shadowSize, shadowBlur, shadowColor); // TODO: Blur support if (hasShadow) { // Disable graphics context shadows (not yet implemented) and paint them manually context->clearShadow(); Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); cairo_save(cr); float red, green, blue, alpha; shadowFillColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha); cairo_translate(cr, shadowSize.width(), shadowSize.height()); cairo_show_glyphs(cr, glyphs, numGlyphs); cairo_restore(cr); } if (context->textDrawingMode() & cTextFill) { if (context->fillGradient()) { cairo_set_source(cr, context->fillGradient()->platformGradient()); if (context->getAlpha() < 1.0f) { cairo_push_group(cr); cairo_paint_with_alpha(cr, context->getAlpha()); cairo_pop_group_to_source(cr); } } else if (context->fillPattern()) { TransformationMatrix affine; cairo_set_source(cr, context->fillPattern()->createPlatformPattern(affine)); if (context->getAlpha() < 1.0f) { cairo_push_group(cr); cairo_paint_with_alpha(cr, context->getAlpha()); cairo_pop_group_to_source(cr); } } else { float red, green, blue, alpha; fillColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha()); } cairo_show_glyphs(cr, glyphs, numGlyphs); } if (context->textDrawingMode() & cTextStroke) { if (context->strokeGradient()) { cairo_set_source(cr, context->strokeGradient()->platformGradient()); if (context->getAlpha() < 1.0f) { cairo_push_group(cr); cairo_paint_with_alpha(cr, context->getAlpha()); cairo_pop_group_to_source(cr); } } else if (context->strokePattern()) { TransformationMatrix affine; cairo_set_source(cr, context->strokePattern()->createPlatformPattern(affine)); if (context->getAlpha() < 1.0f) { cairo_push_group(cr); cairo_paint_with_alpha(cr, context->getAlpha()); cairo_pop_group_to_source(cr); } } else { Color strokeColor = context->strokeColor(); float red, green, blue, alpha; strokeColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha()); } cairo_glyph_path(cr, glyphs, numGlyphs); cairo_set_line_width(cr, context->strokeThickness()); cairo_stroke(cr); } // Re-enable the platform shadow we disabled earlier if (hasShadow) context->setShadow(shadowSize, shadowBlur, shadowColor); cairo_restore(cr); }
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { cairo_t* cr = context->platformContext(); cairo_save(cr); cairo_set_scaled_font(cr, font->platformData().scaledFont()); GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from); float offset = 0.0f; for (int i = 0; i < numGlyphs; i++) { glyphs[i].x = offset; glyphs[i].y = 0.0f; offset += glyphBuffer.advanceAt(from + i); } Color fillColor = context->fillColor(); // Synthetic Oblique if(font->platformData().syntheticOblique()) { cairo_matrix_t mat = {1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, point.x(), point.y()}; cairo_transform(cr, &mat); } else { cairo_translate(cr, point.x(), point.y()); } // Text shadow, inspired by FontMac FloatSize shadowOffset; float shadowBlur = 0; Color shadowColor; bool hasShadow = context->textDrawingMode() & cTextFill && context->getShadow(shadowOffset, shadowBlur, shadowColor); // TODO: Blur support if (hasShadow) { // Disable graphics context shadows (not yet implemented) and paint them manually context->clearShadow(); Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); cairo_save(cr); float red, green, blue, alpha; shadowFillColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha); #if ENABLE(FILTERS) cairo_text_extents_t extents; cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents); FloatRect rect(FloatPoint(), FloatSize(extents.width, extents.height)); IntSize shadowBufferSize; FloatRect shadowRect; float radius = 0; context->calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowOffset, shadowBlur); // Draw shadow into a new ImageBuffer OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); GraphicsContext* shadowContext = shadowBuffer->context(); cairo_t* shadowCr = shadowContext->platformContext(); cairo_translate(shadowCr, radius, extents.height + radius); cairo_set_scaled_font(shadowCr, font->platformData().scaledFont()); cairo_show_glyphs(shadowCr, glyphs, numGlyphs); if (font->syntheticBoldOffset()) { cairo_save(shadowCr); cairo_translate(shadowCr, font->syntheticBoldOffset(), 0); cairo_show_glyphs(shadowCr, glyphs, numGlyphs); cairo_restore(shadowCr); } cairo_translate(cr, 0.0, -extents.height); context->applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius); #else cairo_translate(cr, shadowOffset.width(), shadowOffset.height()); cairo_show_glyphs(cr, glyphs, numGlyphs); if (font->syntheticBoldOffset()) { cairo_save(cr); cairo_translate(cr, font->syntheticBoldOffset(), 0); cairo_show_glyphs(cr, glyphs, numGlyphs); cairo_restore(cr); } #endif cairo_restore(cr); } if (context->textDrawingMode() & cTextFill) { if (context->fillGradient()) { cairo_set_source(cr, context->fillGradient()->platformGradient()); if (context->getAlpha() < 1.0f) { cairo_push_group(cr); cairo_paint_with_alpha(cr, context->getAlpha()); cairo_pop_group_to_source(cr); } } else if (context->fillPattern()) { AffineTransform affine; cairo_pattern_t* pattern = context->fillPattern()->createPlatformPattern(affine); cairo_set_source(cr, pattern); if (context->getAlpha() < 1.0f) { cairo_push_group(cr); cairo_paint_with_alpha(cr, context->getAlpha()); cairo_pop_group_to_source(cr); } cairo_pattern_destroy(pattern); } else { float red, green, blue, alpha; fillColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha()); } cairo_show_glyphs(cr, glyphs, numGlyphs); if (font->syntheticBoldOffset()) { cairo_save(cr); cairo_translate(cr, font->syntheticBoldOffset(), 0); cairo_show_glyphs(cr, glyphs, numGlyphs); cairo_restore(cr); } } // Prevent running into a long computation within cairo. If the stroke width is // twice the size of the width of the text we will not ask cairo to stroke // the text as even one single stroke would cover the full wdth of the text. // See https://bugs.webkit.org/show_bug.cgi?id=33759. if (context->textDrawingMode() & cTextStroke && context->strokeThickness() < 2 * offset) { if (context->strokeGradient()) { cairo_set_source(cr, context->strokeGradient()->platformGradient()); if (context->getAlpha() < 1.0f) { cairo_push_group(cr); cairo_paint_with_alpha(cr, context->getAlpha()); cairo_pop_group_to_source(cr); } } else if (context->strokePattern()) { AffineTransform affine; cairo_pattern_t* pattern = context->strokePattern()->createPlatformPattern(affine); cairo_set_source(cr, pattern); if (context->getAlpha() < 1.0f) { cairo_push_group(cr); cairo_paint_with_alpha(cr, context->getAlpha()); cairo_pop_group_to_source(cr); } cairo_pattern_destroy(pattern); } else { Color strokeColor = context->strokeColor(); float red, green, blue, alpha; strokeColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha()); } cairo_glyph_path(cr, glyphs, numGlyphs); cairo_set_line_width(cr, context->strokeThickness()); cairo_stroke(cr); } // Re-enable the platform shadow we disabled earlier if (hasShadow) context->setShadow(shadowOffset, shadowBlur, shadowColor, DeviceColorSpace); cairo_restore(cr); }
inline static float offsetToMiddleOfAdvanceAtIndex(const GlyphBuffer& glyphBuffer, size_t i) { return glyphBuffer.advanceAt(i) / 2; }
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, const FloatPoint& point, const FloatRect& textRect) const { SkScalar x = SkFloatToScalar(point.x()); SkScalar y = SkFloatToScalar(point.y()); const OpenTypeVerticalData* verticalData = font->verticalData(); if (font->platformData().orientation() == Vertical && verticalData) { SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); SkPoint* pos = storage.get(); AffineTransform savedMatrix = gc->getCTM(); gc->concatCTM(AffineTransform(0, -1, 1, 0, point.x(), point.y())); gc->concatCTM(AffineTransform(1, 0, 0, 1, -point.x(), -point.y())); const unsigned kMaxBufferLength = 256; Vector<FloatPoint, kMaxBufferLength> translations; const FontMetrics& metrics = font->fontMetrics(); SkScalar verticalOriginX = SkFloatToScalar(point.x() + metrics.floatAscent() - metrics.floatAscent(IdeographicBaseline)); float horizontalOffset = point.x(); unsigned glyphIndex = 0; while (glyphIndex < numGlyphs) { unsigned chunkLength = std::min(kMaxBufferLength, numGlyphs - glyphIndex); const Glyph* glyphs = glyphBuffer.glyphs(from + glyphIndex); translations.resize(chunkLength); verticalData->getVerticalTranslationsForGlyphs(font, &glyphs[0], chunkLength, reinterpret_cast<float*>(&translations[0])); x = verticalOriginX; y = SkFloatToScalar(point.y() + horizontalOffset - point.x()); float currentWidth = 0; for (unsigned i = 0; i < chunkLength; ++i, ++glyphIndex) { pos[i].set( x + SkIntToScalar(lroundf(translations[i].x())), y + -SkIntToScalar(-lroundf(currentWidth - translations[i].y()))); currentWidth += glyphBuffer.advanceAt(from + glyphIndex); } horizontalOffset += currentWidth; paintGlyphs(gc, font, glyphs, chunkLength, pos, textRect); } gc->setCTM(savedMatrix); return; } if (!glyphBuffer.hasOffsets()) { SkAutoSTMalloc<64, SkScalar> storage(numGlyphs); SkScalar* xpos = storage.get(); const float* adv = glyphBuffer.advances(from); for (unsigned i = 0; i < numGlyphs; i++) { xpos[i] = x; x += SkFloatToScalar(adv[i]); } const Glyph* glyphs = glyphBuffer.glyphs(from); paintGlyphsHorizontal(gc, font, glyphs, numGlyphs, xpos, SkFloatToScalar(y), textRect); return; } // FIXME: text rendering speed: // Android has code in their WebCore fork to special case when the // GlyphBuffer has no advances other than the defaults. In that case the // text drawing can proceed faster. However, it's unclear when those // patches may be upstreamed to WebKit so we always use the slower path // here. SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); SkPoint* pos = storage.get(); const FloatSize* offsets = glyphBuffer.offsets(from); const float* advances = glyphBuffer.advances(from); SkScalar advanceSoFar = SkFloatToScalar(0); for (unsigned i = 0; i < numGlyphs; i++) { pos[i].set( x + SkFloatToScalar(offsets[i].width()) + advanceSoFar, y + SkFloatToScalar(offsets[i].height())); advanceSoFar += SkFloatToScalar(advances[i]); } const Glyph* glyphs = glyphBuffer.glyphs(from); paintGlyphs(gc, font, glyphs, numGlyphs, pos, textRect); }
static void drawglyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point, float height, float ascent, uint32 penalpha, uint32 penr, uint32 peng, uint32 penb, int shadowx, int shadowy) { GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from)); struct OutlineFont *face = font->m_platformData.m_face; uint32 ysize = font->m_platformData.m_size; int32 imagewidth = 0; uint32 onlyspaces = TRUE; for (int i = 0; i < numGlyphs; i++) { if (32 != glyphs[i]) onlyspaces = FALSE; imagewidth += glyphBuffer.advanceAt(from + i); } if (onlyspaces) return; if (imagewidth <= 0) return; imagewidth += 2 * (ysize * amigaConfig.fontXDPI / 72); Vector<unsigned> *glyphRGBABuffer = new Vector<unsigned>(imagewidth * height); if (!glyphRGBABuffer) return; glyphRGBABuffer->fill(0); int32 offsetinimg = 0; uint32 shiftleft = 0; for (int i = 0; i < numGlyphs; i++) { if (32 == glyphs[i]) { offsetinimg += glyphBuffer.advanceAt(from + i); continue; } struct GlyphMap *glyph; if (IDiskfont->ESetInfo(&face->olf_EEngine, OT_GlyphCode, glyphs[i], TAG_END)) continue; //do not handle error struct OutlineFont *curface = face; if (IDiskfont->EObtainInfo(&face->olf_EEngine, OT_GlyphMap8Bit, &glyph, TAG_END)) { uint32 ok = FALSE; if (amigaConfig.unicodeFace && !IDiskfont->ESetInfo(&amigaConfig.unicodeFace->olf_EEngine, OT_PointHeight, ysize << 16, OT_GlyphCode, glyphs[i], TAG_END) && !IDiskfont->EObtainInfo(&amigaConfig.unicodeFace->olf_EEngine, OT_GlyphMap8Bit, &glyph, TAG_END)) { curface = amigaConfig.unicodeFace; ok = TRUE; } if (!ok && !IDiskfont->ESetInfo(&face->olf_EEngine, OT_GlyphCode, 0xFFFD, TAG_END) && !IDiskfont->EObtainInfo(&face->olf_EEngine, OT_GlyphMap8Bit, &glyph, TAG_END)) ok = TRUE; if (!ok && !IDiskfont->ESetInfo(&face->olf_EEngine, OT_GlyphCode, '?', TAG_END) && !IDiskfont->EObtainInfo(&face->olf_EEngine, OT_GlyphMap8Bit, &glyph, TAG_END)) ok = TRUE; if (!ok) continue; //do not handle error } if (amigaConfig.fontKerning && i > 0) if (!IDiskfont->ESetInfo(&curface->olf_EEngine, OT_GlyphCode, glyphs[i -1], OT_GlyphCode2, glyphs[i], TAG_END)) { FIXED kern = 0; if (!IDiskfont->EObtainInfo(&curface->olf_EEngine, OT_TextKernPair, &kern, TAG_END)) if (kern) offsetinimg -= (int)(kern / 65536.0 * ysize * amigaConfig.fontYDPI / 72); } uint32 left = glyph->glm_BlackLeft; uint32 top = glyph->glm_BlackTop; int32 width = glyph->glm_BlackWidth; int32 gheight = glyph->glm_BlackHeight; int32 x0 = glyph->glm_X0; int32 y0 = glyph->glm_Y0; uint32 modulo = glyph->glm_BMModulo; int32 imgoffsetx = -x0 + left; if (offsetinimg + imgoffsetx < 0) { if (0 == i) { shiftleft = -imgoffsetx; if (shiftleft > ysize) { shiftleft = ysize; imgoffsetx = -ysize; } offsetinimg = shiftleft; } else imgoffsetx = 0; } int32 imgoffsety = ascent - y0 + top; if (imgoffsety < 0) imgoffsety = 0; if (offsetinimg + imgoffsetx + width > imagewidth) { int32 signedwidth = imagewidth - offsetinimg - imgoffsetx; if (signedwidth < 0) signedwidth = 0; width = signedwidth; } if (imgoffsety + gheight > (int)height) gheight = height - imgoffsety; for (int32 y = 0; y < gheight ; y++) { uint32 top_mod_left = (y + top) * modulo + left; for (int32 x = 0; x < width; x++) if ((offsetinimg + imgoffsetx + x < imagewidth) && (offsetinimg + imgoffsetx + x >= 0)) { uint32 a = penalpha * glyph->glm_BitMap[top_mod_left + x] / 255; if (a) { uint32 oldARGB = (*glyphRGBABuffer)[(imgoffsety + y) * imagewidth + offsetinimg + imgoffsetx + x]; if (oldARGB) a = std::max((oldARGB >> 24), a); (*glyphRGBABuffer)[(imgoffsety + y) * imagewidth + offsetinimg + imgoffsetx + x] = (a << 24) | ((penr * a / 255) << 16) | ((peng * a / 255) << 8) | (penb * a / 255); } } } offsetinimg += glyphBuffer.advanceAt(from + i); IDiskfont->EReleaseInfo(&curface->olf_EEngine, OT_GlyphMap8Bit, glyph, TAG_END); }
void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { 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; TransparencyAwareGlyphPainter painter(graphicsContext, font, glyphBuffer, from, numGlyphs, point); // We draw the glyphs in chunks to avoid having to do a heap allocation for // the arrays of characters and advances. Since ExtTextOut is the // lowest-level text output function on Windows, there should be little // penalty for splitting up the text. On the other hand, the buffer cannot // be bigger than 4094 or the function will fail. const int kMaxBufferLength = 256; Vector<WORD, kMaxBufferLength> glyphs; Vector<int, kMaxBufferLength> advances; int glyphIndex = 0; // The starting glyph of the current chunk. int curAdvance = 0; // How far from the left the current chunk is. while (glyphIndex < numGlyphs) { // How many chars will be in this chunk? int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex); glyphs.resize(curLen); advances.resize(curLen); int curWidth = 0; for (int i = 0; i < curLen; ++i, ++glyphIndex) { glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex); advances[i] = static_cast<int>(glyphBuffer.advanceAt(from + glyphIndex)); // Bug 26088 - very large positive or negative runs can fail to // render so we clamp the size here. In the specs, negative // letter-spacing is implementation-defined, so this should be // fine, and it matches Safari's implementation. The call actually // seems to crash if kMaxNegativeRun is set to somewhere around // -32830, so we give ourselves a little breathing room. const int maxNegativeRun = -32768; const int maxPositiveRun = 32768; if ((curWidth + advances[i] < maxNegativeRun) || (curWidth + advances[i] > maxPositiveRun)) advances[i] = 0; curWidth += advances[i]; } // Actually draw the glyphs (with retry on failure). bool success = false; for (int executions = 0; executions < 2; ++executions) { success = painter.drawGlyphs(curLen, &glyphs[0], &advances[0], curAdvance); if (!success && executions == 0) { // Ask the browser to load the font for us and retry. ChromiumBridge::ensureFontLoaded(font->platformData().hfont()); continue; } break; } if (!success) LOG_ERROR("Unable to draw the glyphs after second attempt"); curAdvance += curWidth; } }
void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { SkColor color = graphicsContext->effectiveFillColor(); unsigned char alpha = SkColorGetA(color); // Skip 100% transparent text; no need to draw anything. if (!alpha && graphicsContext->strokeStyle() == NoStroke && !graphicsContext->hasShadow()) return; // We draw the glyphs in chunks to avoid having to do a heap allocation for // the arrays of characters and advances. const int kMaxBufferLength = 256; Vector<int, kMaxBufferLength> advances; int glyphIndex = 0; // The starting glyph of the current chunk. float horizontalOffset = point.x(); // The floating point offset of the left side of the current glyph. #if ENABLE(OPENTYPE_VERTICAL) const OpenTypeVerticalData* verticalData = font->verticalData(); if (verticalData) { Vector<FloatPoint, kMaxBufferLength> translations; Vector<GOFFSET, kMaxBufferLength> offsets; // Skia doesn't have matrix for glyph coordinate space, so we rotate back the CTM. AffineTransform savedMatrix = graphicsContext->getCTM(); graphicsContext->concatCTM(AffineTransform(0, -1, 1, 0, point.x(), point.y())); graphicsContext->concatCTM(AffineTransform(1, 0, 0, 1, -point.x(), -point.y())); const FontMetrics& metrics = font->fontMetrics(); SkScalar verticalOriginX = SkFloatToScalar(point.x() + metrics.floatAscent() - metrics.floatAscent(IdeographicBaseline)); while (glyphIndex < numGlyphs) { // How many chars will be in this chunk? int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex); const Glyph* glyphs = glyphBuffer.glyphs(from + glyphIndex); translations.resize(curLen); verticalData->getVerticalTranslationsForGlyphs(font, &glyphs[0], curLen, reinterpret_cast<float*>(&translations[0])); // To position glyphs vertically, we use offsets instead of advances. advances.resize(curLen); advances.fill(0); offsets.resize(curLen); float currentWidth = 0; for (int i = 0; i < curLen; ++i, ++glyphIndex) { offsets[i].du = lroundf(translations[i].x()); offsets[i].dv = -lroundf(currentWidth - translations[i].y()); currentWidth += glyphBuffer.advanceAt(from + glyphIndex); } SkPoint origin; origin.set(verticalOriginX, SkFloatToScalar(point.y() + horizontalOffset - point.x())); horizontalOffset += currentWidth; paintSkiaText(graphicsContext, font->platformData(), curLen, &glyphs[0], &advances[0], &offsets[0], &origin); } graphicsContext->setCTM(savedMatrix); return; } #endif // In order to round all offsets to the correct pixel boundary, this code keeps track of the absolute position // of each glyph in floating point units and rounds to integer advances at the last possible moment. int lastHorizontalOffsetRounded = lroundf(horizontalOffset); // The rounded offset of the left side of the last glyph rendered. Vector<WORD, kMaxBufferLength> glyphs; while (glyphIndex < numGlyphs) { // How many chars will be in this chunk? int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex); glyphs.resize(curLen); advances.resize(curLen); float currentWidth = 0; for (int i = 0; i < curLen; ++i, ++glyphIndex) { glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex); horizontalOffset += glyphBuffer.advanceAt(from + glyphIndex); advances[i] = lroundf(horizontalOffset) - lastHorizontalOffsetRounded; lastHorizontalOffsetRounded += advances[i]; currentWidth += glyphBuffer.advanceAt(from + glyphIndex); // Bug 26088 - very large positive or negative runs can fail to // render so we clamp the size here. In the specs, negative // letter-spacing is implementation-defined, so this should be // fine, and it matches Safari's implementation. The call actually // seems to crash if kMaxNegativeRun is set to somewhere around // -32830, so we give ourselves a little breathing room. const int maxNegativeRun = -32768; const int maxPositiveRun = 32768; if ((currentWidth + advances[i] < maxNegativeRun) || (currentWidth + advances[i] > maxPositiveRun)) advances[i] = 0; } SkPoint origin = point; origin.fX += SkFloatToScalar(horizontalOffset - point.x() - currentWidth); paintSkiaText(graphicsContext, font->platformData(), curLen, &glyphs[0], &advances[0], 0, &origin); } }
// We need to draw the glyphBuffer glyphs/advances with the pSimpleFontData font onto the // pGraphicsContext pSurface. We draw glyphCount glyphs starting at the glyphIndexBegin. void Font::drawGlyphs(GraphicsContext* pGraphicsContext, const SimpleFontData* pSimpleFontData, const GlyphBuffer& glyphBuffer, int glyphIndexBegin, int glyphCount, const FloatPoint& point) const { // 11/09/09 CSidhall Added notify start of process to user NOTIFY_PROCESS_STATUS(EA::WebKit::kVProcessTypeDrawGlyph, EA::WebKit::kVProcessStatusStarted); #if defined(EA_DEBUG) && defined(AUTHOR_PPEDRIANA_DISABLED) && defined(EA_PLATFORM_WINDOWS) TraceGlyphBufferToString(pSimpleFontData, glyphBuffer, glyphIndexBegin, glyphCount, point); #endif GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(glyphIndexBegin)); float offset = 0; int x_offset = 0; EA::Internal::IFont* pFont = pSimpleFontData->m_font.mpFont; EA::Internal::IGlyphCache* pGlyphCache = EA::WebKit::GetGlyphCache(); EAW_ASSERT_MSG(pGlyphCache, "GlyphCache is not set"); if(!pGlyphCache) { NOTIFY_PROCESS_STATUS(EA::WebKit::kVProcessTypeDrawGlyph, EA::WebKit::kVProcessStatusEnded); return; } EA::Internal::ITextureInfo* pTI = pGlyphCache->GetTextureInfo(0); // Right now we hard-code usage of what is the only texture. EAW_ASSERT_MSG(pTI, "GlyphCache is not initialized with enough number of textures"); if(!pTI) { NOTIFY_PROCESS_STATUS(EA::WebKit::kVProcessTypeDrawGlyph, EA::WebKit::kVProcessStatusEnded); return; } const int32_t textureSize = (int32_t)pTI->GetSize(); EA::Internal::IGlyphTextureInfo gti; EA::Internal::GlyphMetrics glyphMetrics; GlyphDrawInfoArray gdiArray((size_t)(unsigned)glyphCount); // Walk through the list of glyphs and build up render info for each one. for (int i = 0; i < glyphCount; i++) { EA::Internal::GlyphId g = glyphs[i]; if(!pFont->GetGlyphMetrics(g, glyphMetrics)) { EAW_ASSERT_MSG(false, "Font::drawGlyphs: invalid glyph/Font combo."); pFont->GetGlyphIds(L"?", 1, &g, true); pFont->GetGlyphMetrics(g, glyphMetrics); } if(!pGlyphCache->GetGlyphTextureInfo(pFont, g, gti)) { const EA::Internal::GlyphBitmap* pGlyphBitmap; if(pFont->RenderGlyphBitmap(&pGlyphBitmap, g)) { if(pGlyphCache->AddGlyphTexture(pFont, g, pGlyphBitmap->mpData, pGlyphBitmap->mnWidth, pGlyphBitmap->mnHeight, pGlyphBitmap->mnStride, (uint32_t)pGlyphBitmap->mBitmapFormat, gti)) { pGlyphCache->EndUpdate(gti.mpTextureInfo); } else { EAW_ASSERT_MSG(false, "Font::drawGlyphs: AddGlyphTexture failed."); gti.mX1 = gti.mX2 = 0; // Make this an empty glyph. Normally this should never execute. } pFont->DoneGlyphBitmap(pGlyphBitmap); } else { EAW_ASSERT_MSG(false, "Font::drawGlyphs: invalid glyph/Font combo."); gti.mX1 = gti.mX2 = 0; // Make this an empty glyph. Normally this should never execute. } } // Apply kerning. // Note by Paul Pedriana: Can we really apply kerning here at the render stage without it looking // wrong? It seems to me this cannot work unless kerning is also taken into account at the // layout stage. To do: See if in fact kerning is taken into account at the layout stage. EA::Internal::Kerning kerning; if((i > 0) && pFont->GetKerning(glyphs[i - 1], g, kerning, 0)) offset += kerning.mfKernX; // The values we calculate here are relative to the current pen position at the // baseline position of [xoffset, 0], where +X is rightward and +Y is upward. gdiArray[i].x1 = (int)(offset + glyphMetrics.mfHBearingX); gdiArray[i].x2 = (int)(offset + glyphMetrics.mfHBearingX + glyphMetrics.mfSizeX); gdiArray[i].y1 = (int)(glyphMetrics.mfHBearingY); gdiArray[i].y2 = (int)(glyphMetrics.mfHBearingY - glyphMetrics.mfSizeY); gdiArray[i].tx = (int)(gti.mX1 * textureSize); // Convert [0..1] to [0..textureSize] gdiArray[i].ty = (int)(gti.mY1 * textureSize); // advanceAt should return a value that is usually equivalent to glyphMetrics.mfHAdvanceX, at least // for most simple Western text. A case where it would be different would be Arabic combining glyphs, // and custom kerning, though kerning adjustments are handled above. offset += glyphBuffer.advanceAt(glyphIndexBegin + i); // Free wrapper if(gti.mpTextureInfo) gti.mpTextureInfo->DestroyWrapper(); } // Find the X and Y minima and maxima of the glyph boxes. // To do: We can improve the efficiency of this code in a couple of ways, including moving the // min/max tests up into the glyphMetrics code above. int xMin = gdiArray[0].x1; int xMax = gdiArray[0].x2; int yMin = gdiArray[0].y2; // y2 is min because y goes upward. int yMax = gdiArray[0].y1; for (GlyphDrawInfoArray::const_iterator it = gdiArray.begin(); it != gdiArray.end(); ++it) { const GlyphDrawInfo& gdi = *it; // We assume tha x1 is always <= x2. if (gdi.x1 < xMin) xMin = gdi.x1; if (gdi.x2 > xMax) xMax = gdi.x2; // if (gdi.y1 < yMin) // We normally don't need this check, because y2 will usually (or always?) be less than y1. // yMin = gdi.y1; if (gdi.y2 < yMin) yMin = gdi.y2; if (gdi.y1 > yMax) yMax = gdi.y1; // if (gdi.y2 > yMax) // We normally don't need this check, because y1 will usually (or always?) be greater than y2. // yMax = gdi.y2; } const uint16_t destWidth = (abs(xMin) + xMax); // abs(xMin) because it's possible the left of the first glyph is to the left of the origin. Note by Paul Pedriana: Shouldn't this instead be (xMax - min(xMin, 0))? const uint16_t destHeight = (yMax - yMin); if(destWidth && destHeight) // (If we are drawing just space chars (which often happens), then destWidth and/or destHeight will be zero) { // Question by Paul Pedriana: What is the following code doing? I copied this from the // WebKit Freetype equivalent of this function assuming it must be useful. It seems to // me that it is chopping off any glyph pixels to the left of zero. This is probably // going to usually be OK, because it is abnormal for the first char of just about any // written language to be a combining char (and thus drawn to the left of the pen position). if (gdiArray[0].x1 < 0) { x_offset = gdiArray[0].x1; gdiArray[0].x1 = 0; } EA::Raster::Surface* const pSurface = pGraphicsContext->platformContext(); const Color penColor = pGraphicsContext->fillColor(); // Write the glyphs into a linear buffer. // To consider: See if it's possible to often get away with using stack space for this by // using Vector<uint32_t, N> in order to avoid a memory allocation. A typical // width is ~400 pixels and a typical height ~16 pixels, which is 25600 bytes. // So unless the string is small there won't be any benefit to this. Vector<uint32_t> glyphRGBABuffer(destWidth * destHeight); const int penA = penColor.alpha(); const int penR = penColor.red(); const int penG = penColor.green(); const int penB = penColor.blue(); const int penRGB = (penR << 16) | (penG << 8) | penB; glyphRGBABuffer.fill(0); for (int i = 0; i < glyphCount; i++) { const GlyphDrawInfo& gdi = gdiArray[i]; const uint8_t* pGlyphAlpha = (pTI->GetData()) + (gdi.ty * pTI->GetStride()) + gdi.tx; const int yOffset = (destHeight + yMin) - gdi.y1; // Note by Arpit Baldeva: Old index calculation below caused a memory overrun(or I should say underrun on http://get.adobe.com/flashplayer/). // Basically, yOffset * destWidth) + gdi.x1 could end up being negative if the yOffset is 0 and gdi.x1 is negative. Since I do want // to make sure that index is positive, I just force it to be at least 0. There is not enough understanding about this code as of now // and Paul said that he would take a look at this along with other Font problems he is currently looking at. const int bufferIndex = (yOffset * destWidth) + gdi.x1; EAW_ASSERT_FORMATTED(bufferIndex>=0, "Buffer Index is negative. This would corrupt memory. yOffset:%d,destWidth:%u,gdi.x1:%d",yOffset,destWidth,gdi.x1); uint32_t* pDestColor = glyphRGBABuffer.data() + (bufferIndex >= 0 ? bufferIndex : 0);//Old Index calculation- (yOffset * destWidth) + gdi.x1; const int glyphWidth = (gdi.x2 - gdi.x1); const int glyphHeight = (gdi.y1 - gdi.y2); for (int y = 0; y < glyphHeight; ++y) { for (int x = 0; x < glyphWidth; ++x) { //+ 1/5/10 CSidhall - When building the text string texture map, kerning can make certain letters overlap and stomp over the alpha of previous letters so // we need to preserve texels that were aleady set. Should be able to OR herer because we have a clean buffer and penRGB is the same. // Old code: // pDestColor[x] = ((penA * pGlyphAlpha[x] / 255) << 24) | penRGB; // New code: pDestColor[x] |= ((penA * pGlyphAlpha[x] / 255) << 24) | penRGB; // -CS } pDestColor += destWidth; pGlyphAlpha += pTI->GetStride(); } } // It would probably be faster if we kept around a surface for multiple usage instead of // continually recreating this one. EA::Raster::Surface* const pGlyphSurface = EA::Raster::CreateSurface((void*)glyphRGBABuffer.data(), destWidth, destHeight, destWidth * 4, EA::Raster::kPixelFormatTypeARGB, false, false); EA::Raster::Rect rectSrc; EA::Raster::Rect rectDest; rectSrc.w = destWidth; rectSrc.h = destHeight; rectSrc.x = 0; rectSrc.y = 0; rectDest.x = (int)point.x() + x_offset + pGraphicsContext->origin().width(); rectDest.y = (int)point.y() - yMax + pGraphicsContext->origin().height(); if (pGraphicsContext->transparencyLayer() == 1.0) EA::Raster::Blit(pGlyphSurface, &rectSrc, pSurface, &rectDest); else { const float fTransparency = pGraphicsContext->transparencyLayer(); EA::Raster::Surface* const pSurfaceWithAlpha = EA::Raster::CreateTransparentSurface(pGlyphSurface, (int)(fTransparency * 255)); EA::Raster::Blit(pSurfaceWithAlpha, &rectSrc, pSurface, &rectDest); EA::Raster::DestroySurface(pSurfaceWithAlpha); } EA::Raster::DestroySurface(pGlyphSurface); } pTI->DestroyWrapper(); NOTIFY_PROCESS_STATUS(EA::WebKit::kVProcessTypeDrawGlyph, EA::WebKit::kVProcessStatusEnded); }
void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const TextRun& run, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { SVGFontElement* fontElement = 0; SVGFontFaceElement* fontFaceElement = 0; const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement); if (!fontElement || !fontFaceElement) return; // We can only paint SVGFonts if a context is available. RenderSVGResource* activePaintingResource = activePaintingResourceFromRun(run); RenderObject* renderObject = renderObjectFromRun(run); RenderObject* parentRenderObject = firstParentRendererForNonTextNode(renderObject); RenderStyle* parentRenderObjectStyle = 0; ASSERT(renderObject); if (!activePaintingResource) { // TODO: We're only supporting simple filled HTML text so far. RenderSVGResourceSolidColor* solidPaintingResource = RenderSVGResource::sharedSolidPaintingResource(); solidPaintingResource->setColor(context->fillColor()); activePaintingResource = solidPaintingResource; } bool isVerticalText = false; if (parentRenderObject) { parentRenderObjectStyle = parentRenderObject->style(); ASSERT(parentRenderObjectStyle); isVerticalText = parentRenderObjectStyle->svgStyle()->isVerticalWritingMode(); } float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm()); ASSERT(activePaintingResource); FloatPoint glyphOrigin; glyphOrigin.setX(svgFontData->horizontalOriginX() * scale); glyphOrigin.setY(svgFontData->horizontalOriginY() * scale); FloatPoint currentPoint = point; RenderSVGResourceMode resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode; for (int i = 0; i < numGlyphs; ++i) { Glyph glyph = glyphBuffer.glyphAt(from + i); if (!glyph) continue; float advance = glyphBuffer.advanceAt(from + i); SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph); ASSERT(!svgGlyph.isPartOfLigature); ASSERT(svgGlyph.tableEntry == glyph); SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, svgFontData); // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations). if (svgGlyph.pathData.isEmpty()) { if (isVerticalText) currentPoint.move(0, advance); else currentPoint.move(advance, 0); continue; } context->save(); if (isVerticalText) { glyphOrigin.setX(svgGlyph.verticalOriginX * scale); glyphOrigin.setY(svgGlyph.verticalOriginY * scale); } AffineTransform glyphPathTransform; glyphPathTransform.translate(currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y()); glyphPathTransform.scale(scale, -scale); Path glyphPath = svgGlyph.pathData; glyphPath.transform(glyphPathTransform); if (activePaintingResource->applyResource(parentRenderObject, parentRenderObjectStyle, context, resourceMode)) { if (renderObject && renderObject->isSVGInlineText()) { const RenderSVGInlineText* textRenderer = toRenderSVGInlineText(renderObject); context->setStrokeThickness(context->strokeThickness() * textRenderer->scalingFactor()); } activePaintingResource->postApplyResource(parentRenderObject, context, resourceMode, &glyphPath, 0); } context->restore(); if (isVerticalText) currentPoint.move(0, advance); else currentPoint.move(advance, 0); } }
void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { #if USE(WXGC) wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext()); wxGraphicsContext* gc = dc->GetGraphicsContext(); gc->PushState(); cairo_t* cr = (cairo_t*)gc->GetNativeContext(); wxFont* wxfont = font->getWxFont(); cairo_scaled_font_t* scaled_font = 0; #if wxUSE_PANGO PangoFont* pangoFont = createPangoFontForFont(wxfont); PangoFontMap* fontMap = pangoFontMap(); PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(fontMap)); scaled_font = createScaledFontForFont(wxfont); #elif __WXMSW__ cairo_matrix_t sizeMatrix, ctm; cairo_matrix_init_identity(&ctm); int size = font->platformData().size(); cairo_matrix_init_scale(&sizeMatrix, size, size); cairo_font_options_t* fontOptions = cairo_font_options_create(); cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_SUBPIXEL); cairo_font_face_t* win_face = cairo_win32_font_face_create_for_hfont((HFONT)wxfont->GetHFONT()); scaled_font = cairo_scaled_font_create(win_face, &sizeMatrix, &ctm, fontOptions); #endif ASSERT(scaled_font); GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from)); float offset = point.x(); for (int i = 0; i < numGlyphs; i++) { #if wxUSE_PANGO glyphs[i].index = pango_font_get_glyph(pangoFont, pangoContext, glyphBuffer.glyphAt(from + i)); #endif glyphs[i].x = offset; glyphs[i].y = point.y(); offset += glyphBuffer.advanceAt(from + i); } cairo_set_source_rgba(cr, color.Red()/255.0, color.Green()/255.0, color.Blue()/255.0, color.Alpha()/255.0); cairo_set_scaled_font(cr, scaled_font); cairo_show_glyphs(cr, glyphs, numGlyphs); cairo_scaled_font_destroy(scaled_font); gc->PopState(); #else wxDC* dc = graphicsContext->platformContext(); wxFont* wxfont = font->getWxFont(); if (wxfont && wxfont->IsOk()) dc->SetFont(*wxfont); dc->SetTextForeground(color); // convert glyphs to wxString GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from)); int offset = point.x(); wxString text = wxEmptyString; for (unsigned i = 0; i < numGlyphs; i++) { text = text.Append((wxChar)glyphs[i]); offset += glyphBuffer.advanceAt(from + i); } // the y point is actually the bottom point of the text, turn it into the top float height = font->ascent() - font->descent(); wxCoord ypoint = (wxCoord) (point.y() - height); dc->DrawText(text, (wxCoord)point.x(), ypoint); #endif }