• 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 "platform/fonts/Font.h"
25 
26 #include "platform/LayoutUnit.h"
27 #include "platform/fonts/FontCache.h"
28 #include "platform/fonts/FontFallbackList.h"
29 #include "platform/fonts/GlyphPageTreeNode.h"
30 #include "platform/fonts/SimpleFontData.h"
31 #include "platform/fonts/WidthIterator.h"
32 #include "platform/fonts/GlyphBuffer.h"
33 #include "platform/geometry/FloatRect.h"
34 #include "platform/text/TextRun.h"
35 #include "wtf/MainThread.h"
36 #include "wtf/MathExtras.h"
37 #include "wtf/unicode/CharacterNames.h"
38 #include "wtf/unicode/Unicode.h"
39 
40 using namespace WTF;
41 using namespace Unicode;
42 using namespace std;
43 
44 namespace WebCore {
45 
isInRange(UChar32 character,UChar32 lowerBound,UChar32 upperBound)46 static inline bool isInRange(UChar32 character, UChar32 lowerBound, UChar32 upperBound)
47 {
48     return character >= lowerBound && character <= upperBound;
49 }
50 
shouldIgnoreRotation(UChar32 character)51 static bool shouldIgnoreRotation(UChar32 character)
52 {
53     if (character == 0x000A7 || character == 0x000A9 || character == 0x000AE)
54         return true;
55 
56     if (character == 0x000B6 || character == 0x000BC || character == 0x000BD || character == 0x000BE)
57         return true;
58 
59     if (isInRange(character, 0x002E5, 0x002EB))
60         return true;
61 
62     if (isInRange(character, 0x01100, 0x011FF) || isInRange(character, 0x01401, 0x0167F) || isInRange(character, 0x01800, 0x018FF))
63         return true;
64 
65     if (character == 0x02016 || character == 0x02018 || character == 0x02019 || character == 0x02020 || character == 0x02021
66         || character == 0x2030 || character == 0x02031)
67         return true;
68 
69     if (isInRange(character, 0x0203B, 0x0203D) || character == 0x02042 || character == 0x02044 || character == 0x02047
70         || character == 0x02048 || character == 0x02049 || character == 0x2051)
71         return true;
72 
73     if (isInRange(character, 0x02065, 0x02069) || isInRange(character, 0x020DD, 0x020E0)
74         || isInRange(character, 0x020E2, 0x020E4) || isInRange(character, 0x02100, 0x02117)
75         || isInRange(character, 0x02119, 0x02131) || isInRange(character, 0x02133, 0x0213F))
76         return true;
77 
78     if (isInRange(character, 0x02145, 0x0214A) || character == 0x0214C || character == 0x0214D
79         || isInRange(character, 0x0214F, 0x0218F))
80         return true;
81 
82     if (isInRange(character, 0x02300, 0x02307) || isInRange(character, 0x0230C, 0x0231F)
83         || isInRange(character, 0x02322, 0x0232B) || isInRange(character, 0x0237D, 0x0239A)
84         || isInRange(character, 0x023B4, 0x023B6) || isInRange(character, 0x023BA, 0x023CF)
85         || isInRange(character, 0x023D1, 0x023DB) || isInRange(character, 0x023E2, 0x024FF))
86         return true;
87 
88     if (isInRange(character, 0x025A0, 0x02619) || isInRange(character, 0x02620, 0x02767)
89         || isInRange(character, 0x02776, 0x02793) || isInRange(character, 0x02B12, 0x02B2F)
90         || isInRange(character, 0x02B4D, 0x02BFF) || isInRange(character, 0x02E80, 0x03007))
91         return true;
92 
93     if (character == 0x03012 || character == 0x03013 || isInRange(character, 0x03020, 0x0302F)
94         || isInRange(character, 0x03031, 0x0309F) || isInRange(character, 0x030A1, 0x030FB)
95         || isInRange(character, 0x030FD, 0x0A4CF))
96         return true;
97 
98     if (isInRange(character, 0x0A840, 0x0A87F) || isInRange(character, 0x0A960, 0x0A97F)
99         || isInRange(character, 0x0AC00, 0x0D7FF) || isInRange(character, 0x0E000, 0x0FAFF))
100         return true;
101 
102     if (isInRange(character, 0x0FE10, 0x0FE1F) || isInRange(character, 0x0FE30, 0x0FE48)
103         || isInRange(character, 0x0FE50, 0x0FE57) || isInRange(character, 0x0FE5F, 0x0FE62)
104         || isInRange(character, 0x0FE67, 0x0FE6F))
105         return true;
106 
107     if (isInRange(character, 0x0FF01, 0x0FF07) || isInRange(character, 0x0FF0A, 0x0FF0C)
108         || isInRange(character, 0x0FF0E, 0x0FF19) ||isInRange (character, 0x0FF1F, 0x0FF3A))
109         return true;
110 
111     if (character == 0x0FF3C || character == 0x0FF3E)
112         return true;
113 
114     if (isInRange(character, 0x0FF40, 0x0FF5A) || isInRange(character, 0x0FFE0, 0x0FFE2)
115         || isInRange(character, 0x0FFE4, 0x0FFE7) || isInRange(character, 0x0FFF0, 0x0FFF8)
116         || character == 0x0FFFD)
117         return true;
118 
119     if (isInRange(character, 0x13000, 0x1342F) || isInRange(character, 0x1B000, 0x1B0FF)
120         || isInRange(character, 0x1D000, 0x1D1FF) || isInRange(character, 0x1D300, 0x1D37F)
121         || isInRange(character, 0x1F000, 0x1F64F) || isInRange(character, 0x1F680, 0x1F77F))
122         return true;
123 
124     if (isInRange(character, 0x20000, 0x2FFFD) || isInRange(character, 0x30000, 0x3FFFD))
125         return true;
126 
127     return false;
128 }
129 
glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(UChar32 character,NonCJKGlyphOrientation orientation,GlyphData & data,GlyphPage * page,unsigned pageNumber)130 static inline std::pair<GlyphData, GlyphPage*> glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(UChar32 character, NonCJKGlyphOrientation orientation, GlyphData& data, GlyphPage* page, unsigned pageNumber)
131 {
132     if (orientation == NonCJKGlyphOrientationUpright || shouldIgnoreRotation(character)) {
133         RefPtr<SimpleFontData> uprightFontData = data.fontData->uprightOrientationFontData();
134         GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getRootChild(uprightFontData.get(), pageNumber);
135         GlyphPage* uprightPage = uprightNode->page();
136         if (uprightPage) {
137             GlyphData uprightData = uprightPage->glyphDataForCharacter(character);
138             // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright.
139             if (data.glyph == uprightData.glyph)
140                 return make_pair(data, page);
141             // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that
142             // glyph, so we fall back to the upright data and use the horizontal glyph.
143             if (uprightData.fontData)
144                 return make_pair(uprightData, uprightPage);
145         }
146     } else if (orientation == NonCJKGlyphOrientationVerticalRight) {
147         RefPtr<SimpleFontData> verticalRightFontData = data.fontData->verticalRightOrientationFontData();
148         GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getRootChild(verticalRightFontData.get(), pageNumber);
149         GlyphPage* verticalRightPage = verticalRightNode->page();
150         if (verticalRightPage) {
151             GlyphData verticalRightData = verticalRightPage->glyphDataForCharacter(character);
152             // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked
153             // into it.
154             if (data.glyph != verticalRightData.glyph)
155                 return make_pair(data, page);
156             // The glyphs are identical, meaning that we should just use the horizontal glyph.
157             if (verticalRightData.fontData)
158                 return make_pair(verticalRightData, verticalRightPage);
159         }
160     }
161     return make_pair(data, page);
162 }
163 
glyphDataAndPageForCharacter(UChar32 c,bool mirror,FontDataVariant variant) const164 std::pair<GlyphData, GlyphPage*> Font::glyphDataAndPageForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const
165 {
166     ASSERT(isMainThread());
167 
168     if (variant == AutoVariant) {
169         if (m_fontDescription.smallCaps() && !primaryFont()->isSVGFont()) {
170             UChar32 upperC = toUpper(c);
171             if (upperC != c) {
172                 c = upperC;
173                 variant = SmallCapsVariant;
174             } else
175                 variant = NormalVariant;
176         } else
177             variant = NormalVariant;
178     }
179 
180     if (mirror)
181         c = mirroredChar(c);
182 
183     unsigned pageNumber = (c / GlyphPage::size);
184 
185     GlyphPageTreeNode* node = pageNumber ? m_fontFallbackList->m_pages.get(pageNumber) : m_fontFallbackList->m_pageZero;
186     if (!node) {
187         node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
188         if (pageNumber)
189             m_fontFallbackList->m_pages.set(pageNumber, node);
190         else
191             m_fontFallbackList->m_pageZero = node;
192     }
193 
194     GlyphPage* page = 0;
195     if (variant == NormalVariant) {
196         // Fastest loop, for the common case (normal variant).
197         while (true) {
198             page = node->page();
199             if (page) {
200                 GlyphData data = page->glyphDataForCharacter(c);
201                 if (data.fontData && (data.fontData->platformData().orientation() == Horizontal || data.fontData->isTextOrientationFallback()))
202                     return make_pair(data, page);
203 
204                 if (data.fontData) {
205                     if (isCJKIdeographOrSymbol(c)) {
206                         if (!data.fontData->hasVerticalGlyphs()) {
207                             // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs
208                             // to make sure you get a square (even for broken glyphs like symbols used for punctuation).
209                             variant = BrokenIdeographVariant;
210                             break;
211                         }
212                     } else
213                         return glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(c, m_fontDescription.nonCJKGlyphOrientation(), data, page, pageNumber);
214 
215                     return make_pair(data, page);
216                 }
217 
218                 if (node->isSystemFallback())
219                     break;
220             }
221 
222             // Proceed with the fallback list.
223             node = node->getChild(fontDataAt(node->level()), pageNumber);
224             if (pageNumber)
225                 m_fontFallbackList->m_pages.set(pageNumber, node);
226             else
227                 m_fontFallbackList->m_pageZero = node;
228         }
229     }
230     if (variant != NormalVariant) {
231         while (true) {
232             page = node->page();
233             if (page) {
234                 GlyphData data = page->glyphDataForCharacter(c);
235                 if (data.fontData) {
236                     // The variantFontData function should not normally return 0.
237                     // But if it does, we will just render the capital letter big.
238                     RefPtr<SimpleFontData> variantFontData = data.fontData->variantFontData(m_fontDescription, variant);
239                     if (!variantFontData)
240                         return make_pair(data, page);
241 
242                     GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData.get(), pageNumber);
243                     GlyphPage* variantPage = variantNode->page();
244                     if (variantPage) {
245                         GlyphData data = variantPage->glyphDataForCharacter(c);
246                         if (data.fontData)
247                             return make_pair(data, variantPage);
248                     }
249 
250                     // Do not attempt system fallback off the variantFontData. This is the very unlikely case that
251                     // a font has the lowercase character but the small caps font does not have its uppercase version.
252                     return make_pair(variantFontData->missingGlyphData(), page);
253                 }
254 
255                 if (node->isSystemFallback())
256                     break;
257             }
258 
259             // Proceed with the fallback list.
260             node = node->getChild(fontDataAt(node->level()), pageNumber);
261             if (pageNumber)
262                 m_fontFallbackList->m_pages.set(pageNumber, node);
263             else
264                 m_fontFallbackList->m_pageZero = node;
265         }
266     }
267 
268     ASSERT(page);
269     ASSERT(node->isSystemFallback());
270 
271     // System fallback is character-dependent. When we get here, we
272     // know that the character in question isn't in the system fallback
273     // font's glyph page. Try to lazily create it here.
274 
275     // FIXME: Unclear if this should normalizeSpaces above 0xFFFF.
276     // Doing so changes fast/text/international/plane2-diffs.html
277     UChar32 characterToRender = c;
278     if (characterToRender <=  0xFFFF)
279         characterToRender = Font::normalizeSpaces(characterToRender);
280     const SimpleFontData* fontDataToSubstitute = fontDataAt(0)->fontDataForCharacter(characterToRender);
281     RefPtr<SimpleFontData> characterFontData = FontCache::fontCache()->platformFallbackForCharacter(m_fontDescription, characterToRender, fontDataToSubstitute, isPlatformFont());
282     if (characterFontData) {
283         if (characterFontData->platformData().orientation() == Vertical && !characterFontData->hasVerticalGlyphs() && isCJKIdeographOrSymbol(c))
284             variant = BrokenIdeographVariant;
285         if (variant != NormalVariant)
286             characterFontData = characterFontData->variantFontData(m_fontDescription, variant);
287     }
288     if (characterFontData) {
289         // Got the fallback glyph and font.
290         GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData.get(), pageNumber)->page();
291         GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
292         // Cache it so we don't have to do system fallback again next time.
293         if (variant == NormalVariant) {
294             page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
295             data.fontData->setMaxGlyphPageTreeLevel(max(data.fontData->maxGlyphPageTreeLevel(), node->level()));
296             if (!isCJKIdeographOrSymbol(c) && data.fontData->platformData().orientation() != Horizontal && !data.fontData->isTextOrientationFallback())
297                 return glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(c, m_fontDescription.nonCJKGlyphOrientation(), data, fallbackPage, pageNumber);
298         }
299         return make_pair(data, page);
300     }
301 
302     // Even system fallback can fail; use the missing glyph in that case.
303     // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
304     GlyphData data = primaryFont()->missingGlyphData();
305     if (variant == NormalVariant) {
306         page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
307         data.fontData->setMaxGlyphPageTreeLevel(max(data.fontData->maxGlyphPageTreeLevel(), node->level()));
308     }
309     return make_pair(data, page);
310 }
311 
primaryFontHasGlyphForCharacter(UChar32 character) const312 bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const
313 {
314     unsigned pageNumber = (character / GlyphPage::size);
315 
316     GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber);
317     GlyphPage* page = node->page();
318 
319     return page && page->fontDataForCharacter(character);
320 }
321 
322 // FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
323 // standard emphasis marks do so.
getEmphasisMarkGlyphData(const AtomicString & mark,GlyphData & glyphData) const324 bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const
325 {
326     if (mark.isEmpty())
327         return false;
328 
329     UChar32 character = mark[0];
330 
331     if (U16_IS_SURROGATE(character)) {
332         if (!U16_IS_SURROGATE_LEAD(character))
333             return false;
334 
335         if (mark.length() < 2)
336             return false;
337 
338         UChar low = mark[1];
339         if (!U16_IS_TRAIL(low))
340             return false;
341 
342         character = U16_GET_SUPPLEMENTARY(character, low);
343     }
344 
345     glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant);
346     return true;
347 }
348 
emphasisMarkAscent(const AtomicString & mark) const349 int Font::emphasisMarkAscent(const AtomicString& mark) const
350 {
351     FontCachePurgePreventer purgePreventer;
352 
353     GlyphData markGlyphData;
354     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
355         return 0;
356 
357     const SimpleFontData* markFontData = markGlyphData.fontData;
358     ASSERT(markFontData);
359     if (!markFontData)
360         return 0;
361 
362     return markFontData->fontMetrics().ascent();
363 }
364 
emphasisMarkDescent(const AtomicString & mark) const365 int Font::emphasisMarkDescent(const AtomicString& mark) const
366 {
367     FontCachePurgePreventer purgePreventer;
368 
369     GlyphData markGlyphData;
370     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
371         return 0;
372 
373     const SimpleFontData* markFontData = markGlyphData.fontData;
374     ASSERT(markFontData);
375     if (!markFontData)
376         return 0;
377 
378     return markFontData->fontMetrics().descent();
379 }
380 
emphasisMarkHeight(const AtomicString & mark) const381 int Font::emphasisMarkHeight(const AtomicString& mark) const
382 {
383     FontCachePurgePreventer purgePreventer;
384 
385     GlyphData markGlyphData;
386     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
387         return 0;
388 
389     const SimpleFontData* markFontData = markGlyphData.fontData;
390     ASSERT(markFontData);
391     if (!markFontData)
392         return 0;
393 
394     return markFontData->fontMetrics().height();
395 }
396 
getGlyphsAndAdvancesForSimpleText(const TextRun & run,int from,int to,GlyphBuffer & glyphBuffer,ForTextEmphasisOrNot forTextEmphasis) const397 float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
398 {
399     float initialAdvance;
400 
401     WidthIterator it(this, run, 0, false, forTextEmphasis);
402     // FIXME: Using separate glyph buffers for the prefix and the suffix is incorrect when kerning or
403     // ligatures are enabled.
404     GlyphBuffer localGlyphBuffer;
405     it.advance(from, &localGlyphBuffer);
406     float beforeWidth = it.m_runWidthSoFar;
407     it.advance(to, &glyphBuffer);
408 
409     if (glyphBuffer.isEmpty())
410         return 0;
411 
412     float afterWidth = it.m_runWidthSoFar;
413 
414     if (run.rtl()) {
415         float finalRoundingWidth = it.m_finalRoundingWidth;
416         it.advance(run.length(), &localGlyphBuffer);
417         initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
418     } else
419         initialAdvance = beforeWidth;
420 
421     if (run.rtl())
422         glyphBuffer.reverse(0, glyphBuffer.size());
423 
424     return initialAdvance;
425 }
426 
drawSimpleText(GraphicsContext * context,const TextRunPaintInfo & runInfo,const FloatPoint & point) const427 void Font::drawSimpleText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const FloatPoint& point) const
428 {
429     // This glyph buffer holds our glyphs+advances+font data for each glyph.
430     GlyphBuffer glyphBuffer;
431 
432     float startX = point.x() + getGlyphsAndAdvancesForSimpleText(runInfo.run, runInfo.from, runInfo.to, glyphBuffer);
433 
434     if (glyphBuffer.isEmpty())
435         return;
436 
437     FloatPoint startPoint(startX, point.y());
438     drawGlyphBuffer(context, runInfo, glyphBuffer, startPoint);
439 }
440 
drawEmphasisMarksForSimpleText(GraphicsContext * context,const TextRunPaintInfo & runInfo,const AtomicString & mark,const FloatPoint & point) const441 void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const
442 {
443     GlyphBuffer glyphBuffer;
444     float initialAdvance = getGlyphsAndAdvancesForSimpleText(runInfo.run, runInfo.from, runInfo.to, glyphBuffer, ForTextEmphasis);
445 
446     if (glyphBuffer.isEmpty())
447         return;
448 
449     drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
450 }
451 
drawGlyphBuffer(GraphicsContext * context,const TextRunPaintInfo & runInfo,const GlyphBuffer & glyphBuffer,const FloatPoint & point) const452 void Font::drawGlyphBuffer(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const
453 {
454     // Draw each contiguous run of glyphs that use the same font data.
455     const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
456     FloatPoint startPoint(point);
457     float nextX = startPoint.x() + glyphBuffer.advanceAt(0);
458     unsigned lastFrom = 0;
459     unsigned nextGlyph = 1;
460 #if ENABLE(SVG_FONTS)
461     TextRun::RenderingContext* renderingContext = runInfo.run.renderingContext();
462 #endif
463     while (nextGlyph < glyphBuffer.size()) {
464         const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
465 
466         if (nextFontData != fontData) {
467 #if ENABLE(SVG_FONTS)
468             if (renderingContext && fontData->isSVGFont())
469                 renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
470             else
471 #endif
472                 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds);
473 
474             lastFrom = nextGlyph;
475             fontData = nextFontData;
476             startPoint.setX(nextX);
477         }
478         nextX += glyphBuffer.advanceAt(nextGlyph);
479         nextGlyph++;
480     }
481 
482 #if ENABLE(SVG_FONTS)
483     if (renderingContext && fontData->isSVGFont())
484         renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
485     else
486 #endif
487         drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds);
488 }
489 
offsetToMiddleOfGlyph(const SimpleFontData * fontData,Glyph glyph)490 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph)
491 {
492     if (fontData->platformData().orientation() == Horizontal) {
493         FloatRect bounds = fontData->boundsForGlyph(glyph);
494         return bounds.x() + bounds.width() / 2;
495     }
496     // FIXME: Use glyph bounds once they make sense for vertical fonts.
497     return fontData->widthForGlyph(glyph) / 2;
498 }
499 
offsetToMiddleOfGlyphAtIndex(const GlyphBuffer & glyphBuffer,size_t i)500 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
501 {
502     return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i));
503 }
504 
drawEmphasisMarks(GraphicsContext * context,const TextRunPaintInfo & runInfo,const GlyphBuffer & glyphBuffer,const AtomicString & mark,const FloatPoint & point) const505 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
506 {
507     FontCachePurgePreventer purgePreventer;
508 
509     GlyphData markGlyphData;
510     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
511         return;
512 
513     const SimpleFontData* markFontData = markGlyphData.fontData;
514     ASSERT(markFontData);
515     if (!markFontData)
516         return;
517 
518     Glyph markGlyph = markGlyphData.glyph;
519     Glyph spaceGlyph = markFontData->spaceGlyph();
520 
521     float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0);
522     FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
523 
524     GlyphBuffer markBuffer;
525     for (unsigned i = 0; i + 1 < glyphBuffer.size(); ++i) {
526         float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1);
527         float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfNextGlyph;
528         markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
529         middleOfLastGlyph = middleOfNextGlyph;
530     }
531     markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
532 
533     drawGlyphBuffer(context, runInfo, markBuffer, startPoint);
534 }
535 
floatWidthForSimpleText(const TextRun & run,HashSet<const SimpleFontData * > * fallbackFonts,GlyphOverflow * glyphOverflow) const536 float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
537 {
538     WidthIterator it(this, run, fallbackFonts, glyphOverflow);
539     GlyphBuffer glyphBuffer;
540     it.advance(run.length(), (typesettingFeatures() & (Kerning | Ligatures)) ? &glyphBuffer : 0);
541 
542     if (glyphOverflow) {
543         glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent()));
544         glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent()));
545         glyphOverflow->left = ceilf(it.firstGlyphOverflow());
546         glyphOverflow->right = ceilf(it.lastGlyphOverflow());
547     }
548 
549     return it.m_runWidthSoFar;
550 }
551 
selectionRectForSimpleText(const TextRun & run,const FloatPoint & point,int h,int from,int to) const552 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
553 {
554     GlyphBuffer glyphBuffer;
555     WidthIterator it(this, run);
556     it.advance(from, &glyphBuffer);
557     float beforeWidth = it.m_runWidthSoFar;
558     it.advance(to, &glyphBuffer);
559     float afterWidth = it.m_runWidthSoFar;
560 
561     // Using roundf() rather than ceilf() for the right edge as a compromise to
562     // ensure correct caret positioning.
563     // Use LayoutUnit::epsilon() to ensure that values that cannot be stored as
564     // an integer are floored to n and not n-1 due to floating point imprecision.
565     if (run.rtl()) {
566         it.advance(run.length(), &glyphBuffer);
567         float totalWidth = it.m_runWidthSoFar;
568         float pixelAlignedX = floorf(point.x() + totalWidth - afterWidth + LayoutUnit::epsilon());
569         return FloatRect(pixelAlignedX, point.y(),
570             roundf(point.x() + totalWidth - beforeWidth) - pixelAlignedX, h);
571     }
572 
573     float pixelAlignedX = floorf(point.x() + beforeWidth + LayoutUnit::epsilon());
574     return FloatRect(pixelAlignedX, point.y(),
575         roundf(point.x() + afterWidth) - pixelAlignedX, h);
576 }
577 
offsetForPositionForSimpleText(const TextRun & run,float x,bool includePartialGlyphs) const578 int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
579 {
580     float delta = x;
581 
582     WidthIterator it(this, run);
583     GlyphBuffer localGlyphBuffer;
584     unsigned offset;
585     if (run.rtl()) {
586         delta -= floatWidthForSimpleText(run);
587         while (1) {
588             offset = it.m_currentCharacter;
589             float w;
590             if (!it.advanceOneCharacter(w, localGlyphBuffer))
591                 break;
592             delta += w;
593             if (includePartialGlyphs) {
594                 if (delta - w / 2 >= 0)
595                     break;
596             } else {
597                 if (delta >= 0)
598                     break;
599             }
600         }
601     } else {
602         while (1) {
603             offset = it.m_currentCharacter;
604             float w;
605             if (!it.advanceOneCharacter(w, localGlyphBuffer))
606                 break;
607             delta -= w;
608             if (includePartialGlyphs) {
609                 if (delta + w / 2 <= 0)
610                     break;
611             } else {
612                 if (delta <= 0)
613                     break;
614             }
615         }
616     }
617 
618     return offset;
619 }
620 
621 }
622