1/* 2 * Copyright (C) 2006 Apple Inc. All rights reserved. 3 * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com 4 * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com> 5 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> 6 * Copyright (C) 2010 Holger Hans Peter Freyther 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 25 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#include "config.h" 31#include "Font.h" 32 33#include "AffineTransform.h" 34#include "CairoUtilities.h" 35#include "GlyphBuffer.h" 36#include "Gradient.h" 37#include "GraphicsContext.h" 38#include "ImageBuffer.h" 39#include "Pattern.h" 40#include "PlatformContextCairo.h" 41#include "ShadowBlur.h" 42#include "SimpleFontData.h" 43 44namespace WebCore { 45 46static void drawGlyphsToContext(cairo_t* context, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs) 47{ 48 cairo_matrix_t originalTransform; 49 float syntheticBoldOffset = font->syntheticBoldOffset(); 50 if (syntheticBoldOffset) 51 cairo_get_matrix(context, &originalTransform); 52 53 cairo_set_scaled_font(context, font->platformData().scaledFont()); 54 cairo_show_glyphs(context, glyphs, numGlyphs); 55 56 if (syntheticBoldOffset) { 57 cairo_translate(context, syntheticBoldOffset, 0); 58 cairo_show_glyphs(context, glyphs, numGlyphs); 59 } 60 61 if (syntheticBoldOffset) 62 cairo_set_matrix(context, &originalTransform); 63} 64 65static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& point, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs) 66{ 67 ShadowBlur& shadow = graphicsContext->platformContext()->shadowBlur(); 68 69 if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow.type() == ShadowBlur::NoShadow) 70 return; 71 72 if (!graphicsContext->mustUseShadowBlur()) { 73 // Optimize non-blurry shadows, by just drawing text without the ShadowBlur. 74 cairo_t* context = graphicsContext->platformContext()->cr(); 75 cairo_save(context); 76 77 FloatSize shadowOffset(graphicsContext->state().shadowOffset); 78 cairo_translate(context, shadowOffset.width(), shadowOffset.height()); 79 setSourceRGBAFromColor(context, graphicsContext->state().shadowColor); 80 drawGlyphsToContext(context, font, glyphs, numGlyphs); 81 82 cairo_restore(context); 83 return; 84 } 85 86 cairo_text_extents_t extents; 87 cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents); 88 FloatRect fontExtentsRect(point.x() + extents.x_bearing, point.y() + extents.y_bearing, extents.width, extents.height); 89 90 if (GraphicsContext* shadowContext = shadow.beginShadowLayer(graphicsContext, fontExtentsRect)) { 91 drawGlyphsToContext(shadowContext->platformContext()->cr(), font, glyphs, numGlyphs); 92 shadow.endShadowLayer(graphicsContext); 93 } 94} 95 96void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, 97 int from, int numGlyphs, const FloatPoint& point) const 98{ 99 if (!font->platformData().size()) 100 return; 101 102 GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from)); 103 104 float offset = point.x(); 105 for (int i = 0; i < numGlyphs; i++) { 106 glyphs[i].x = offset; 107 glyphs[i].y = point.y(); 108 offset += glyphBuffer.advanceAt(from + i).width(); 109 } 110 111 PlatformContextCairo* platformContext = context->platformContext(); 112 drawGlyphsShadow(context, point, font, glyphs, numGlyphs); 113 114 cairo_t* cr = platformContext->cr(); 115 cairo_save(cr); 116 117 if (context->textDrawingMode() & TextModeFill) { 118 platformContext->prepareForFilling(context->state(), PlatformContextCairo::AdjustPatternForGlobalAlpha); 119 drawGlyphsToContext(cr, font, glyphs, numGlyphs); 120 } 121 122 // Prevent running into a long computation within cairo. If the stroke width is 123 // twice the size of the width of the text we will not ask cairo to stroke 124 // the text as even one single stroke would cover the full wdth of the text. 125 // See https://bugs.webkit.org/show_bug.cgi?id=33759. 126 if (context->textDrawingMode() & TextModeStroke && context->strokeThickness() < 2 * offset) { 127 platformContext->prepareForStroking(context->state()); 128 cairo_set_line_width(cr, context->strokeThickness()); 129 130 // This may disturb the CTM, but we are going to call cairo_restore soon after. 131 cairo_set_scaled_font(cr, font->platformData().scaledFont()); 132 cairo_glyph_path(cr, glyphs, numGlyphs); 133 cairo_stroke(cr); 134 } 135 136 cairo_restore(cr); 137} 138 139} 140