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