7e2c706d64c2ce5cff482f35d8f426fd835572a8
[WebKit-https.git] / Source / WebCore / platform / graphics / FontFastPath.cpp
1 /**
2  * Copyright (C) 2003, 2006, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Holger Hans Peter Freyther
4  * Copyright (C) 2009 Torch Mobile, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #include "config.h"
24 #include "Font.h"
25
26 #include "FloatRect.h"
27 #include "FontCache.h"
28 #include "FontGlyphs.h"
29 #include "GlyphBuffer.h"
30 #include "LayoutRect.h"
31 #include "SimpleFontData.h"
32 #include "TextRun.h"
33 #include "WidthIterator.h"
34 #include <wtf/MainThread.h>
35 #include <wtf/MathExtras.h>
36 #include <wtf/unicode/CharacterNames.h>
37
38 using namespace WTF;
39 using namespace Unicode;
40
41 namespace WebCore {
42
43 bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const
44 {
45     return primaryFont()->glyphForCharacter(character);
46 }
47
48 // FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
49 // standard emphasis marks do so.
50 bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const
51 {
52     if (mark.isEmpty())
53         return false;
54
55     UChar32 character = mark[0];
56
57     if (U16_IS_SURROGATE(character)) {
58         if (!U16_IS_SURROGATE_LEAD(character))
59             return false;
60
61         if (mark.length() < 2)
62             return false;
63
64         UChar low = mark[1];
65         if (!U16_IS_TRAIL(low))
66             return false;
67
68         character = U16_GET_SUPPLEMENTARY(character, low);
69     }
70
71     glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant);
72     return true;
73 }
74
75 int Font::emphasisMarkAscent(const AtomicString& mark) const
76 {
77     FontCachePurgePreventer purgePreventer;
78     
79     GlyphData markGlyphData;
80     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
81         return 0;
82
83     const SimpleFontData* markFontData = markGlyphData.fontData;
84     ASSERT(markFontData);
85     if (!markFontData)
86         return 0;
87
88     return markFontData->fontMetrics().ascent();
89 }
90
91 int Font::emphasisMarkDescent(const AtomicString& mark) const
92 {
93     FontCachePurgePreventer purgePreventer;
94     
95     GlyphData markGlyphData;
96     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
97         return 0;
98
99     const SimpleFontData* markFontData = markGlyphData.fontData;
100     ASSERT(markFontData);
101     if (!markFontData)
102         return 0;
103
104     return markFontData->fontMetrics().descent();
105 }
106
107 int Font::emphasisMarkHeight(const AtomicString& mark) const
108 {
109     FontCachePurgePreventer purgePreventer;
110
111     GlyphData markGlyphData;
112     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
113         return 0;
114
115     const SimpleFontData* markFontData = markGlyphData.fontData;
116     ASSERT(markFontData);
117     if (!markFontData)
118         return 0;
119
120     return markFontData->fontMetrics().height();
121 }
122
123 float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
124 {
125     float initialAdvance;
126
127     WidthIterator it(this, run, 0, false, forTextEmphasis);
128     // FIXME: Using separate glyph buffers for the prefix and the suffix is incorrect when kerning or
129     // ligatures are enabled.
130     GlyphBuffer localGlyphBuffer;
131     it.advance(from, &localGlyphBuffer);
132     float beforeWidth = it.m_runWidthSoFar;
133     it.advance(to, &glyphBuffer);
134
135     if (glyphBuffer.isEmpty())
136         return 0;
137
138     float afterWidth = it.m_runWidthSoFar;
139
140     if (run.rtl()) {
141         float finalRoundingWidth = it.m_finalRoundingWidth;
142         it.advance(run.length(), &localGlyphBuffer);
143         initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
144     } else
145         initialAdvance = beforeWidth;
146
147     if (run.rtl())
148         glyphBuffer.reverse(0, glyphBuffer.size());
149
150     return initialAdvance;
151 }
152
153 float Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
154 {
155     // This glyph buffer holds our glyphs+advances+font data for each glyph.
156     GlyphBuffer glyphBuffer;
157
158     float startX = point.x() + getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer);
159
160     if (glyphBuffer.isEmpty())
161         return 0;
162
163     FloatPoint startPoint(startX, point.y());
164     drawGlyphBuffer(context, run, glyphBuffer, startPoint);
165
166     return startPoint.x() - startX;
167 }
168
169 void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
170 {
171     GlyphBuffer glyphBuffer;
172     float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis);
173
174     if (glyphBuffer.isEmpty())
175         return;
176
177     drawEmphasisMarks(context, run, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
178 }
179
180 void Font::drawGlyphBuffer(GraphicsContext* context, const TextRun& run, const GlyphBuffer& glyphBuffer, FloatPoint& point) const
181 {
182 #if !ENABLE(SVG_FONTS)
183     UNUSED_PARAM(run);
184 #endif
185
186     // Draw each contiguous run of glyphs that use the same font data.
187     const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
188     FloatSize offset = glyphBuffer.offsetAt(0);
189     FloatPoint startPoint(point.x(), point.y() - glyphBuffer.initialAdvance().height());
190     float nextX = startPoint.x() + glyphBuffer.advanceAt(0).width();
191     float nextY = startPoint.y() + glyphBuffer.advanceAt(0).height();
192     int lastFrom = 0;
193     int nextGlyph = 1;
194 #if ENABLE(SVG_FONTS)
195     TextRun::RenderingContext* renderingContext = run.renderingContext();
196 #endif
197     while (nextGlyph < glyphBuffer.size()) {
198         const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
199         FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
200
201         if (nextFontData != fontData || nextOffset != offset) {
202 #if ENABLE(SVG_FONTS)
203             if (renderingContext && fontData->isSVGFont())
204                 renderingContext->drawSVGGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
205             else
206 #endif
207                 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
208
209             lastFrom = nextGlyph;
210             fontData = nextFontData;
211             offset = nextOffset;
212             startPoint.setX(nextX);
213             startPoint.setY(nextY);
214         }
215         nextX += glyphBuffer.advanceAt(nextGlyph).width();
216         nextY += glyphBuffer.advanceAt(nextGlyph).height();
217         nextGlyph++;
218     }
219
220 #if ENABLE(SVG_FONTS)
221     if (renderingContext && fontData->isSVGFont())
222         renderingContext->drawSVGGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
223     else
224 #endif
225     {
226         drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
227         point.setX(nextX);
228     }
229 }
230
231 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph)
232 {
233     if (fontData->platformData().orientation() == Horizontal) {
234         FloatRect bounds = fontData->boundsForGlyph(glyph);
235         return bounds.x() + bounds.width() / 2;
236     }
237     // FIXME: Use glyph bounds once they make sense for vertical fonts.
238     return fontData->widthForGlyph(glyph) / 2;
239 }
240
241 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
242 {
243     return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i));
244 }
245
246 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
247 {
248     FontCachePurgePreventer purgePreventer;
249     
250     GlyphData markGlyphData;
251     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
252         return;
253
254     const SimpleFontData* markFontData = markGlyphData.fontData;
255     ASSERT(markFontData);
256     if (!markFontData)
257         return;
258
259     Glyph markGlyph = markGlyphData.glyph;
260     Glyph spaceGlyph = markFontData->spaceGlyph();
261
262     float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0);
263     FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
264
265     GlyphBuffer markBuffer;
266     for (int i = 0; i + 1 < glyphBuffer.size(); ++i) {
267         float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1);
268         float advance = glyphBuffer.advanceAt(i).width() - middleOfLastGlyph + middleOfNextGlyph;
269         markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
270         middleOfLastGlyph = middleOfNextGlyph;
271     }
272     markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
273
274     drawGlyphBuffer(context, run, markBuffer, startPoint);
275 }
276
277 float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
278 {
279     WidthIterator it(this, run, fallbackFonts, glyphOverflow);
280     GlyphBuffer glyphBuffer;
281     it.advance(run.length(), (typesettingFeatures() & (Kerning | Ligatures)) ? &glyphBuffer : 0);
282
283     if (glyphOverflow) {
284         glyphOverflow->top = std::max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent()));
285         glyphOverflow->bottom = std::max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent()));
286         glyphOverflow->left = ceilf(it.firstGlyphOverflow());
287         glyphOverflow->right = ceilf(it.lastGlyphOverflow());
288     }
289
290     return it.m_runWidthSoFar;
291 }
292
293 void Font::adjustSelectionRectForSimpleText(const TextRun& run, LayoutRect& selectionRect, int from, int to) const
294 {
295     GlyphBuffer glyphBuffer;
296     WidthIterator it(this, run);
297     it.advance(from, &glyphBuffer);
298     float beforeWidth = it.m_runWidthSoFar;
299     it.advance(to, &glyphBuffer);
300     float afterWidth = it.m_runWidthSoFar;
301     float totalWidth = -1;
302
303     if (run.rtl()) {
304         it.advance(run.length(), &glyphBuffer);
305         totalWidth = it.m_runWidthSoFar;
306         selectionRect.move(totalWidth - afterWidth, 0);
307     } else
308         selectionRect.move(beforeWidth, 0);
309     selectionRect.setWidth(afterWidth - beforeWidth);
310 }
311
312 int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
313 {
314     float delta = x;
315
316     WidthIterator it(this, run);
317     GlyphBuffer localGlyphBuffer;
318     unsigned offset;
319     if (run.rtl()) {
320         delta -= floatWidthForSimpleText(run);
321         while (1) {
322             offset = it.m_currentCharacter;
323             float w;
324             if (!it.advanceOneCharacter(w, localGlyphBuffer))
325                 break;
326             delta += w;
327             if (includePartialGlyphs) {
328                 if (delta - w / 2 >= 0)
329                     break;
330             } else {
331                 if (delta >= 0)
332                     break;
333             }
334         }
335     } else {
336         while (1) {
337             offset = it.m_currentCharacter;
338             float w;
339             if (!it.advanceOneCharacter(w, localGlyphBuffer))
340                 break;
341             delta -= w;
342             if (includePartialGlyphs) {
343                 if (delta + w / 2 <= 0)
344                     break;
345             } else {
346                 if (delta <= 0)
347                     break;
348             }
349         }
350     }
351
352     return offset;
353 }
354
355 }