• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 Apple Computer, 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 COMPUTER, 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 COMPUTER, 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 "ContextShadow.h"
36 #include "GlyphBuffer.h"
37 #include "Gradient.h"
38 #include "GraphicsContext.h"
39 #include "PlatformContextCairo.h"
40 #include "ImageBuffer.h"
41 #include "Pattern.h"
42 #include "SimpleFontData.h"
43 
44 namespace WebCore {
45 
prepareContextForGlyphDrawing(cairo_t * context,const SimpleFontData * font,const FloatPoint & point)46 static void prepareContextForGlyphDrawing(cairo_t* context, const SimpleFontData* font, const FloatPoint& point)
47 {
48     static const float syntheticObliqueSkew = -tanf(14 * acosf(0) / 90);
49     cairo_set_scaled_font(context, font->platformData().scaledFont());
50     if (font->platformData().syntheticOblique()) {
51         cairo_matrix_t mat = {1, 0, syntheticObliqueSkew, 1, point.x(), point.y()};
52         cairo_transform(context, &mat);
53     } else
54         cairo_translate(context, point.x(), point.y());
55 }
56 
drawGlyphsToContext(cairo_t * context,const SimpleFontData * font,GlyphBufferGlyph * glyphs,int numGlyphs)57 static void drawGlyphsToContext(cairo_t* context, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs)
58 {
59     cairo_show_glyphs(context, glyphs, numGlyphs);
60     if (font->syntheticBoldOffset()) {
61         // We could use cairo_save/cairo_restore here, but two translations are likely faster.
62         cairo_translate(context, font->syntheticBoldOffset(), 0);
63         cairo_show_glyphs(context, glyphs, numGlyphs);
64         cairo_translate(context, -font->syntheticBoldOffset(), 0);
65     }
66 }
67 
drawGlyphsShadow(GraphicsContext * graphicsContext,const FloatPoint & point,const SimpleFontData * font,GlyphBufferGlyph * glyphs,int numGlyphs)68 static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& point, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs)
69 {
70     ContextShadow* shadow = graphicsContext->contextShadow();
71     ASSERT(shadow);
72 
73     if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow->m_type == ContextShadow::NoShadow)
74         return;
75 
76     if (!shadow->mustUseContextShadow(graphicsContext)) {
77         // Optimize non-blurry shadows, by just drawing text without the ContextShadow.
78         cairo_t* context = graphicsContext->platformContext()->cr();
79         cairo_save(context);
80         cairo_translate(context, shadow->m_offset.width(), shadow->m_offset.height());
81         setSourceRGBAFromColor(context, shadow->m_color);
82         prepareContextForGlyphDrawing(context, font, point);
83         cairo_show_glyphs(context, glyphs, numGlyphs);
84         cairo_restore(context);
85         return;
86     }
87 
88     cairo_text_extents_t extents;
89     cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents);
90     FloatRect fontExtentsRect(point.x(), point.y() - extents.height, extents.width, extents.height);
91     cairo_t* shadowContext = shadow->beginShadowLayer(graphicsContext, fontExtentsRect);
92     if (shadowContext) {
93         prepareContextForGlyphDrawing(shadowContext, font, point);
94         drawGlyphsToContext(shadowContext, font, glyphs, numGlyphs);
95         shadow->endShadowLayer(graphicsContext);
96     }
97 }
98 
drawGlyphs(GraphicsContext * context,const SimpleFontData * font,const GlyphBuffer & glyphBuffer,int from,int numGlyphs,const FloatPoint & point) const99 void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
100                       int from, int numGlyphs, const FloatPoint& point) const
101 {
102     GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);
103 
104     float offset = 0.0f;
105     for (int i = 0; i < numGlyphs; i++) {
106         glyphs[i].x = offset;
107         glyphs[i].y = 0.0f;
108         offset += glyphBuffer.advanceAt(from + i);
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     prepareContextForGlyphDrawing(cr, font, point);
117     if (context->textDrawingMode() & TextModeFill) {
118         if (context->fillGradient()) {
119             cairo_set_source(cr, context->fillGradient()->platformGradient());
120             if (context->getAlpha() < 1.0f) {
121                 cairo_push_group(cr);
122                 cairo_paint_with_alpha(cr, context->getAlpha());
123                 cairo_pop_group_to_source(cr);
124             }
125         } else if (context->fillPattern()) {
126             AffineTransform affine;
127             cairo_pattern_t* pattern = context->fillPattern()->createPlatformPattern(affine);
128             cairo_set_source(cr, pattern);
129             if (context->getAlpha() < 1.0f) {
130                 cairo_push_group(cr);
131                 cairo_paint_with_alpha(cr, context->getAlpha());
132                 cairo_pop_group_to_source(cr);
133             }
134             cairo_pattern_destroy(pattern);
135         } else {
136             float red, green, blue, alpha;
137             context->fillColor().getRGBA(red, green, blue, alpha);
138             cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
139         }
140         drawGlyphsToContext(cr, font, glyphs, numGlyphs);
141     }
142 
143     // Prevent running into a long computation within cairo. If the stroke width is
144     // twice the size of the width of the text we will not ask cairo to stroke
145     // the text as even one single stroke would cover the full wdth of the text.
146     //  See https://bugs.webkit.org/show_bug.cgi?id=33759.
147     if (context->textDrawingMode() & TextModeStroke && context->strokeThickness() < 2 * offset) {
148         if (context->strokeGradient()) {
149             cairo_set_source(cr, context->strokeGradient()->platformGradient());
150             if (context->getAlpha() < 1.0f) {
151                 cairo_push_group(cr);
152                 cairo_paint_with_alpha(cr, context->getAlpha());
153                 cairo_pop_group_to_source(cr);
154             }
155         } else if (context->strokePattern()) {
156             AffineTransform affine;
157             cairo_pattern_t* pattern = context->strokePattern()->createPlatformPattern(affine);
158             cairo_set_source(cr, pattern);
159             if (context->getAlpha() < 1.0f) {
160                 cairo_push_group(cr);
161                 cairo_paint_with_alpha(cr, context->getAlpha());
162                 cairo_pop_group_to_source(cr);
163             }
164             cairo_pattern_destroy(pattern);
165         } else {
166             float red, green, blue, alpha;
167             context->strokeColor().getRGBA(red, green, blue, alpha);
168             cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
169         }
170         cairo_glyph_path(cr, glyphs, numGlyphs);
171         cairo_set_line_width(cr, context->strokeThickness());
172         cairo_stroke(cr);
173     }
174 
175     cairo_restore(cr);
176 }
177 
178 }
179