Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / platform / fonts / Font.cpp
blobaa087069dcd1202865b9e157dacb175a2be0e576
1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2000 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved.
6 * Copyright (c) 2007, 2008, 2010 Google Inc. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
25 #include "config.h"
26 #include "platform/fonts/Font.h"
28 #include "platform/LayoutUnit.h"
29 #include "platform/RuntimeEnabledFeatures.h"
30 #include "platform/fonts/Character.h"
31 #include "platform/fonts/FontCache.h"
32 #include "platform/fonts/FontFallbackList.h"
33 #include "platform/fonts/GlyphBuffer.h"
34 #include "platform/fonts/GlyphPageTreeNode.h"
35 #include "platform/fonts/SimpleFontData.h"
36 #include "platform/fonts/shaping/HarfBuzzFace.h"
37 #include "platform/fonts/shaping/HarfBuzzShaper.h"
38 #include "platform/fonts/shaping/SimpleShaper.h"
39 #include "platform/geometry/FloatRect.h"
40 #include "platform/graphics/skia/SkiaUtils.h"
41 #include "platform/text/BidiResolver.h"
42 #include "platform/text/TextRun.h"
43 #include "platform/text/TextRunIterator.h"
44 #include "platform/transforms/AffineTransform.h"
45 #include "third_party/skia/include/core/SkCanvas.h"
46 #include "third_party/skia/include/core/SkPaint.h"
47 #include "wtf/MainThread.h"
48 #include "wtf/StdLibExtras.h"
49 #include "wtf/text/CharacterNames.h"
50 #include "wtf/text/Unicode.h"
52 using namespace WTF;
53 using namespace Unicode;
55 namespace blink {
57 Font::Font()
61 Font::Font(const FontDescription& fd)
62 : m_fontDescription(fd)
63 , m_canShapeWordByWord(0)
64 , m_shapeWordByWordComputed(0)
68 Font::Font(const Font& other)
69 : m_fontDescription(other.m_fontDescription)
70 , m_fontFallbackList(other.m_fontFallbackList)
71 , m_canShapeWordByWord(0)
72 , m_shapeWordByWordComputed(0)
76 Font& Font::operator=(const Font& other)
78 m_fontDescription = other.m_fontDescription;
79 m_fontFallbackList = other.m_fontFallbackList;
80 m_canShapeWordByWord = other.m_canShapeWordByWord;
81 m_shapeWordByWordComputed = other.m_shapeWordByWordComputed;
82 return *this;
85 bool Font::operator==(const Font& other) const
87 FontSelector* first = m_fontFallbackList ? m_fontFallbackList->fontSelector() : 0;
88 FontSelector* second = other.m_fontFallbackList ? other.m_fontFallbackList->fontSelector() : 0;
90 return first == second
91 && m_fontDescription == other.m_fontDescription
92 && (m_fontFallbackList ? m_fontFallbackList->fontSelectorVersion() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->fontSelectorVersion() : 0)
93 && (m_fontFallbackList ? m_fontFallbackList->generation() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->generation() : 0);
96 void Font::update(PassRefPtrWillBeRawPtr<FontSelector> fontSelector) const
98 // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up
99 // being reasonably safe (because inherited fonts in the render tree pick up the new
100 // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and
101 // won't stick around long enough to get you in trouble). Still, this is pretty disgusting,
102 // and could eventually be rectified by using RefPtrs for Fonts themselves.
103 if (!m_fontFallbackList)
104 m_fontFallbackList = FontFallbackList::create();
105 m_fontFallbackList->invalidate(fontSelector);
108 float Font::buildGlyphBuffer(const TextRunPaintInfo& runInfo, GlyphBuffer& glyphBuffer,
109 const GlyphData* emphasisData) const
111 if (codePath(runInfo) == ComplexPath) {
112 float width;
113 CachingWordShaper& shaper = m_fontFallbackList->cachingWordShaper();
114 if (emphasisData) {
115 width = shaper.fillGlyphBufferForTextEmphasis(this, runInfo.run,
116 emphasisData, &glyphBuffer, runInfo.from, runInfo.to);
117 } else {
118 width = shaper.fillGlyphBuffer(this, runInfo.run, nullptr,
119 &glyphBuffer, runInfo.from, runInfo.to);
122 return width;
125 SimpleShaper shaper(this, runInfo.run, emphasisData, nullptr /* fallbackFonts */, nullptr);
126 shaper.advance(runInfo.from);
127 shaper.advance(runInfo.to, &glyphBuffer);
128 float width = shaper.runWidthSoFar();
130 if (runInfo.run.rtl()) {
131 // Glyphs are shaped & stored in RTL advance order - reverse them for LTR drawing.
132 shaper.advance(runInfo.run.length());
133 glyphBuffer.reverseForSimpleRTL(width, shaper.runWidthSoFar());
136 return width;
139 void Font::drawText(SkCanvas* canvas, const TextRunPaintInfo& runInfo,
140 const FloatPoint& point, float deviceScaleFactor, const SkPaint& paint) const
142 // Don't draw anything while we are using custom fonts that are in the process of loading.
143 if (shouldSkipDrawing())
144 return;
146 if (runInfo.cachedTextBlob && runInfo.cachedTextBlob->get()) {
147 // we have a pre-cached blob -- happy joy!
148 drawTextBlob(canvas, paint, runInfo.cachedTextBlob->get(), point.data());
149 return;
152 GlyphBuffer glyphBuffer;
153 buildGlyphBuffer(runInfo, glyphBuffer);
155 drawGlyphBuffer(canvas, paint, runInfo, glyphBuffer, point, deviceScaleFactor);
158 void Font::drawBidiText(SkCanvas* canvas, const TextRunPaintInfo& runInfo, const FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction, float deviceScaleFactor, const SkPaint& paint) const
160 // Don't draw anything while we are using custom fonts that are in the process of loading,
161 // except if the 'force' argument is set to true (in which case it will use a fallback
162 // font).
163 if (shouldSkipDrawing() && customFontNotReadyAction == DoNotPaintIfFontNotReady)
164 return;
166 // sub-run painting is not supported for Bidi text.
167 const TextRun& run = runInfo.run;
168 ASSERT((runInfo.from == 0) && (runInfo.to == run.length()));
169 BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
170 bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride()));
171 bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0));
173 // FIXME: This ownership should be reversed. We should pass BidiRunList
174 // to BidiResolver in createBidiRunsForLine.
175 BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
176 bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));
177 if (!bidiRuns.runCount())
178 return;
180 FloatPoint currPoint = point;
181 BidiCharacterRun* bidiRun = bidiRuns.firstRun();
182 while (bidiRun) {
183 TextRun subrun = run.subRun(bidiRun->start(), bidiRun->stop() - bidiRun->start());
184 bool isRTL = bidiRun->level() % 2;
185 subrun.setDirection(isRTL ? RTL : LTR);
186 subrun.setDirectionalOverride(bidiRun->dirOverride(false));
188 TextRunPaintInfo subrunInfo(subrun);
189 subrunInfo.bounds = runInfo.bounds;
191 // TODO: investigate blob consolidation/caching (technically,
192 // all subruns could be part of the same blob).
193 GlyphBuffer glyphBuffer;
194 float runWidth = buildGlyphBuffer(subrunInfo, glyphBuffer);
195 drawGlyphBuffer(canvas, paint, subrunInfo, glyphBuffer, currPoint, deviceScaleFactor);
197 bidiRun = bidiRun->next();
198 currPoint.move(runWidth, 0);
201 bidiRuns.deleteRuns();
204 void Font::drawEmphasisMarks(SkCanvas* canvas, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point, float deviceScaleFactor, const SkPaint& paint) const
206 if (shouldSkipDrawing())
207 return;
209 FontCachePurgePreventer purgePreventer;
211 GlyphData emphasisGlyphData;
212 if (!getEmphasisMarkGlyphData(mark, emphasisGlyphData))
213 return;
215 ASSERT(emphasisGlyphData.fontData);
216 if (!emphasisGlyphData.fontData)
217 return;
219 GlyphBuffer glyphBuffer;
220 buildGlyphBuffer(runInfo, glyphBuffer, &emphasisGlyphData);
222 if (glyphBuffer.isEmpty())
223 return;
225 drawGlyphBuffer(canvas, paint, runInfo, glyphBuffer, point, deviceScaleFactor);
228 float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* glyphBounds) const
230 FontCachePurgePreventer purgePreventer;
232 if (codePath(TextRunPaintInfo(run)) == ComplexPath)
233 return floatWidthForComplexText(run, fallbackFonts, glyphBounds);
234 return floatWidthForSimpleText(run, fallbackFonts, glyphBounds);
237 PassTextBlobPtr Font::buildTextBlob(const GlyphBuffer& glyphBuffer) const
239 SkTextBlobBuilder builder;
240 bool hasVerticalOffsets = glyphBuffer.hasVerticalOffsets();
242 unsigned i = 0;
243 while (i < glyphBuffer.size()) {
244 const SimpleFontData* fontData = glyphBuffer.fontDataAt(i);
246 // FIXME: Handle vertical text.
247 if (fontData->platformData().isVerticalAnyUpright())
248 return nullptr;
250 SkPaint paint;
251 // FIXME: FontPlatformData makes some decisions on the device scale
252 // factor, which is found via the GraphicsContext. This should be fixed
253 // to avoid correctness problems here.
254 float deviceScaleFactor = 1.0f;
255 fontData->platformData().setupPaint(&paint, deviceScaleFactor, this);
256 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
258 unsigned start = i++;
259 while (i < glyphBuffer.size() && glyphBuffer.fontDataAt(i) == fontData)
260 i++;
261 unsigned count = i - start;
263 const SkTextBlobBuilder::RunBuffer& buffer = hasVerticalOffsets
264 ? builder.allocRunPos(paint, count)
265 : builder.allocRunPosH(paint, count, 0);
267 const uint16_t* glyphs = glyphBuffer.glyphs(start);
268 const float* offsets = glyphBuffer.offsets(start);
269 std::copy(glyphs, glyphs + count, buffer.glyphs);
270 std::copy(offsets, offsets + (hasVerticalOffsets ? 2 * count : count), buffer.pos);
273 return adoptRef(builder.build());
276 static inline FloatRect pixelSnappedSelectionRect(FloatRect rect)
278 // Using roundf() rather than ceilf() for the right edge as a compromise to
279 // ensure correct caret positioning.
280 float roundedX = roundf(rect.x());
281 return FloatRect(roundedX, rect.y(), roundf(rect.maxX() - roundedX), rect.height());
284 FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to, bool accountForGlyphBounds) const
286 to = (to == -1 ? run.length() : to);
288 TextRunPaintInfo runInfo(run);
289 runInfo.from = from;
290 runInfo.to = to;
292 FontCachePurgePreventer purgePreventer;
294 if (codePath(runInfo) != ComplexPath)
295 return pixelSnappedSelectionRect(selectionRectForSimpleText(run, point, h, from, to, accountForGlyphBounds));
296 return pixelSnappedSelectionRect(selectionRectForComplexText(run, point, h, from, to));
299 int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
301 FontCachePurgePreventer purgePreventer;
303 if (codePath(TextRunPaintInfo(run)) != ComplexPath && !fontDescription().typesettingFeatures())
304 return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
306 return offsetForPositionForComplexText(run, x, includePartialGlyphs);
309 CodePath Font::codePath(const TextRunPaintInfo& runInfo) const
311 if (RuntimeEnabledFeatures::alwaysUseComplexTextEnabled())
312 return ComplexPath;
314 const TextRun& run = runInfo.run;
316 if (fontDescription().typesettingFeatures() && (runInfo.from || runInfo.to != run.length()))
317 return ComplexPath;
319 if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0 && m_fontDescription.letterSpacing() == 0)
320 return ComplexPath;
322 if (m_fontDescription.isVerticalBaseline())
323 return ComplexPath;
325 if (m_fontDescription.widthVariant() != RegularWidth)
326 return ComplexPath;
328 if (run.length() > 1 && fontDescription().typesettingFeatures())
329 return ComplexPath;
331 // FIXME: This really shouldn't be needed but for some reason the
332 // TextRendering setting doesn't propagate to typesettingFeatures in time
333 // for the prefs width calculation.
334 if (fontDescription().textRendering() == OptimizeLegibility || fontDescription().textRendering() == GeometricPrecision)
335 return ComplexPath;
337 if (run.codePath() == TextRun::ForceComplex)
338 return ComplexPath;
340 if (run.codePath() == TextRun::ForceSimple)
341 return SimplePath;
343 if (run.is8Bit())
344 return SimplePath;
346 // Start from 0 since drawing and highlighting also measure the characters before run->from.
347 return Character::characterRangeCodePath(run.characters16(), run.length());
350 bool Font::canShapeWordByWord() const
352 if (!m_shapeWordByWordComputed) {
353 m_canShapeWordByWord = computeCanShapeWordByWord();
354 m_shapeWordByWordComputed = true;
356 return m_canShapeWordByWord;
359 bool Font::computeCanShapeWordByWord() const
361 if (!fontDescription().typesettingFeatures())
362 return true;
364 const FontPlatformData& platformData = primaryFont()->platformData();
365 TypesettingFeatures features = fontDescription().typesettingFeatures();
366 return !platformData.hasSpaceInLigaturesOrKerning(features);
369 void Font::willUseFontData(UChar32 character) const
371 const FontFamily& family = fontDescription().family();
372 if (m_fontFallbackList && m_fontFallbackList->fontSelector() && !family.familyIsEmpty())
373 m_fontFallbackList->fontSelector()->willUseFontData(fontDescription(), family.family(), character);
376 static inline GlyphData glyphDataForNonCJKCharacterWithGlyphOrientation(UChar32 character, bool isUpright, GlyphData& data, unsigned pageNumber)
378 if (isUpright) {
379 RefPtr<SimpleFontData> uprightFontData = data.fontData->uprightOrientationFontData();
380 GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getNormalRootChild(uprightFontData.get(), pageNumber);
381 GlyphPage* uprightPage = uprightNode->page();
382 if (uprightPage) {
383 GlyphData uprightData = uprightPage->glyphDataForCharacter(character);
384 // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright.
385 if (data.glyph == uprightData.glyph)
386 return data;
387 // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that
388 // glyph, so we fall back to the upright data and use the horizontal glyph.
389 if (uprightData.fontData)
390 return uprightData;
392 } else {
393 RefPtr<SimpleFontData> verticalRightFontData = data.fontData->verticalRightOrientationFontData();
394 GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getNormalRootChild(verticalRightFontData.get(), pageNumber);
395 GlyphPage* verticalRightPage = verticalRightNode->page();
396 if (verticalRightPage) {
397 GlyphData verticalRightData = verticalRightPage->glyphDataForCharacter(character);
398 // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked
399 // into it.
400 if (data.glyph != verticalRightData.glyph)
401 return data;
402 // The glyphs are identical, meaning that we should just use the horizontal glyph.
403 if (verticalRightData.fontData)
404 return verticalRightData;
407 return data;
410 GlyphData Font::glyphDataForCharacter(UChar32& c, bool mirror, bool normalizeSpace, FontDataVariant variant) const
412 ASSERT(isMainThread());
414 if (variant == AutoVariant) {
415 if (m_fontDescription.variant() == FontVariantSmallCaps) {
416 bool includeDefault = false;
417 UChar32 upperC = toUpper(c, m_fontDescription.locale(includeDefault));
418 if (upperC != c) {
419 c = upperC;
420 variant = SmallCapsVariant;
421 } else {
422 variant = NormalVariant;
424 } else {
425 variant = NormalVariant;
429 if (normalizeSpace && Character::isNormalizedCanvasSpaceCharacter(c))
430 c = spaceCharacter;
432 if (mirror)
433 c = mirroredChar(c);
435 unsigned pageNumber = (c / GlyphPage::size);
437 GlyphPageTreeNodeBase* node = m_fontFallbackList->getPageNode(pageNumber);
438 if (!node) {
439 node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
440 m_fontFallbackList->setPageNode(pageNumber, node);
443 GlyphPage* page = 0;
444 if (variant == NormalVariant) {
445 // Fastest loop, for the common case (normal variant).
446 while (true) {
447 page = node->page(m_fontDescription.script());
448 if (page) {
449 GlyphData data = page->glyphDataForCharacter(c);
450 if (data.fontData) {
451 if (!data.fontData->platformData().isVerticalAnyUpright() || data.fontData->isTextOrientationFallback())
452 return data;
454 bool isUpright = m_fontDescription.isVerticalUpright(c);
455 if (!isUpright || !Character::isCJKIdeographOrSymbol(c))
456 return glyphDataForNonCJKCharacterWithGlyphOrientation(c, isUpright, data, pageNumber);
458 return data;
461 if (node->isSystemFallback())
462 break;
465 // Proceed with the fallback list.
466 node = toGlyphPageTreeNode(node)->getChild(fontDataAt(node->level()), pageNumber);
467 m_fontFallbackList->setPageNode(pageNumber, node);
470 if (variant != NormalVariant) {
471 while (true) {
472 page = node->page(m_fontDescription.script());
473 if (page) {
474 GlyphData data = page->glyphDataForCharacter(c);
475 if (data.fontData) {
476 // The variantFontData function should not normally return 0.
477 // But if it does, we will just render the capital letter big.
478 RefPtr<SimpleFontData> variantFontData = data.fontData->variantFontData(m_fontDescription, variant);
479 if (!variantFontData)
480 return data;
482 GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getNormalRootChild(variantFontData.get(), pageNumber);
483 GlyphPage* variantPage = variantNode->page();
484 if (variantPage) {
485 GlyphData data = variantPage->glyphDataForCharacter(c);
486 if (data.fontData)
487 return data;
490 // Do not attempt system fallback off the variantFontData. This is the very unlikely case that
491 // a font has the lowercase character but the small caps font does not have its uppercase version.
492 return variantFontData->missingGlyphData();
495 if (node->isSystemFallback())
496 break;
499 // Proceed with the fallback list.
500 node = toGlyphPageTreeNode(node)->getChild(fontDataAt(node->level()), pageNumber);
501 m_fontFallbackList->setPageNode(pageNumber, node);
505 ASSERT(page);
506 ASSERT(node->isSystemFallback());
508 // System fallback is character-dependent. When we get here, we
509 // know that the character in question isn't in the system fallback
510 // font's glyph page. Try to lazily create it here.
512 // FIXME: Unclear if this should normalizeSpaces above 0xFFFF.
513 // Doing so changes fast/text/international/plane2-diffs.html
514 UChar32 characterToRender = c;
515 if (characterToRender <= 0xFFFF)
516 characterToRender = Character::normalizeSpaces(characterToRender);
518 const FontData* fontData = fontDataAt(0);
519 if (fontData) {
520 const SimpleFontData* fontDataToSubstitute = fontData->fontDataForCharacter(characterToRender);
521 RefPtr<SimpleFontData> characterFontData = FontCache::fontCache()->fallbackFontForCharacter(m_fontDescription, characterToRender, fontDataToSubstitute);
522 if (characterFontData && variant != NormalVariant) {
523 characterFontData = characterFontData->variantFontData(m_fontDescription, variant);
525 if (characterFontData) {
526 // Got the fallback glyph and font.
527 unsigned pageNumberForRendering = characterToRender / GlyphPage::size;
528 GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData.get(), pageNumberForRendering)->page();
529 GlyphData data = fallbackPage && fallbackPage->glyphForCharacter(characterToRender) ? fallbackPage->glyphDataForCharacter(characterToRender) : characterFontData->missingGlyphData();
530 // Cache it so we don't have to do system fallback again next time.
531 if (variant == NormalVariant) {
532 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
533 data.fontData->setMaxGlyphPageTreeLevel(std::max(data.fontData->maxGlyphPageTreeLevel(), node->level()));
534 if (data.fontData->platformData().isVerticalAnyUpright() && !data.fontData->isTextOrientationFallback() && !Character::isCJKIdeographOrSymbol(characterToRender))
535 return glyphDataForNonCJKCharacterWithGlyphOrientation(characterToRender, m_fontDescription.isVerticalUpright(characterToRender), data, pageNumberForRendering);
537 return data;
541 // Even system fallback can fail; use the missing glyph in that case.
542 // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
543 ASSERT(primaryFont());
544 GlyphData data = primaryFont()->missingGlyphData();
545 if (variant == NormalVariant) {
546 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
547 data.fontData->setMaxGlyphPageTreeLevel(std::max(data.fontData->maxGlyphPageTreeLevel(), node->level()));
549 return data;
552 // FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
553 // standard emphasis marks do so.
554 bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const
556 if (mark.isEmpty())
557 return false;
559 UChar32 character = mark[0];
561 if (U16_IS_SURROGATE(character)) {
562 if (!U16_IS_SURROGATE_LEAD(character))
563 return false;
565 if (mark.length() < 2)
566 return false;
568 UChar low = mark[1];
569 if (!U16_IS_TRAIL(low))
570 return false;
572 character = U16_GET_SUPPLEMENTARY(character, low);
575 bool normalizeSpace = false;
576 glyphData = glyphDataForCharacter(character, false, normalizeSpace, EmphasisMarkVariant);
577 return true;
580 int Font::emphasisMarkAscent(const AtomicString& mark) const
582 FontCachePurgePreventer purgePreventer;
584 GlyphData markGlyphData;
585 if (!getEmphasisMarkGlyphData(mark, markGlyphData))
586 return 0;
588 const SimpleFontData* markFontData = markGlyphData.fontData;
589 ASSERT(markFontData);
590 if (!markFontData)
591 return 0;
593 return markFontData->fontMetrics().ascent();
596 int Font::emphasisMarkDescent(const AtomicString& mark) const
598 FontCachePurgePreventer purgePreventer;
600 GlyphData markGlyphData;
601 if (!getEmphasisMarkGlyphData(mark, markGlyphData))
602 return 0;
604 const SimpleFontData* markFontData = markGlyphData.fontData;
605 ASSERT(markFontData);
606 if (!markFontData)
607 return 0;
609 return markFontData->fontMetrics().descent();
612 int Font::emphasisMarkHeight(const AtomicString& mark) const
614 FontCachePurgePreventer purgePreventer;
616 GlyphData markGlyphData;
617 if (!getEmphasisMarkGlyphData(mark, markGlyphData))
618 return 0;
620 const SimpleFontData* markFontData = markGlyphData.fontData;
621 ASSERT(markFontData);
622 if (!markFontData)
623 return 0;
625 return markFontData->fontMetrics().height();
628 void Font::paintGlyphs(SkCanvas* canvas, const SkPaint& paint, const SimpleFontData* font,
629 const Glyph glyphs[], unsigned numGlyphs,
630 const SkPoint pos[], const FloatRect& textRect, float deviceScaleFactor) const
632 SkPaint fontPaint(paint);
633 font->platformData().setupPaint(&fontPaint, deviceScaleFactor, this);
634 fontPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
635 canvas->drawPosText(glyphs, numGlyphs * sizeof(Glyph), pos, fontPaint);
638 void Font::paintGlyphsHorizontal(SkCanvas* canvas, const SkPaint& paint, const SimpleFontData* font,
639 const Glyph glyphs[], unsigned numGlyphs,
640 const SkScalar xpos[], SkScalar constY, const FloatRect& textRect, float deviceScaleFactor) const
642 SkPaint fontPaint(paint);
643 font->platformData().setupPaint(&fontPaint, deviceScaleFactor, this);
644 fontPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
645 canvas->drawPosTextH(glyphs, numGlyphs * sizeof(Glyph), xpos, constY, fontPaint);
648 void Font::drawGlyphs(SkCanvas* canvas, const SkPaint& paint, const SimpleFontData* font,
649 const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs,
650 const FloatPoint& point, const FloatRect& textRect, float deviceScaleFactor) const
652 ASSERT(glyphBuffer.size() >= from + numGlyphs);
654 if (!glyphBuffer.hasVerticalOffsets()) {
655 Vector<SkScalar, 64> xpos(numGlyphs);
656 for (unsigned i = 0; i < numGlyphs; i++)
657 xpos[i] = SkFloatToScalar(point.x() + glyphBuffer.xOffsetAt(from + i));
659 paintGlyphsHorizontal(canvas, paint, font, glyphBuffer.glyphs(from), numGlyphs, xpos.data(),
660 SkFloatToScalar(point.y()), textRect, deviceScaleFactor);
661 return;
664 bool drawVertically = font->platformData().isVerticalAnyUpright() && font->verticalData();
666 int canvasStackLevel = canvas->getSaveCount();
667 if (drawVertically) {
668 canvas->save();
669 canvas->concat(affineTransformToSkMatrix(AffineTransform(0, -1, 1, 0, point.x(), point.y())));
670 canvas->concat(affineTransformToSkMatrix(AffineTransform(1, 0, 0, 1, -point.x(), -point.y())));
673 const float verticalBaselineXOffset = drawVertically ? SkFloatToScalar(font->fontMetrics().floatAscent() - font->fontMetrics().floatAscent(IdeographicBaseline)) : 0;
675 ASSERT(glyphBuffer.hasVerticalOffsets());
676 Vector<SkPoint, 32> pos(numGlyphs);
677 for (unsigned i = 0; i < numGlyphs; i++) {
678 pos[i].set(
679 SkFloatToScalar(point.x() + verticalBaselineXOffset + glyphBuffer.xOffsetAt(from + i)),
680 SkFloatToScalar(point.y() + glyphBuffer.yOffsetAt(from + i)));
683 paintGlyphs(canvas, paint, font, glyphBuffer.glyphs(from), numGlyphs, pos.data(), textRect, deviceScaleFactor);
684 canvas->restoreToCount(canvasStackLevel);
687 void Font::drawTextBlob(SkCanvas* canvas, const SkPaint& paint, const SkTextBlob* blob, const SkPoint& origin) const
689 canvas->drawTextBlob(blob, origin.x(), origin.y(), paint);
692 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* glyphBounds) const
694 CachingWordShaper& shaper = m_fontFallbackList->cachingWordShaper();
695 float width = shaper.width(this, run, fallbackFonts, glyphBounds);
696 return width;
699 // Return the code point index for the given |x| offset into the text run.
700 int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat,
701 bool includePartialGlyphs) const
703 CachingWordShaper& shaper = m_fontFallbackList->cachingWordShaper();
704 return shaper.offsetForPosition(this, run, xFloat);
707 // Return the rectangle for selecting the given range of code-points in the TextRun.
708 FloatRect Font::selectionRectForComplexText(const TextRun& run,
709 const FloatPoint& point, int height, int from, int to) const
711 CachingWordShaper& shaper = m_fontFallbackList->cachingWordShaper();
712 return shaper.selectionRect(this, run, point, height, from, to);
715 void Font::drawGlyphBuffer(SkCanvas* canvas, const SkPaint& paint, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const FloatPoint& point, float deviceScaleFactor) const
717 if (glyphBuffer.isEmpty())
718 return;
720 // Always try to draw a text blob, even for uncacheable blobs.
721 TextBlobPtr uncacheableTextBlob;
722 TextBlobPtr& textBlob = runInfo.cachedTextBlob ? *runInfo.cachedTextBlob : uncacheableTextBlob;
723 textBlob = buildTextBlob(glyphBuffer);
724 if (textBlob) {
725 drawTextBlob(canvas, paint, textBlob.get(), point.data());
726 return;
729 // Draw each contiguous run of glyphs that use the same font data.
730 const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
731 unsigned lastFrom = 0;
732 unsigned nextGlyph;
734 for (nextGlyph = 0; nextGlyph < glyphBuffer.size(); ++nextGlyph) {
735 const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
737 if (nextFontData != fontData) {
738 drawGlyphs(canvas, paint, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, point, runInfo.bounds, deviceScaleFactor);
739 lastFrom = nextGlyph;
740 fontData = nextFontData;
744 drawGlyphs(canvas, paint, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, point, runInfo.bounds, deviceScaleFactor);
747 float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* glyphBounds) const
749 SimpleShaper shaper(this, run, nullptr, fallbackFonts, glyphBounds);
750 shaper.advance(run.length());
751 return shaper.runWidthSoFar();
754 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to, bool accountForGlyphBounds) const
756 FloatRect bounds;
757 SimpleShaper shaper(this, run, nullptr, nullptr, accountForGlyphBounds ? &bounds : nullptr);
758 shaper.advance(from);
759 float fromX = shaper.runWidthSoFar();
760 shaper.advance(to);
761 float toX = shaper.runWidthSoFar();
763 if (run.rtl()) {
764 shaper.advance(run.length());
765 float totalWidth = shaper.runWidthSoFar();
766 float beforeWidth = fromX;
767 float afterWidth = toX;
768 fromX = totalWidth - afterWidth;
769 toX = totalWidth - beforeWidth;
772 return FloatRect(point.x() + fromX,
773 accountForGlyphBounds ? bounds.y(): point.y(),
774 toX - fromX,
775 accountForGlyphBounds ? bounds.maxY()- bounds.y(): h);
778 int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
780 float delta = x;
782 SimpleShaper shaper(this, run);
783 unsigned offset;
784 if (run.rtl()) {
785 delta -= floatWidthForSimpleText(run);
786 while (1) {
787 offset = shaper.currentOffset();
788 float w;
789 if (!shaper.advanceOneCharacter(w))
790 break;
791 delta += w;
792 if (includePartialGlyphs) {
793 if (delta - w / 2 >= 0)
794 break;
795 } else {
796 if (delta >= 0)
797 break;
800 } else {
801 while (1) {
802 offset = shaper.currentOffset();
803 float w;
804 if (!shaper.advanceOneCharacter(w))
805 break;
806 delta -= w;
807 if (includePartialGlyphs) {
808 if (delta + w / 2 <= 0)
809 break;
810 } else {
811 if (delta <= 0)
812 break;
817 return offset;
820 bool Font::loadingCustomFonts() const
822 return m_fontFallbackList && m_fontFallbackList->loadingCustomFonts();
825 bool Font::isFallbackValid() const
827 return !m_fontFallbackList || m_fontFallbackList->isValid();
830 } // namespace blink