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.
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.
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.
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.
26 #include "FloatRect.h"
27 #include "FontCache.h"
28 #include "FontFallbackList.h"
29 #include "GlyphBuffer.h"
30 #include "GlyphPageTreeNode.h"
31 #include "SimpleFontData.h"
33 #include "WidthIterator.h"
34 #include <wtf/MainThread.h>
35 #include <wtf/MathExtras.h>
36 #include <wtf/unicode/CharacterNames.h>
37 #include <wtf/unicode/Unicode.h>
40 using namespace Unicode;
45 GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const
47 return glyphDataAndPageForCharacter(c, mirror, variant).first;
50 std::pair<GlyphData, GlyphPage*> Font::glyphDataAndPageForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const
52 ASSERT(isMainThread());
54 if (variant == AutoVariant) {
55 if (m_fontDescription.smallCaps() && !primaryFont()->isSVGFont()) {
56 UChar32 upperC = toUpper(c);
59 variant = SmallCapsVariant;
61 variant = NormalVariant;
63 variant = NormalVariant;
69 unsigned pageNumber = (c / GlyphPage::size);
71 GlyphPageTreeNode* node = pageNumber ? m_fontList->m_pages.get(pageNumber) : m_fontList->m_pageZero;
73 node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
75 m_fontList->m_pages.set(pageNumber, node);
77 m_fontList->m_pageZero = node;
81 if (variant == NormalVariant) {
82 // Fastest loop, for the common case (normal variant).
86 GlyphData data = page->glyphDataForCharacter(c);
87 if (data.fontData && (data.fontData->platformData().orientation() == Horizontal || data.fontData->isTextOrientationFallback()))
88 return make_pair(data, page);
91 if (isCJKIdeographOrSymbol(c)) {
92 if (!data.fontData->hasVerticalGlyphs()) {
93 // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs
94 // to make sure you get a square (even for broken glyphs like symbols used for punctuation).
95 variant = BrokenIdeographVariant;
99 if (m_fontDescription.textOrientation() == TextOrientationVerticalRight) {
100 const SimpleFontData* verticalRightFontData = data.fontData->verticalRightOrientationFontData();
101 GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getRootChild(verticalRightFontData, pageNumber);
102 GlyphPage* verticalRightPage = verticalRightNode->page();
103 if (verticalRightPage) {
104 GlyphData verticalRightData = verticalRightPage->glyphDataForCharacter(c);
105 // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked
107 if (data.glyph != verticalRightData.glyph)
108 return make_pair(data, page);
109 // The glyphs are identical, meaning that we should just use the horizontal glyph.
110 if (verticalRightData.fontData)
111 return make_pair(verticalRightData, verticalRightPage);
113 } else if (m_fontDescription.textOrientation() == TextOrientationUpright) {
114 const SimpleFontData* uprightFontData = data.fontData->uprightOrientationFontData();
115 GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getRootChild(uprightFontData, pageNumber);
116 GlyphPage* uprightPage = uprightNode->page();
118 GlyphData uprightData = uprightPage->glyphDataForCharacter(c);
119 // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright.
120 if (data.glyph == uprightData.glyph)
121 return make_pair(data, page);
122 // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that
123 // glyph, so we fall back to the upright data and use the horizontal glyph.
124 if (uprightData.fontData)
125 return make_pair(uprightData, uprightPage);
129 // Shouldn't be possible to even reach this point.
130 ASSERT_NOT_REACHED();
132 return make_pair(data, page);
135 if (node->isSystemFallback())
139 // Proceed with the fallback list.
140 node = node->getChild(fontDataAt(node->level()), pageNumber);
142 m_fontList->m_pages.set(pageNumber, node);
144 m_fontList->m_pageZero = node;
147 if (variant != NormalVariant) {
151 GlyphData data = page->glyphDataForCharacter(c);
153 // The variantFontData function should not normally return 0.
154 // But if it does, we will just render the capital letter big.
155 const SimpleFontData* variantFontData = data.fontData->variantFontData(m_fontDescription, variant);
156 if (!variantFontData)
157 return make_pair(data, page);
159 GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData, pageNumber);
160 GlyphPage* variantPage = variantNode->page();
162 GlyphData data = variantPage->glyphDataForCharacter(c);
164 return make_pair(data, variantPage);
167 // Do not attempt system fallback off the variantFontData. This is the very unlikely case that
168 // a font has the lowercase character but the small caps font does not have its uppercase version.
169 return make_pair(variantFontData->missingGlyphData(), page);
172 if (node->isSystemFallback())
176 // Proceed with the fallback list.
177 node = node->getChild(fontDataAt(node->level()), pageNumber);
179 m_fontList->m_pages.set(pageNumber, node);
181 m_fontList->m_pageZero = node;
186 ASSERT(node->isSystemFallback());
188 // System fallback is character-dependent. When we get here, we
189 // know that the character in question isn't in the system fallback
190 // font's glyph page. Try to lazily create it here.
194 codeUnits[0] = Font::normalizeSpaces(c);
197 codeUnits[0] = U16_LEAD(c);
198 codeUnits[1] = U16_TRAIL(c);
201 const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
202 if (characterFontData) {
203 if (characterFontData->platformData().orientation() == Vertical && !characterFontData->hasVerticalGlyphs() && isCJKIdeographOrSymbol(c))
204 variant = BrokenIdeographVariant;
205 if (variant != NormalVariant)
206 characterFontData = characterFontData->variantFontData(m_fontDescription, variant);
208 if (characterFontData) {
209 // Got the fallback glyph and font.
210 GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
211 GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
212 // Cache it so we don't have to do system fallback again next time.
213 if (variant == NormalVariant) {
215 // missingGlyphData returns a null character, which is not suitable for GDI to display.
216 // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
217 // display the character, probably because the font package is not installed correctly.
218 // So we just always set the glyph to be same as the character, and let GDI solve it.
219 page->setGlyphDataForCharacter(c, c, characterFontData);
220 characterFontData->setMaxGlyphPageTreeLevel(max(characterFontData->maxGlyphPageTreeLevel(), node->level()));
221 return make_pair(page->glyphDataForCharacter(c), page);
223 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
224 data.fontData->setMaxGlyphPageTreeLevel(max(data.fontData->maxGlyphPageTreeLevel(), node->level()));
227 return make_pair(data, page);
230 // Even system fallback can fail; use the missing glyph in that case.
231 // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
232 GlyphData data = primaryFont()->missingGlyphData();
233 if (variant == NormalVariant) {
235 // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
236 page->setGlyphDataForCharacter(c, c, data.fontData);
237 data.fontData->setMaxGlyphPageTreeLevel(max(data.fontData->maxGlyphPageTreeLevel(), node->level()));
238 return make_pair(page->glyphDataForCharacter(c), page);
240 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
241 data.fontData->setMaxGlyphPageTreeLevel(max(data.fontData->maxGlyphPageTreeLevel(), node->level()));
244 return make_pair(data, page);
247 bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const
249 unsigned pageNumber = (character / GlyphPage::size);
251 GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber);
252 GlyphPage* page = node->page();
254 return page && page->fontDataForCharacter(character);
257 // FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
258 // standard emphasis marks do so.
259 bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const
264 UChar32 character = mark[0];
266 if (U16_IS_SURROGATE(character)) {
267 if (!U16_IS_SURROGATE_LEAD(character))
270 if (mark.length() < 2)
274 if (!U16_IS_TRAIL(low))
277 character = U16_GET_SUPPLEMENTARY(character, low);
280 glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant);
284 int Font::emphasisMarkAscent(const AtomicString& mark) const
286 GlyphData markGlyphData;
287 if (!getEmphasisMarkGlyphData(mark, markGlyphData))
290 const SimpleFontData* markFontData = markGlyphData.fontData;
291 ASSERT(markFontData);
295 return markFontData->fontMetrics().ascent();
298 int Font::emphasisMarkDescent(const AtomicString& mark) const
300 GlyphData markGlyphData;
301 if (!getEmphasisMarkGlyphData(mark, markGlyphData))
304 const SimpleFontData* markFontData = markGlyphData.fontData;
305 ASSERT(markFontData);
309 return markFontData->fontMetrics().descent();
312 int Font::emphasisMarkHeight(const AtomicString& mark) const
314 GlyphData markGlyphData;
315 if (!getEmphasisMarkGlyphData(mark, markGlyphData))
318 const SimpleFontData* markFontData = markGlyphData.fontData;
319 ASSERT(markFontData);
323 return markFontData->fontMetrics().height();
326 float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
328 float initialAdvance;
330 WidthIterator it(this, run, 0, false, forTextEmphasis);
332 float beforeWidth = it.m_runWidthSoFar;
333 it.advance(to, &glyphBuffer);
335 if (glyphBuffer.isEmpty())
338 float afterWidth = it.m_runWidthSoFar;
341 float finalRoundingWidth = it.m_finalRoundingWidth;
342 it.advance(run.length());
343 initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
345 initialAdvance = beforeWidth;
348 for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
349 glyphBuffer.swap(i, end);
352 return initialAdvance;
355 void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
357 // This glyph buffer holds our glyphs+advances+font data for each glyph.
358 GlyphBuffer glyphBuffer;
360 float startX = point.x() + getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer);
362 if (glyphBuffer.isEmpty())
365 FloatPoint startPoint(startX, point.y());
366 drawGlyphBuffer(context, run, glyphBuffer, startPoint);
369 void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
371 GlyphBuffer glyphBuffer;
372 float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis);
374 if (glyphBuffer.isEmpty())
377 drawEmphasisMarks(context, run, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
380 void Font::drawGlyphBuffer(GraphicsContext* context, const TextRun& run, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const
382 #if !ENABLE(SVG_FONTS)
386 // Draw each contiguous run of glyphs that use the same font data.
387 const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
388 FloatSize offset = glyphBuffer.offsetAt(0);
389 FloatPoint startPoint(point);
390 float nextX = startPoint.x() + glyphBuffer.advanceAt(0);
393 #if ENABLE(SVG_FONTS)
394 TextRun::RenderingContext* renderingContext = run.renderingContext();
396 while (nextGlyph < glyphBuffer.size()) {
397 const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
398 FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
400 if (nextFontData != fontData || nextOffset != offset) {
401 #if ENABLE(SVG_FONTS)
402 if (renderingContext && fontData->isSVGFont())
403 renderingContext->drawSVGGlyphs(context, run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
406 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
408 lastFrom = nextGlyph;
409 fontData = nextFontData;
411 startPoint.setX(nextX);
413 nextX += glyphBuffer.advanceAt(nextGlyph);
417 #if ENABLE(SVG_FONTS)
418 if (renderingContext && fontData->isSVGFont())
419 renderingContext->drawSVGGlyphs(context, run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
422 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
425 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph)
427 if (fontData->platformData().orientation() == Horizontal) {
428 FloatRect bounds = fontData->boundsForGlyph(glyph);
429 return bounds.x() + bounds.width() / 2;
431 // FIXME: Use glyph bounds once they make sense for vertical fonts.
432 return fontData->widthForGlyph(glyph) / 2;
435 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
437 return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i));
440 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
442 GlyphData markGlyphData;
443 if (!getEmphasisMarkGlyphData(mark, markGlyphData))
446 const SimpleFontData* markFontData = markGlyphData.fontData;
447 ASSERT(markFontData);
451 Glyph markGlyph = markGlyphData.glyph;
452 Glyph spaceGlyph = markFontData->spaceGlyph();
454 float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0);
455 FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
457 GlyphBuffer markBuffer;
458 for (int i = 0; i + 1 < glyphBuffer.size(); ++i) {
459 float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1);
460 float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfNextGlyph;
461 markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
462 middleOfLastGlyph = middleOfNextGlyph;
464 markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
466 drawGlyphBuffer(context, run, markBuffer, startPoint);
469 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
471 WidthIterator it(this, run, fallbackFonts, glyphOverflow);
472 it.advance(run.length(), glyphBuffer);
475 glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent()));
476 glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent()));
477 glyphOverflow->left = ceilf(it.firstGlyphOverflow());
478 glyphOverflow->right = ceilf(it.lastGlyphOverflow());
481 return it.m_runWidthSoFar;
484 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
486 WidthIterator it(this, run);
488 float beforeWidth = it.m_runWidthSoFar;
490 float afterWidth = it.m_runWidthSoFar;
492 // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning.
494 it.advance(run.length());
495 float totalWidth = it.m_runWidthSoFar;
496 return FloatRect(floorf(point.x() + totalWidth - afterWidth), point.y(), roundf(point.x() + totalWidth - beforeWidth) - floorf(point.x() + totalWidth - afterWidth), h);
499 return FloatRect(floorf(point.x() + beforeWidth), point.y(), roundf(point.x() + afterWidth) - floorf(point.x() + beforeWidth), h);
502 int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
506 WidthIterator it(this, run);
507 GlyphBuffer localGlyphBuffer;
510 delta -= floatWidthForSimpleText(run, 0);
512 offset = it.m_currentCharacter;
514 if (!it.advanceOneCharacter(w, &localGlyphBuffer))
517 if (includePartialGlyphs) {
518 if (delta - w / 2 >= 0)
527 offset = it.m_currentCharacter;
529 if (!it.advanceOneCharacter(w, &localGlyphBuffer))
532 if (includePartialGlyphs) {
533 if (delta + w / 2 <= 0)