Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(438)

Side by Side Diff: Source/core/platform/graphics/FontFastPath.cpp

Issue 99103006: Moving GraphicsContext and dependencies from core to platform. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Final patch - fixes Android Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « Source/core/platform/graphics/FontFallbackList.cpp ('k') | Source/core/platform/graphics/FontPlatformData.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698