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/MathExtras.h>
35 #include <wtf/unicode/CharacterNames.h>
36 #include <wtf/unicode/Unicode.h>
39 using namespace Unicode;
43 GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const
45 ASSERT(isMainThread());
47 if (variant == AutoVariant) {
48 if (m_fontDescription.smallCaps()) {
49 UChar32 upperC = toUpper(c);
52 variant = SmallCapsVariant;
54 variant = NormalVariant;
56 variant = NormalVariant;
62 unsigned pageNumber = (c / GlyphPage::size);
64 GlyphPageTreeNode* node = pageNumber ? m_fontList->m_pages.get(pageNumber) : m_fontList->m_pageZero;
66 node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
68 m_fontList->m_pages.set(pageNumber, node);
70 m_fontList->m_pageZero = node;
74 if (variant == NormalVariant) {
75 // Fastest loop, for the common case (normal variant).
79 GlyphData data = page->glyphDataForCharacter(c);
80 if (data.fontData && (data.fontData->platformData().orientation() == Horizontal || data.fontData->isTextOrientationFallback()))
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;
97 // Shouldn't be possible to even reach this point.
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
109 if (data.glyph != verticalRightData.glyph)
111 // The glyphs are identical, meaning that we should just use the horizontal glyph.
112 if (verticalRightData.fontData)
113 return verticalRightData;
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();
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)
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)
131 // Shouldn't be possible to even reach this point.
132 ASSERT_NOT_REACHED();
137 if (node->isSystemFallback())
141 // Proceed with the fallback list.
142 node = node->getChild(fontDataAt(node->level()), pageNumber);
144 m_fontList->m_pages.set(pageNumber, node);
146 m_fontList->m_pageZero = node;
152 GlyphData data = page->glyphDataForCharacter(c);
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)
160 GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData, pageNumber);
161 const GlyphPage* variantPage = variantNode->page();
163 GlyphData data = variantPage->glyphDataForCharacter(c);
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();
173 if (node->isSystemFallback())
177 // Proceed with the fallback list.
178 node = node->getChild(fontDataAt(node->level()), pageNumber);
180 m_fontList->m_pages.set(pageNumber, node);
182 m_fontList->m_pageZero = node;
187 ASSERT(node->isSystemFallback());
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.
195 codeUnits[0] = Font::normalizeSpaces(c);
198 codeUnits[0] = U16_LEAD(c);
199 codeUnits[1] = U16_TRAIL(c);
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) {
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);
219 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
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) {
230 // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
231 page->setGlyphDataForCharacter(c, c, data.fontData);
232 return page->glyphDataForCharacter(c);
234 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
240 bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const
242 unsigned pageNumber = (character / GlyphPage::size);
244 GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber);
245 GlyphPage* page = node->page();
247 return page && page->fontDataForCharacter(character);
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.
252 bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const
257 #if ENABLE(SVG_FONTS)
258 // FIXME: Implement for SVG fonts.
259 if (primaryFont()->isSVGFont())
263 UChar32 character = mark[0];
265 if (U16_IS_SURROGATE(character)) {
266 if (!U16_IS_SURROGATE_LEAD(character))
269 if (mark.length() < 2)
273 if (!U16_IS_TRAIL(low))
276 character = U16_GET_SUPPLEMENTARY(character, low);
279 glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant);
283 int Font::emphasisMarkAscent(const AtomicString& mark) const
285 GlyphData markGlyphData;
286 if (!getEmphasisMarkGlyphData(mark, markGlyphData))
289 const SimpleFontData* markFontData = markGlyphData.fontData;
290 ASSERT(markFontData);
294 return markFontData->fontMetrics().ascent();
297 int Font::emphasisMarkDescent(const AtomicString& mark) const
299 GlyphData markGlyphData;
300 if (!getEmphasisMarkGlyphData(mark, markGlyphData))
303 const SimpleFontData* markFontData = markGlyphData.fontData;
304 ASSERT(markFontData);
308 return markFontData->fontMetrics().descent();
311 int Font::emphasisMarkHeight(const AtomicString& mark) const
313 GlyphData markGlyphData;
314 if (!getEmphasisMarkGlyphData(mark, markGlyphData))
317 const SimpleFontData* markFontData = markGlyphData.fontData;
318 ASSERT(markFontData);
322 return markFontData->fontMetrics().height();
325 float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
327 float initialAdvance;
329 WidthIterator it(this, run, 0, false, forTextEmphasis);
331 float beforeWidth = it.m_runWidthSoFar;
332 it.advance(to, &glyphBuffer);
334 if (glyphBuffer.isEmpty())
337 float afterWidth = it.m_runWidthSoFar;
340 it.advance(run.length());
341 initialAdvance = it.m_runWidthSoFar - afterWidth;
343 initialAdvance = beforeWidth;
346 for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
347 glyphBuffer.swap(i, end);
350 return initialAdvance;
353 void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
355 // This glyph buffer holds our glyphs+advances+font data for each glyph.
356 GlyphBuffer glyphBuffer;
358 float startX = point.x() + getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer);
360 if (glyphBuffer.isEmpty())
363 FloatPoint startPoint(startX, point.y());
364 drawGlyphBuffer(context, glyphBuffer, startPoint);
367 void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
369 GlyphBuffer glyphBuffer;
370 float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis);
372 if (glyphBuffer.isEmpty())
375 drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
378 void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const
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();
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);
393 lastFrom = nextGlyph;
394 fontData = nextFontData;
396 startPoint.setX(nextX);
398 nextX += glyphBuffer.advanceAt(nextGlyph);
402 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
405 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph)
407 if (fontData->platformData().orientation() == Horizontal) {
408 FloatRect bounds = fontData->boundsForGlyph(glyph);
409 return bounds.x() + bounds.width() / 2;
411 // FIXME: Use glyph bounds once they make sense for vertical fonts.
412 return fontData->widthForGlyph(glyph) / 2;
415 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
417 return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i));
420 void Font::drawEmphasisMarks(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
422 GlyphData markGlyphData;
423 if (!getEmphasisMarkGlyphData(mark, markGlyphData))
426 const SimpleFontData* markFontData = markGlyphData.fontData;
427 ASSERT(markFontData);
431 Glyph markGlyph = markGlyphData.glyph;
432 Glyph spaceGlyph = markFontData->spaceGlyph();
434 float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0);
435 FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
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;
444 markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
446 drawGlyphBuffer(context, markBuffer, startPoint);
449 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
451 WidthIterator it(this, run, fallbackFonts, glyphOverflow);
452 it.advance(run.length(), glyphBuffer);
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());
461 return it.m_runWidthSoFar;
464 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
466 WidthIterator it(this, run);
468 float beforeWidth = it.m_runWidthSoFar;
470 float afterWidth = it.m_runWidthSoFar;
472 // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning.
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);
479 return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
482 int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
486 WidthIterator it(this, run);
487 GlyphBuffer localGlyphBuffer;
490 delta -= floatWidthForSimpleText(run, 0);
492 offset = it.m_currentCharacter;
494 if (!it.advanceOneCharacter(w, &localGlyphBuffer))
497 if (includePartialGlyphs) {
498 if (delta - w / 2 >= 0)
507 offset = it.m_currentCharacter;
509 if (!it.advanceOneCharacter(w, &localGlyphBuffer))
512 if (includePartialGlyphs) {
513 if (delta + w / 2 <= 0)