Revert r170413 and r170390
[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 "GlyphPageTreeNode.h"
31 #include "LayoutRect.h"
32 #include "SimpleFontData.h"
33 #include "TextRun.h"
34 #include "WidthIterator.h"
35 #include <wtf/MainThread.h>
36 #include <wtf/MathExtras.h>
37 #include <wtf/unicode/CharacterNames.h>
38
39 using namespace WTF;
40 using namespace Unicode;
41
42 namespace WebCore {
43
44 bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const
45 {
46     unsigned pageNumber = (character / GlyphPage::size);
47
48     GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber);
49     GlyphPage* page = node->page();
50
51     return page && page->fontDataForCharacter(character);
52 }
53
54 // FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
55 // standard emphasis marks do so.
56 bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const
57 {
58     if (mark.isEmpty())
59         return false;
60
61     UChar32 character = mark[0];
62
63     if (U16_IS_SURROGATE(character)) {
64         if (!U16_IS_SURROGATE_LEAD(character))
65             return false;
66
67         if (mark.length() < 2)
68             return false;
69
70         UChar low = mark[1];
71         if (!U16_IS_TRAIL(low))
72             return false;
73
74         character = U16_GET_SUPPLEMENTARY(character, low);
75     }
76
77     glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant);
78     return true;
79 }
80
81 int Font::emphasisMarkAscent(const AtomicString& mark) const
82 {
83     FontCachePurgePreventer purgePreventer;
84     
85     GlyphData markGlyphData;
86     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
87         return 0;
88
89     const SimpleFontData* markFontData = markGlyphData.fontData;
90     ASSERT(markFontData);
91     if (!markFontData)
92         return 0;
93
94     return markFontData->fontMetrics().ascent();
95 }
96
97 int Font::emphasisMarkDescent(const AtomicString& mark) const
98 {
99     FontCachePurgePreventer purgePreventer;
100     
101     GlyphData markGlyphData;
102     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
103         return 0;
104
105     const SimpleFontData* markFontData = markGlyphData.fontData;
106     ASSERT(markFontData);
107     if (!markFontData)
108         return 0;
109
110     return markFontData->fontMetrics().descent();
111 }
112
113 int Font::emphasisMarkHeight(const AtomicString& mark) const
114 {
115     FontCachePurgePreventer purgePreventer;
116
117     GlyphData markGlyphData;
118     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
119         return 0;
120
121     const SimpleFontData* markFontData = markGlyphData.fontData;
122     ASSERT(markFontData);
123     if (!markFontData)
124         return 0;
125
126     return markFontData->fontMetrics().height();
127 }
128
129 float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
130 {
131     float initialAdvance;
132
133     WidthIterator it(this, run, 0, false, forTextEmphasis);
134     // FIXME: Using separate glyph buffers for the prefix and the suffix is incorrect when kerning or
135     // ligatures are enabled.
136     GlyphBuffer localGlyphBuffer;
137     it.advance(from, &localGlyphBuffer);
138     float beforeWidth = it.m_runWidthSoFar;
139     it.advance(to, &glyphBuffer);
140
141     if (glyphBuffer.isEmpty())
142         return 0;
143
144     float afterWidth = it.m_runWidthSoFar;
145
146     if (run.rtl()) {
147         float finalRoundingWidth = it.m_finalRoundingWidth;
148         it.advance(run.length(), &localGlyphBuffer);
149         initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
150     } else
151         initialAdvance = beforeWidth;
152
153     if (run.rtl())
154         glyphBuffer.reverse(0, glyphBuffer.size());
155
156     return initialAdvance;
157 }
158
159 float Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
160 {
161     // This glyph buffer holds our glyphs+advances+font data for each glyph.
162     GlyphBuffer glyphBuffer;
163
164     float startX = point.x() + getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer);
165
166     if (glyphBuffer.isEmpty())
167         return 0;
168
169     FloatPoint startPoint(startX, point.y());
170     drawGlyphBuffer(context, run, glyphBuffer, startPoint);
171
172     return startPoint.x() - startX;
173 }
174
175 void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
176 {
177     GlyphBuffer glyphBuffer;
178     float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis);
179
180     if (glyphBuffer.isEmpty())
181         return;
182
183     drawEmphasisMarks(context, run, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
184 }
185
186 void Font::drawGlyphBuffer(GraphicsContext* context, const TextRun& run, const GlyphBuffer& glyphBuffer, FloatPoint& point) const
187 {
188 #if !ENABLE(SVG_FONTS)
189     UNUSED_PARAM(run);
190 #endif
191
192     // Draw each contiguous run of glyphs that use the same font data.
193     const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
194     FloatSize offset = glyphBuffer.offsetAt(0);
195     FloatPoint startPoint(point.x(), point.y() - glyphBuffer.initialAdvance().height());
196     float nextX = startPoint.x() + glyphBuffer.advanceAt(0).width();
197     float nextY = startPoint.y() + glyphBuffer.advanceAt(0).height();
198     int lastFrom = 0;
199     int nextGlyph = 1;
200 #if ENABLE(SVG_FONTS)
201     TextRun::RenderingContext* renderingContext = run.renderingContext();
202 #endif
203     while (nextGlyph < glyphBuffer.size()) {
204         const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
205         FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
206
207         if (nextFontData != fontData || nextOffset != offset) {
208 #if ENABLE(SVG_FONTS)
209             if (renderingContext && fontData->isSVGFont())
210                 renderingContext->drawSVGGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
211             else
212 #endif
213                 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
214
215             lastFrom = nextGlyph;
216             fontData = nextFontData;
217             offset = nextOffset;
218             startPoint.setX(nextX);
219             startPoint.setY(nextY);
220         }
221         nextX += glyphBuffer.advanceAt(nextGlyph).width();
222         nextY += glyphBuffer.advanceAt(nextGlyph).height();
223         nextGlyph++;
224     }
225
226 #if ENABLE(SVG_FONTS)
227     if (renderingContext && fontData->isSVGFont())
228         renderingContext->drawSVGGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
229     else
230 #endif
231     {
232         drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
233         point.setX(nextX);
234     }
235 }
236
237 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph)
238 {
239     if (fontData->platformData().orientation() == Horizontal) {
240         FloatRect bounds = fontData->boundsForGlyph(glyph);
241         return bounds.x() + bounds.width() / 2;
242     }
243     // FIXME: Use glyph bounds once they make sense for vertical fonts.
244     return fontData->widthForGlyph(glyph) / 2;
245 }
246
247 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
248 {
249     return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i));
250 }
251
252 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
253 {
254     FontCachePurgePreventer purgePreventer;
255     
256     GlyphData markGlyphData;
257     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
258         return;
259
260     const SimpleFontData* markFontData = markGlyphData.fontData;
261     ASSERT(markFontData);
262     if (!markFontData)
263         return;
264
265     Glyph markGlyph = markGlyphData.glyph;
266     Glyph spaceGlyph = markFontData->spaceGlyph();
267
268     float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0);
269     FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
270
271     GlyphBuffer markBuffer;
272     for (int i = 0; i + 1 < glyphBuffer.size(); ++i) {
273         float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1);
274         float advance = glyphBuffer.advanceAt(i).width() - middleOfLastGlyph + middleOfNextGlyph;
275         markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
276         middleOfLastGlyph = middleOfNextGlyph;
277     }
278     markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
279
280     drawGlyphBuffer(context, run, markBuffer, startPoint);
281 }
282
283 float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
284 {
285     WidthIterator it(this, run, fallbackFonts, glyphOverflow);
286     GlyphBuffer glyphBuffer;
287     it.advance(run.length(), (typesettingFeatures() & (Kerning | Ligatures)) ? &glyphBuffer : 0);
288
289     if (glyphOverflow) {
290         glyphOverflow->top = std::max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent()));
291         glyphOverflow->bottom = std::max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent()));
292         glyphOverflow->left = ceilf(it.firstGlyphOverflow());
293         glyphOverflow->right = ceilf(it.lastGlyphOverflow());
294     }
295
296     return it.m_runWidthSoFar;
297 }
298
299 void Font::adjustSelectionRectForSimpleText(const TextRun& run, LayoutRect& selectionRect, int from, int to) const
300 {
301     GlyphBuffer glyphBuffer;
302     WidthIterator it(this, run);
303     it.advance(from, &glyphBuffer);
304     float beforeWidth = it.m_runWidthSoFar;
305     it.advance(to, &glyphBuffer);
306     float afterWidth = it.m_runWidthSoFar;
307     float totalWidth = -1;
308
309     if (run.rtl()) {
310         it.advance(run.length(), &glyphBuffer);
311         totalWidth = it.m_runWidthSoFar;
312         selectionRect.move(totalWidth - afterWidth, 0);
313     } else
314         selectionRect.move(beforeWidth, 0);
315     selectionRect.setWidth(afterWidth - beforeWidth);
316 }
317
318 int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
319 {
320     float delta = x;
321
322     WidthIterator it(this, run);
323     GlyphBuffer localGlyphBuffer;
324     unsigned offset;
325     if (run.rtl()) {
326         delta -= floatWidthForSimpleText(run);
327         while (1) {
328             offset = it.m_currentCharacter;
329             float w;
330             if (!it.advanceOneCharacter(w, localGlyphBuffer))
331                 break;
332             delta += w;
333             if (includePartialGlyphs) {
334                 if (delta - w / 2 >= 0)
335                     break;
336             } else {
337                 if (delta >= 0)
338                     break;
339             }
340         }
341     } else {
342         while (1) {
343             offset = it.m_currentCharacter;
344             float w;
345             if (!it.advanceOneCharacter(w, localGlyphBuffer))
346                 break;
347             delta -= w;
348             if (includePartialGlyphs) {
349                 if (delta + w / 2 <= 0)
350                     break;
351             } else {
352                 if (delta <= 0)
353                     break;
354             }
355         }
356     }
357
358     return offset;
359 }
360
361 }