• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
glyphDataForCharacter(UChar32 c,bool mirror,FontDataVariant variant) const43 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 && (data.fontData->platformData().orientation() == Horizontal || data.fontData->isTextOrientationFallback()))
81                     return data;
82 
83                 if (data.fontData) {
84                     if (isCJKIdeographOrSymbol(c)) {
85                         if (!data.fontData->hasVerticalGlyphs()) {
86                             // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs
87                             // to make sure you get a square (even for broken glyphs like symbols used for punctuation).
88                             const SimpleFontData* brokenIdeographFontData = data.fontData->brokenIdeographFontData();
89                             GlyphPageTreeNode* brokenIdeographNode = GlyphPageTreeNode::getRootChild(brokenIdeographFontData, pageNumber);
90                             const GlyphPage* brokenIdeographPage = brokenIdeographNode->page();
91                             if (brokenIdeographPage) {
92                                 GlyphData brokenIdeographData = brokenIdeographPage->glyphDataForCharacter(c);
93                                 if (brokenIdeographData.fontData)
94                                     return brokenIdeographData;
95                             }
96 
97                             // Shouldn't be possible to even reach this point.
98                             ASSERT_NOT_REACHED();
99                         }
100                     } else {
101                         if (m_fontDescription.textOrientation() == TextOrientationVerticalRight) {
102                             const SimpleFontData* verticalRightFontData = data.fontData->verticalRightOrientationFontData();
103                             GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getRootChild(verticalRightFontData, pageNumber);
104                             const GlyphPage* verticalRightPage = verticalRightNode->page();
105                             if (verticalRightPage) {
106                                 GlyphData verticalRightData = verticalRightPage->glyphDataForCharacter(c);
107                                 // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked
108                                 // into it.
109                                 if (data.glyph != verticalRightData.glyph)
110                                     return data;
111                                 // The glyphs are identical, meaning that we should just use the horizontal glyph.
112                                 if (verticalRightData.fontData)
113                                     return verticalRightData;
114                             }
115                         } else if (m_fontDescription.textOrientation() == TextOrientationUpright) {
116                             const SimpleFontData* uprightFontData = data.fontData->uprightOrientationFontData();
117                             GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getRootChild(uprightFontData, pageNumber);
118                             const GlyphPage* uprightPage = uprightNode->page();
119                             if (uprightPage) {
120                                 GlyphData uprightData = uprightPage->glyphDataForCharacter(c);
121                                 // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright.
122                                 if (data.glyph == uprightData.glyph)
123                                     return data;
124                                 // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that
125                                 // glyph, so we fall back to the upright data and use the horizontal glyph.
126                                 if (uprightData.fontData)
127                                     return uprightData;
128                             }
129                         }
130 
131                         // Shouldn't be possible to even reach this point.
132                         ASSERT_NOT_REACHED();
133                     }
134                     return data;
135                 }
136 
137                 if (node->isSystemFallback())
138                     break;
139             }
140 
141             // Proceed with the fallback list.
142             node = node->getChild(fontDataAt(node->level()), pageNumber);
143             if (pageNumber)
144                 m_fontList->m_pages.set(pageNumber, node);
145             else
146                 m_fontList->m_pageZero = node;
147         }
148     } else {
149         while (true) {
150             page = node->page();
151             if (page) {
152                 GlyphData data = page->glyphDataForCharacter(c);
153                 if (data.fontData) {
154                     // The variantFontData function should not normally return 0.
155                     // But if it does, we will just render the capital letter big.
156                     const SimpleFontData* variantFontData = data.fontData->variantFontData(m_fontDescription, variant);
157                     if (!variantFontData)
158                         return data;
159 
160                     GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData, pageNumber);
161                     const GlyphPage* variantPage = variantNode->page();
162                     if (variantPage) {
163                         GlyphData data = variantPage->glyphDataForCharacter(c);
164                         if (data.fontData)
165                             return data;
166                     }
167 
168                     // Do not attempt system fallback off the variantFontData. This is the very unlikely case that
169                     // a font has the lowercase character but the small caps font does not have its uppercase version.
170                     return variantFontData->missingGlyphData();
171                 }
172 
173                 if (node->isSystemFallback())
174                     break;
175             }
176 
177             // Proceed with the fallback list.
178             node = node->getChild(fontDataAt(node->level()), pageNumber);
179             if (pageNumber)
180                 m_fontList->m_pages.set(pageNumber, node);
181             else
182                 m_fontList->m_pageZero = node;
183         }
184     }
185 
186     ASSERT(page);
187     ASSERT(node->isSystemFallback());
188 
189     // System fallback is character-dependent. When we get here, we
190     // know that the character in question isn't in the system fallback
191     // font's glyph page. Try to lazily create it here.
192     UChar codeUnits[2];
193     int codeUnitsLength;
194     if (c <= 0xFFFF) {
195         codeUnits[0] = Font::normalizeSpaces(c);
196         codeUnitsLength = 1;
197     } else {
198         codeUnits[0] = U16_LEAD(c);
199         codeUnits[1] = U16_TRAIL(c);
200         codeUnitsLength = 2;
201     }
202     const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
203     if (variant != NormalVariant && characterFontData)
204         characterFontData = characterFontData->variantFontData(m_fontDescription, variant);
205     if (characterFontData) {
206         // Got the fallback glyph and font.
207         GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
208         GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
209         // Cache it so we don't have to do system fallback again next time.
210         if (variant == NormalVariant) {
211 #if OS(WINCE)
212             // missingGlyphData returns a null character, which is not suitable for GDI to display.
213             // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
214             // display the character, probably because the font package is not installed correctly.
215             // So we just always set the glyph to be same as the character, and let GDI solve it.
216             page->setGlyphDataForCharacter(c, c, characterFontData);
217             return page->glyphDataForCharacter(c);
218 #else
219             page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
220 #endif
221         }
222         return data;
223     }
224 
225     // Even system fallback can fail; use the missing glyph in that case.
226     // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
227     GlyphData data = primaryFont()->missingGlyphData();
228     if (variant == NormalVariant) {
229 #if OS(WINCE)
230         // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
231         page->setGlyphDataForCharacter(c, c, data.fontData);
232         return page->glyphDataForCharacter(c);
233 #else
234         page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
235 #endif
236     }
237     return data;
238 }
239 
primaryFontHasGlyphForCharacter(UChar32 character) const240 bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const
241 {
242     unsigned pageNumber = (character / GlyphPage::size);
243 
244     GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber);
245     GlyphPage* page = node->page();
246 
247     return page && page->fontDataForCharacter(character);
248 }
249 
250 // FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
251 // standard emphasis marks do so.
getEmphasisMarkGlyphData(const AtomicString & mark,GlyphData & glyphData) const252 bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const
253 {
254     if (mark.isEmpty())
255         return false;
256 
257 #if ENABLE(SVG_FONTS)
258     // FIXME: Implement for SVG fonts.
259     if (primaryFont()->isSVGFont())
260         return false;
261 #endif
262 
263     UChar32 character = mark[0];
264 
265     if (U16_IS_SURROGATE(character)) {
266         if (!U16_IS_SURROGATE_LEAD(character))
267             return false;
268 
269         if (mark.length() < 2)
270             return false;
271 
272         UChar low = mark[1];
273         if (!U16_IS_TRAIL(low))
274             return false;
275 
276         character = U16_GET_SUPPLEMENTARY(character, low);
277     }
278 
279     glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant);
280     return true;
281 }
282 
emphasisMarkAscent(const AtomicString & mark) const283 int Font::emphasisMarkAscent(const AtomicString& mark) const
284 {
285     GlyphData markGlyphData;
286     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
287         return 0;
288 
289     const SimpleFontData* markFontData = markGlyphData.fontData;
290     ASSERT(markFontData);
291     if (!markFontData)
292         return 0;
293 
294     return markFontData->fontMetrics().ascent();
295 }
296 
emphasisMarkDescent(const AtomicString & mark) const297 int Font::emphasisMarkDescent(const AtomicString& mark) const
298 {
299     GlyphData markGlyphData;
300     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
301         return 0;
302 
303     const SimpleFontData* markFontData = markGlyphData.fontData;
304     ASSERT(markFontData);
305     if (!markFontData)
306         return 0;
307 
308     return markFontData->fontMetrics().descent();
309 }
310 
emphasisMarkHeight(const AtomicString & mark) const311 int Font::emphasisMarkHeight(const AtomicString& mark) const
312 {
313     GlyphData markGlyphData;
314     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
315         return 0;
316 
317     const SimpleFontData* markFontData = markGlyphData.fontData;
318     ASSERT(markFontData);
319     if (!markFontData)
320         return 0;
321 
322     return markFontData->fontMetrics().height();
323 }
324 
getGlyphsAndAdvancesForSimpleText(const TextRun & run,int from,int to,GlyphBuffer & glyphBuffer,ForTextEmphasisOrNot forTextEmphasis) const325 float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
326 {
327     float initialAdvance;
328 
329     WidthIterator it(this, run, 0, false, forTextEmphasis);
330     it.advance(from);
331     float beforeWidth = it.m_runWidthSoFar;
332     it.advance(to, &glyphBuffer);
333 
334     if (glyphBuffer.isEmpty())
335         return 0;
336 
337     float afterWidth = it.m_runWidthSoFar;
338 
339     if (run.rtl()) {
340         it.advance(run.length());
341         initialAdvance = it.m_runWidthSoFar - afterWidth;
342     } else
343         initialAdvance = beforeWidth;
344 
345     if (run.rtl()) {
346         for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
347             glyphBuffer.swap(i, end);
348     }
349 
350     return initialAdvance;
351 }
352 
drawSimpleText(GraphicsContext * context,const TextRun & run,const FloatPoint & point,int from,int to) const353 void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
354 {
355     // This glyph buffer holds our glyphs+advances+font data for each glyph.
356     GlyphBuffer glyphBuffer;
357 
358     float startX = point.x() + getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer);
359 
360     if (glyphBuffer.isEmpty())
361         return;
362 
363     FloatPoint startPoint(startX, point.y());
364     drawGlyphBuffer(context, glyphBuffer, startPoint);
365 }
366 
drawEmphasisMarksForSimpleText(GraphicsContext * context,const TextRun & run,const AtomicString & mark,const FloatPoint & point,int from,int to) const367 void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
368 {
369     GlyphBuffer glyphBuffer;
370     float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis);
371 
372     if (glyphBuffer.isEmpty())
373         return;
374 
375     drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
376 }
377 
drawGlyphBuffer(GraphicsContext * context,const GlyphBuffer & glyphBuffer,const FloatPoint & point) const378 void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const
379 {
380     // Draw each contiguous run of glyphs that use the same font data.
381     const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
382     FloatSize offset = glyphBuffer.offsetAt(0);
383     FloatPoint startPoint(point);
384     float nextX = startPoint.x();
385     int lastFrom = 0;
386     int nextGlyph = 0;
387     while (nextGlyph < glyphBuffer.size()) {
388         const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
389         FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
390         if (nextFontData != fontData || nextOffset != offset) {
391             drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
392 
393             lastFrom = nextGlyph;
394             fontData = nextFontData;
395             offset = nextOffset;
396             startPoint.setX(nextX);
397         }
398         nextX += glyphBuffer.advanceAt(nextGlyph);
399         nextGlyph++;
400     }
401 
402     drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
403 }
404 
offsetToMiddleOfGlyph(const SimpleFontData * fontData,Glyph glyph)405 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph)
406 {
407     if (fontData->platformData().orientation() == Horizontal) {
408         FloatRect bounds = fontData->boundsForGlyph(glyph);
409         return bounds.x() + bounds.width() / 2;
410     }
411     // FIXME: Use glyph bounds once they make sense for vertical fonts.
412     return fontData->widthForGlyph(glyph) / 2;
413 }
414 
offsetToMiddleOfGlyphAtIndex(const GlyphBuffer & glyphBuffer,size_t i)415 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
416 {
417     return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i));
418 }
419 
drawEmphasisMarks(GraphicsContext * context,const GlyphBuffer & glyphBuffer,const AtomicString & mark,const FloatPoint & point) const420 void Font::drawEmphasisMarks(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
421 {
422     GlyphData markGlyphData;
423     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
424         return;
425 
426     const SimpleFontData* markFontData = markGlyphData.fontData;
427     ASSERT(markFontData);
428     if (!markFontData)
429         return;
430 
431     Glyph markGlyph = markGlyphData.glyph;
432     Glyph spaceGlyph = markFontData->spaceGlyph();
433 
434     float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0);
435     FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
436 
437     GlyphBuffer markBuffer;
438     for (int i = 0; i + 1 < glyphBuffer.size(); ++i) {
439         float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1);
440         float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfNextGlyph;
441         markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
442         middleOfLastGlyph = middleOfNextGlyph;
443     }
444     markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
445 
446     drawGlyphBuffer(context, markBuffer, startPoint);
447 }
448 
floatWidthForSimpleText(const TextRun & run,GlyphBuffer * glyphBuffer,HashSet<const SimpleFontData * > * fallbackFonts,GlyphOverflow * glyphOverflow) const449 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
450 {
451     WidthIterator it(this, run, fallbackFonts, glyphOverflow);
452     it.advance(run.length(), glyphBuffer);
453 
454     if (glyphOverflow) {
455         glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent()));
456         glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent()));
457         glyphOverflow->left = ceilf(it.firstGlyphOverflow());
458         glyphOverflow->right = ceilf(it.lastGlyphOverflow());
459     }
460 
461     return it.m_runWidthSoFar;
462 }
463 
selectionRectForSimpleText(const TextRun & run,const FloatPoint & point,int h,int from,int to) const464 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
465 {
466     WidthIterator it(this, run);
467     it.advance(from);
468     float beforeWidth = it.m_runWidthSoFar;
469     it.advance(to);
470     float afterWidth = it.m_runWidthSoFar;
471 
472     // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning.
473     if (run.rtl()) {
474         it.advance(run.length());
475         float totalWidth = it.m_runWidthSoFar;
476         return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
477     }
478 
479     return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
480 }
481 
offsetForPositionForSimpleText(const TextRun & run,float x,bool includePartialGlyphs) const482 int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
483 {
484     float delta = x;
485 
486     WidthIterator it(this, run);
487     GlyphBuffer localGlyphBuffer;
488     unsigned offset;
489     if (run.rtl()) {
490         delta -= floatWidthForSimpleText(run, 0);
491         while (1) {
492             offset = it.m_currentCharacter;
493             float w;
494             if (!it.advanceOneCharacter(w, &localGlyphBuffer))
495                 break;
496             delta += w;
497             if (includePartialGlyphs) {
498                 if (delta - w / 2 >= 0)
499                     break;
500             } else {
501                 if (delta >= 0)
502                     break;
503             }
504         }
505     } else {
506         while (1) {
507             offset = it.m_currentCharacter;
508             float w;
509             if (!it.advanceOneCharacter(w, &localGlyphBuffer))
510                 break;
511             delta -= w;
512             if (includePartialGlyphs) {
513                 if (delta + w / 2 <= 0)
514                     break;
515             } else {
516                 if (delta <= 0)
517                     break;
518             }
519         }
520     }
521 
522     return offset;
523 }
524 
525 }
526