void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { #if defined(USE_FREETYPE) if (!primaryFont()->platformData().m_pattern) { drawSimpleText(context, run, point, from, to); return; } #endif cairo_t* cr = context->platformContext(); PangoLayout* layout = pango_cairo_create_layout(cr); setPangoAttributes(this, run, layout); gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length()); pango_layout_set_text(layout, utf8, -1); // Our layouts are single line PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0); // Get the region where this text will be laid out. We will use it to clip // the Cairo context, for when we are only painting part of the text run and // to calculate the size of the shadow buffer. PangoRegionType partialRegion = 0; char* start = g_utf8_offset_to_pointer(utf8, from); char* end = g_utf8_offset_to_pointer(start, to - from); int ranges[] = {start - utf8, end - utf8}; partialRegion = gdk_pango_layout_line_get_clip_region(layoutLine, 0, 0, ranges, 1); drawGlyphsShadow(context, cr, point, layoutLine, partialRegion); cairo_save(cr); cairo_translate(cr, point.x(), point.y()); float red, green, blue, alpha; context->fillColor().getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha); gdk_cairo_region(cr, partialRegion); cairo_clip(cr); pango_cairo_show_layout_line(cr, layoutLine); if (context->textDrawingMode() & TextModeStroke) { Color strokeColor = context->strokeColor(); strokeColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha); pango_cairo_layout_line_path(cr, layoutLine); cairo_set_line_width(cr, context->strokeThickness()); cairo_stroke(cr); } // Pango sometimes leaves behind paths we don't want cairo_new_path(cr); destroyPangoRegion(partialRegion); g_free(utf8); g_object_unref(layout); cairo_restore(cr); }
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); }