e62df610cff7fe6b19dc0caf8658f67bac8d0b65
[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 "FontFallbackList.h"
29 #include "GlyphBuffer.h"
30 #include "GlyphPageTreeNode.h"
31 #include "SimpleFontData.h"
32 #include "TextRun.h"
33 #include "WidthIterator.h"
34 #include <wtf/MathExtras.h>
35 #include <wtf/unicode/CharacterNames.h>
36 #include <wtf/unicode/Unicode.h>
37
38 using namespace WTF;
39 using namespace Unicode;
40
41 namespace WebCore {
42
43 GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const
44 {
45     ASSERT(isMainThread());
46
47     if (variant == AutoVariant) {
48         if (m_fontDescription.smallCaps()) {
49             UChar32 upperC = toUpper(c);
50             if (upperC != c) {
51                 c = upperC;
52                 variant = SmallCapsVariant;
53             } else
54                 variant = NormalVariant;
55         } else
56             variant = NormalVariant;
57     }
58
59     if (mirror)
60         c = mirroredChar(c);
61
62     unsigned pageNumber = (c / GlyphPage::size);
63
64     GlyphPageTreeNode* node = pageNumber ? m_fontList->m_pages.get(pageNumber) : m_fontList->m_pageZero;
65     if (!node) {
66         node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
67         if (pageNumber)
68             m_fontList->m_pages.set(pageNumber, node);
69         else
70             m_fontList->m_pageZero = node;
71     }
72
73     GlyphPage* page;
74     if (variant == NormalVariant) {
75         // Fastest loop, for the common case (normal variant).
76         while (true) {
77             page = node->page();
78             if (page) {
79                 GlyphData data = page->glyphDataForCharacter(c);
80                 if (data.fontData) {
81                     if (data.fontData->platformData().orientation() == Vertical && data.fontData->orientation() == Horizontal && Font::isCJKIdeographOrSymbol(c)) {
82                         const SimpleFontData* ideographFontData = data.fontData->brokenIdeographFontData();
83                         GlyphPageTreeNode* ideographNode = GlyphPageTreeNode::getRootChild(ideographFontData, pageNumber);
84                         const GlyphPage* ideographPage = ideographNode->page();
85                         if (ideographPage) {
86                             GlyphData data = ideographPage->glyphDataForCharacter(c);
87                             if (data.fontData)
88                                 return data;
89                         }
90                         
91                         // Shouldn't be possible to even reach this point.
92                         ASSERT_NOT_REACHED();
93                     }
94                     return data;
95                 }
96
97                 if (node->isSystemFallback())
98                     break;
99             }
100
101             // Proceed with the fallback list.
102             node = node->getChild(fontDataAt(node->level()), pageNumber);
103             if (pageNumber)
104                 m_fontList->m_pages.set(pageNumber, node);
105             else
106                 m_fontList->m_pageZero = node;
107         }
108     } else {
109         while (true) {
110             page = node->page();
111             if (page) {
112                 GlyphData data = page->glyphDataForCharacter(c);
113                 if (data.fontData) {
114                     // The variantFontData function should not normally return 0.
115                     // But if it does, we will just render the capital letter big.
116                     const SimpleFontData* variantFontData = data.fontData->variantFontData(m_fontDescription, variant);
117                     if (!variantFontData)
118                         return data;
119
120                     GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData, pageNumber);
121                     const GlyphPage* variantPage = variantNode->page();
122                     if (variantPage) {
123                         GlyphData data = variantPage->glyphDataForCharacter(c);
124                         if (data.fontData)
125                             return data;
126                     }
127
128                     // Do not attempt system fallback off the variantFontData. This is the very unlikely case that
129                     // a font has the lowercase character but the small caps font does not have its uppercase version.
130                     return variantFontData->missingGlyphData();
131                 }
132
133                 if (node->isSystemFallback())
134                     break;
135             }
136
137             // Proceed with the fallback list.
138             node = node->getChild(fontDataAt(node->level()), pageNumber);
139             if (pageNumber)
140                 m_fontList->m_pages.set(pageNumber, node);
141             else
142                 m_fontList->m_pageZero = node;
143         }
144     }
145
146     ASSERT(page);
147     ASSERT(node->isSystemFallback());
148
149     // System fallback is character-dependent. When we get here, we
150     // know that the character in question isn't in the system fallback
151     // font's glyph page. Try to lazily create it here.
152     UChar codeUnits[2];
153     int codeUnitsLength;
154     if (c <= 0xFFFF) {
155         codeUnits[0] = Font::normalizeSpaces(c);
156         codeUnitsLength = 1;
157     } else {
158         codeUnits[0] = U16_LEAD(c);
159         codeUnits[1] = U16_TRAIL(c);
160         codeUnitsLength = 2;
161     }
162     const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
163     if (variant != NormalVariant && characterFontData)
164         characterFontData = characterFontData->variantFontData(m_fontDescription, variant);
165     if (characterFontData) {
166         // Got the fallback glyph and font.
167         GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
168         GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
169         // Cache it so we don't have to do system fallback again next time.
170         if (variant == NormalVariant) {
171 #if OS(WINCE)
172             // missingGlyphData returns a null character, which is not suitable for GDI to display.
173             // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
174             // display the character, probably because the font package is not installed correctly.
175             // So we just always set the glyph to be same as the character, and let GDI solve it.
176             page->setGlyphDataForCharacter(c, c, characterFontData);
177             return page->glyphDataForCharacter(c);
178 #else
179             page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
180 #endif
181         }
182         return data;
183     }
184
185     // Even system fallback can fail; use the missing glyph in that case.
186     // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
187     GlyphData data = primaryFont()->missingGlyphData();
188     if (variant == NormalVariant) {
189 #if OS(WINCE)
190         // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
191         page->setGlyphDataForCharacter(c, c, data.fontData);
192         return page->glyphDataForCharacter(c);
193 #else
194         page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
195 #endif
196     }
197     return data;
198 }
199
200 bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const
201 {
202     unsigned pageNumber = (character / GlyphPage::size);
203
204     GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber);
205     GlyphPage* page = node->page();
206
207     return page && page->fontDataForCharacter(character);
208 }
209
210 // FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
211 // standard emphasis marks do so.
212 bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const
213 {
214     if (mark.isEmpty())
215         return false;
216
217 #if ENABLE(SVG_FONTS)
218     // FIXME: Implement for SVG fonts.
219     if (primaryFont()->isSVGFont())
220         return false;
221 #endif
222
223     UChar32 character = mark[0];
224
225     if (U16_IS_SURROGATE(character)) {
226         if (!U16_IS_SURROGATE_LEAD(character))
227             return false;
228
229         if (mark.length() < 2)
230             return false;
231
232         UChar low = mark[1];
233         if (!U16_IS_TRAIL(low))
234             return false;
235
236         character = U16_GET_SUPPLEMENTARY(character, low);
237     }
238
239     glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant);
240     return true;
241 }
242
243 int Font::emphasisMarkAscent(const AtomicString& mark) const
244 {
245     GlyphData markGlyphData;
246     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
247         return 0;
248
249     const SimpleFontData* markFontData = markGlyphData.fontData;
250     ASSERT(markFontData);
251     if (!markFontData)
252         return 0;
253
254     return markFontData->fontMetrics().ascent();
255 }
256
257 int Font::emphasisMarkDescent(const AtomicString& mark) const
258 {
259     GlyphData markGlyphData;
260     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
261         return 0;
262
263     const SimpleFontData* markFontData = markGlyphData.fontData;
264     ASSERT(markFontData);
265     if (!markFontData)
266         return 0;
267
268     return markFontData->fontMetrics().descent();
269 }
270
271 int Font::emphasisMarkHeight(const AtomicString& mark) const
272 {
273     GlyphData markGlyphData;
274     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
275         return 0;
276
277     const SimpleFontData* markFontData = markGlyphData.fontData;
278     ASSERT(markFontData);
279     if (!markFontData)
280         return 0;
281
282     return markFontData->fontMetrics().height();
283 }
284
285 float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
286 {
287     float initialAdvance;
288
289     WidthIterator it(this, run, 0, false, forTextEmphasis);
290     it.advance(from);
291     float beforeWidth = it.m_runWidthSoFar;
292     it.advance(to, &glyphBuffer);
293
294     if (glyphBuffer.isEmpty())
295         return 0;
296
297     float afterWidth = it.m_runWidthSoFar;
298
299     if (run.rtl()) {
300         it.advance(run.length());
301         initialAdvance = it.m_runWidthSoFar - afterWidth;
302     } else
303         initialAdvance = beforeWidth;
304
305     if (run.rtl()) {
306         for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
307             glyphBuffer.swap(i, end);
308     }
309
310     return initialAdvance;
311 }
312
313 void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
314 {
315     // This glyph buffer holds our glyphs+advances+font data for each glyph.
316     GlyphBuffer glyphBuffer;
317
318     float startX = point.x() + getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer);
319
320     if (glyphBuffer.isEmpty())
321         return;
322
323     FloatPoint startPoint(startX, point.y());
324     drawGlyphBuffer(context, glyphBuffer, startPoint);
325 }
326
327 void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
328 {
329     GlyphBuffer glyphBuffer;
330     float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis);
331
332     if (glyphBuffer.isEmpty())
333         return;
334
335     drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
336 }
337
338 void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const
339 {   
340     // Draw each contiguous run of glyphs that use the same font data.
341     const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
342     FloatSize offset = glyphBuffer.offsetAt(0);
343     FloatPoint startPoint(point);
344     float nextX = startPoint.x();
345     int lastFrom = 0;
346     int nextGlyph = 0;
347     while (nextGlyph < glyphBuffer.size()) {
348         const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
349         FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
350         if (nextFontData != fontData || nextOffset != offset) {
351             drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
352
353             lastFrom = nextGlyph;
354             fontData = nextFontData;
355             offset = nextOffset;
356             startPoint.setX(nextX);
357         }
358         nextX += glyphBuffer.advanceAt(nextGlyph);
359         nextGlyph++;
360     }
361
362     drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
363 }
364
365 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph)
366 {
367     if (fontData->orientation() == Horizontal) {
368         FloatRect bounds = fontData->boundsForGlyph(glyph);
369         return bounds.x() + bounds.width() / 2;
370     }
371     // FIXME: Use glyph bounds once they make sense for vertical fonts.
372     return fontData->widthForGlyph(glyph) / 2;
373 }
374
375 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
376 {
377     return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i));
378 }
379
380 void Font::drawEmphasisMarks(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
381 {
382     GlyphData markGlyphData;
383     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
384         return;
385
386     const SimpleFontData* markFontData = markGlyphData.fontData;
387     ASSERT(markFontData);
388     if (!markFontData)
389         return;
390
391     Glyph markGlyph = markGlyphData.glyph;
392     Glyph spaceGlyph = markFontData->spaceGlyph();
393
394     float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0);
395     FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
396
397     GlyphBuffer markBuffer;
398     for (int i = 0; i + 1 < glyphBuffer.size(); ++i) {
399         float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1);
400         float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfNextGlyph;
401         markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
402         middleOfLastGlyph = middleOfNextGlyph;
403     }
404     markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
405
406     drawGlyphBuffer(context, markBuffer, startPoint);
407 }
408
409 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
410 {
411     WidthIterator it(this, run, fallbackFonts, glyphOverflow);
412     it.advance(run.length(), glyphBuffer);
413
414     if (glyphOverflow) {
415         glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - fontMetrics().ascent());
416         glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - fontMetrics().descent());
417         glyphOverflow->left = ceilf(it.firstGlyphOverflow());
418         glyphOverflow->right = ceilf(it.lastGlyphOverflow());
419     }
420
421     return it.m_runWidthSoFar;
422 }
423
424 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
425 {
426     WidthIterator it(this, run);
427     it.advance(from);
428     float beforeWidth = it.m_runWidthSoFar;
429     it.advance(to);
430     float afterWidth = it.m_runWidthSoFar;
431
432     // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning.
433     if (run.rtl()) {
434         it.advance(run.length());
435         float totalWidth = it.m_runWidthSoFar;
436         return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
437     }
438
439     return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
440 }
441
442 int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
443 {
444     float delta = x;
445
446     WidthIterator it(this, run);
447     GlyphBuffer localGlyphBuffer;
448     unsigned offset;
449     if (run.rtl()) {
450         delta -= floatWidthForSimpleText(run, 0);
451         while (1) {
452             offset = it.m_currentCharacter;
453             float w;
454             if (!it.advanceOneCharacter(w, &localGlyphBuffer))
455                 break;
456             delta += w;
457             if (includePartialGlyphs) {
458                 if (delta - w / 2 >= 0)
459                     break;
460             } else {
461                 if (delta >= 0)
462                     break;
463             }
464         }
465     } else {
466         while (1) {
467             offset = it.m_currentCharacter;
468             float w;
469             if (!it.advanceOneCharacter(w, &localGlyphBuffer))
470                 break;
471             delta -= w;
472             if (includePartialGlyphs) {
473                 if (delta + w / 2 <= 0)
474                     break;
475             } else {
476                 if (delta <= 0)
477                     break;
478             }
479         }
480     }
481
482     return offset;
483 }
484
485 }