OLD | NEW |
| (Empty) |
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 "core/platform/graphics/Font.h" | |
25 | |
26 #include "core/platform/graphics/FontCache.h" | |
27 #include "core/platform/graphics/FontFallbackList.h" | |
28 #include "core/platform/graphics/GlyphPageTreeNode.h" | |
29 #include "core/platform/graphics/SimpleFontData.h" | |
30 #include "core/platform/graphics/WidthIterator.h" | |
31 #include "platform/LayoutUnit.h" | |
32 #include "platform/fonts/GlyphBuffer.h" | |
33 #include "platform/geometry/FloatRect.h" | |
34 #include "platform/graphics/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 | |
46 static inline bool isInRange(UChar32 character, UChar32 lowerBound, UChar32 uppe
rBound) | |
47 { | |
48 return character >= lowerBound && character <= upperBound; | |
49 } | |
50 | |
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 || charac
ter == 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, 0x0210
0, 0x02117) | |
75 || isInRange(character, 0x02119, 0x02131) || isInRange(character, 0x0213
3, 0x0213F)) | |
76 return true; | |
77 | |
78 if (isInRange(character, 0x02145, 0x0214A) || character == 0x0214C || charac
ter == 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, 0x0237
D, 0x0239A) | |
84 || isInRange(character, 0x023B4, 0x023B6) || isInRange(character, 0x023B
A, 0x023CF) | |
85 || isInRange(character, 0x023D1, 0x023DB) || isInRange(character, 0x023E
2, 0x024FF)) | |
86 return true; | |
87 | |
88 if (isInRange(character, 0x025A0, 0x02619) || isInRange(character, 0x02620,
0x02767) | |
89 || isInRange(character, 0x02776, 0x02793) || isInRange(character, 0x02B1
2, 0x02B2F) | |
90 || isInRange(character, 0x02B4D, 0x02BFF) || isInRange(character, 0x02E8
0, 0x03007)) | |
91 return true; | |
92 | |
93 if (character == 0x03012 || character == 0x03013 || isInRange(character, 0x0
3020, 0x0302F) | |
94 || isInRange(character, 0x03031, 0x0309F) || isInRange(character, 0x030A
1, 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, 0x0E00
0, 0x0FAFF)) | |
100 return true; | |
101 | |
102 if (isInRange(character, 0x0FE10, 0x0FE1F) || isInRange(character, 0x0FE30,
0x0FE48) | |
103 || isInRange(character, 0x0FE50, 0x0FE57) || isInRange(character, 0x0FE5
F, 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, 0x0FF1
F, 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, 0x0FFF
0, 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, 0x1D30
0, 0x1D37F) | |
121 || isInRange(character, 0x1F000, 0x1F64F) || isInRange(character, 0x1F68
0, 0x1F77F)) | |
122 return true; | |
123 | |
124 if (isInRange(character, 0x20000, 0x2FFFD) || isInRange(character, 0x30000,
0x3FFFD)) | |
125 return true; | |
126 | |
127 return false; | |
128 } | |
129 | |
130 static inline std::pair<GlyphData, GlyphPage*> glyphDataAndPageForNonCJKCharacte
rWithGlyphOrientation(UChar32 character, NonCJKGlyphOrientation orientation, Gly
phData& data, GlyphPage* page, unsigned pageNumber) | |
131 { | |
132 if (orientation == NonCJKGlyphOrientationUpright || shouldIgnoreRotation(cha
racter)) { | |
133 RefPtr<SimpleFontData> uprightFontData = data.fontData->uprightOrientati
onFontData(); | |
134 GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getRootChild(upright
FontData.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 hori
zontal 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-rig
ht 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->verticalRi
ghtOrientationFontData(); | |
148 GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getRootChild(v
erticalRightFontData.get(), pageNumber); | |
149 GlyphPage* verticalRightPage = verticalRightNode->page(); | |
150 if (verticalRightPage) { | |
151 GlyphData verticalRightData = verticalRightPage->glyphDataForCharact
er(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 hor
izontal glyph. | |
157 if (verticalRightData.fontData) | |
158 return make_pair(verticalRightData, verticalRightPage); | |
159 } | |
160 } | |
161 return make_pair(data, page); | |
162 } | |
163 | |
164 std::pair<GlyphData, GlyphPage*> Font::glyphDataAndPageForCharacter(UChar32 c, b
ool 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(pageN
umber) : 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 id
eograph font will use the horizontal width of glyphs | |
208 // to make sure you get a square (even for broken gl
yphs like symbols used for punctuation). | |
209 variant = BrokenIdeographVariant; | |
210 break; | |
211 } | |
212 } else | |
213 return glyphDataAndPageForNonCJKCharacterWithGlyphOrient
ation(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 bi
g. | |
238 RefPtr<SimpleFontData> variantFontData = data.fontData->vari
antFontData(m_fontDescription, variant); | |
239 if (!variantFontData) | |
240 return make_pair(data, page); | |
241 | |
242 GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootC
hild(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. T
his is the very unlikely case that | |
251 // a font has the lowercase character but the small caps fon
t 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)->fontDataForChara
cter(characterToRender); | |
281 RefPtr<SimpleFontData> characterFontData = fontCache()->platformFallbackForC
haracter(m_fontDescription, characterToRender, fontDataToSubstitute, isPlatformF
ont()); | |
282 if (characterFontData) { | |
283 if (characterFontData->platformData().orientation() == Vertical && !char
acterFontData->hasVerticalGlyphs() && isCJKIdeographOrSymbol(c)) | |
284 variant = BrokenIdeographVariant; | |
285 if (variant != NormalVariant) | |
286 characterFontData = characterFontData->variantFontData(m_fontDescrip
tion, variant); | |
287 } | |
288 if (characterFontData) { | |
289 // Got the fallback glyph and font. | |
290 GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontD
ata.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->maxGlyphP
ageTreeLevel(), node->level())); | |
296 if (!isCJKIdeographOrSymbol(c) && data.fontData->platformData().orie
ntation() != 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 fo
nt 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->maxGlyphPageT
reeLevel(), node->level())); | |
308 } | |
309 return make_pair(data, page); | |
310 } | |
311 | |
312 bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const | |
313 { | |
314 unsigned pageNumber = (character / GlyphPage::size); | |
315 | |
316 GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pag
eNumber); | |
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. | |
324 bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphDa
ta) 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 | |
349 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 | |
365 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 | |
381 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 | |
397 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 inco
rrect 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 | |
427 void Font::drawSimpleText(GraphicsContext* context, const TextRunPaintInfo& runI
nfo, 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, ru
nInfo.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 | |
441 void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRu
nPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const | |
442 { | |
443 GlyphBuffer glyphBuffer; | |
444 float initialAdvance = getGlyphsAndAdvancesForSimpleText(runInfo.run, runInf
o.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 | |
452 void Font::drawGlyphBuffer(GraphicsContext* context, const TextRunPaintInfo& run
Info, 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, glyphBuf
fer, lastFrom, nextGlyph - lastFrom, startPoint); | |
485 else | |
486 #endif | |
487 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFro
m, startPoint, runInfo.bounds); | |
488 } | |
489 | |
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 | |
500 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer,
size_t i) | |
501 { | |
502 return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(
i)); | |
503 } | |
504 | |
505 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& r
unInfo, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoi
nt& 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 + middleOfN
extGlyph; | |
528 markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFont
Data, advance); | |
529 middleOfLastGlyph = middleOfNextGlyph; | |
530 } | |
531 markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spa
ceGlyph, markFontData, 0); | |
532 | |
533 drawGlyphBuffer(context, runInfo, markBuffer, startPoint); | |
534 } | |
535 | |
536 float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFont
Data*>* 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.minGlyphBoun
dingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent())); | |
544 glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyp
hBoundingBoxY()) - (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 | |
552 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 + Layou
tUnit::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 | |
578 int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool inclu
dePartialGlyphs) 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 } | |
OLD | NEW |