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.
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"
53 using namespace Unicode
;
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
;
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
) {
113 CachingWordShaper
& shaper
= m_fontFallbackList
->cachingWordShaper();
115 width
= shaper
.fillGlyphBufferForTextEmphasis(this, runInfo
.run
,
116 emphasisData
, &glyphBuffer
, runInfo
.from
, runInfo
.to
);
118 width
= shaper
.fillGlyphBuffer(this, runInfo
.run
, nullptr,
119 &glyphBuffer
, runInfo
.from
, runInfo
.to
);
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());
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())
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());
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
163 if (shouldSkipDrawing() && customFontNotReadyAction
== DoNotPaintIfFontNotReady
)
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())
180 FloatPoint currPoint
= point
;
181 BidiCharacterRun
* bidiRun
= bidiRuns
.firstRun();
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())
209 FontCachePurgePreventer purgePreventer
;
211 GlyphData emphasisGlyphData
;
212 if (!getEmphasisMarkGlyphData(mark
, emphasisGlyphData
))
215 ASSERT(emphasisGlyphData
.fontData
);
216 if (!emphasisGlyphData
.fontData
)
219 GlyphBuffer glyphBuffer
;
220 buildGlyphBuffer(runInfo
, glyphBuffer
, &emphasisGlyphData
);
222 if (glyphBuffer
.isEmpty())
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();
243 while (i
< glyphBuffer
.size()) {
244 const SimpleFontData
* fontData
= glyphBuffer
.fontDataAt(i
);
246 // FIXME: Handle vertical text.
247 if (fontData
->platformData().isVerticalAnyUpright())
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
)
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
);
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())
314 const TextRun
& run
= runInfo
.run
;
316 if (fontDescription().typesettingFeatures() && (runInfo
.from
|| runInfo
.to
!= run
.length()))
319 if (m_fontDescription
.featureSettings() && m_fontDescription
.featureSettings()->size() > 0 && m_fontDescription
.letterSpacing() == 0)
322 if (m_fontDescription
.isVerticalBaseline())
325 if (m_fontDescription
.widthVariant() != RegularWidth
)
328 if (run
.length() > 1 && fontDescription().typesettingFeatures())
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
)
337 if (run
.codePath() == TextRun::ForceComplex
)
340 if (run
.codePath() == TextRun::ForceSimple
)
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())
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
)
379 RefPtr
<SimpleFontData
> uprightFontData
= data
.fontData
->uprightOrientationFontData();
380 GlyphPageTreeNode
* uprightNode
= GlyphPageTreeNode::getNormalRootChild(uprightFontData
.get(), pageNumber
);
381 GlyphPage
* uprightPage
= uprightNode
->page();
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
)
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
)
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
400 if (data
.glyph
!= verticalRightData
.glyph
)
402 // The glyphs are identical, meaning that we should just use the horizontal glyph.
403 if (verticalRightData
.fontData
)
404 return verticalRightData
;
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
));
420 variant
= SmallCapsVariant
;
422 variant
= NormalVariant
;
425 variant
= NormalVariant
;
429 if (normalizeSpace
&& Character::isNormalizedCanvasSpaceCharacter(c
))
435 unsigned pageNumber
= (c
/ GlyphPage::size
);
437 GlyphPageTreeNodeBase
* node
= m_fontFallbackList
->getPageNode(pageNumber
);
439 node
= GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber
);
440 m_fontFallbackList
->setPageNode(pageNumber
, node
);
444 if (variant
== NormalVariant
) {
445 // Fastest loop, for the common case (normal variant).
447 page
= node
->page(m_fontDescription
.script());
449 GlyphData data
= page
->glyphDataForCharacter(c
);
451 if (!data
.fontData
->platformData().isVerticalAnyUpright() || data
.fontData
->isTextOrientationFallback())
454 bool isUpright
= m_fontDescription
.isVerticalUpright(c
);
455 if (!isUpright
|| !Character::isCJKIdeographOrSymbol(c
))
456 return glyphDataForNonCJKCharacterWithGlyphOrientation(c
, isUpright
, data
, pageNumber
);
461 if (node
->isSystemFallback())
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
) {
472 page
= node
->page(m_fontDescription
.script());
474 GlyphData data
= page
->glyphDataForCharacter(c
);
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
)
482 GlyphPageTreeNode
* variantNode
= GlyphPageTreeNode::getNormalRootChild(variantFontData
.get(), pageNumber
);
483 GlyphPage
* variantPage
= variantNode
->page();
485 GlyphData data
= variantPage
->glyphDataForCharacter(c
);
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())
499 // Proceed with the fallback list.
500 node
= toGlyphPageTreeNode(node
)->getChild(fontDataAt(node
->level()), pageNumber
);
501 m_fontFallbackList
->setPageNode(pageNumber
, node
);
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);
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
);
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()));
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
559 UChar32 character
= mark
[0];
561 if (U16_IS_SURROGATE(character
)) {
562 if (!U16_IS_SURROGATE_LEAD(character
))
565 if (mark
.length() < 2)
569 if (!U16_IS_TRAIL(low
))
572 character
= U16_GET_SUPPLEMENTARY(character
, low
);
575 bool normalizeSpace
= false;
576 glyphData
= glyphDataForCharacter(character
, false, normalizeSpace
, EmphasisMarkVariant
);
580 int Font::emphasisMarkAscent(const AtomicString
& mark
) const
582 FontCachePurgePreventer purgePreventer
;
584 GlyphData markGlyphData
;
585 if (!getEmphasisMarkGlyphData(mark
, markGlyphData
))
588 const SimpleFontData
* markFontData
= markGlyphData
.fontData
;
589 ASSERT(markFontData
);
593 return markFontData
->fontMetrics().ascent();
596 int Font::emphasisMarkDescent(const AtomicString
& mark
) const
598 FontCachePurgePreventer purgePreventer
;
600 GlyphData markGlyphData
;
601 if (!getEmphasisMarkGlyphData(mark
, markGlyphData
))
604 const SimpleFontData
* markFontData
= markGlyphData
.fontData
;
605 ASSERT(markFontData
);
609 return markFontData
->fontMetrics().descent();
612 int Font::emphasisMarkHeight(const AtomicString
& mark
) const
614 FontCachePurgePreventer purgePreventer
;
616 GlyphData markGlyphData
;
617 if (!getEmphasisMarkGlyphData(mark
, markGlyphData
))
620 const SimpleFontData
* markFontData
= markGlyphData
.fontData
;
621 ASSERT(markFontData
);
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
);
664 bool drawVertically
= font
->platformData().isVerticalAnyUpright() && font
->verticalData();
666 int canvasStackLevel
= canvas
->getSaveCount();
667 if (drawVertically
) {
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
++) {
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
);
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())
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
);
725 drawTextBlob(canvas
, paint
, textBlob
.get(), point
.data());
729 // Draw each contiguous run of glyphs that use the same font data.
730 const SimpleFontData
* fontData
= glyphBuffer
.fontDataAt(0);
731 unsigned lastFrom
= 0;
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
757 SimpleShaper
shaper(this, run
, nullptr, nullptr, accountForGlyphBounds
? &bounds
: nullptr);
758 shaper
.advance(from
);
759 float fromX
= shaper
.runWidthSoFar();
761 float toX
= shaper
.runWidthSoFar();
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(),
775 accountForGlyphBounds
? bounds
.maxY()- bounds
.y(): h
);
778 int Font::offsetForPositionForSimpleText(const TextRun
& run
, float x
, bool includePartialGlyphs
) const
782 SimpleShaper
shaper(this, run
);
785 delta
-= floatWidthForSimpleText(run
);
787 offset
= shaper
.currentOffset();
789 if (!shaper
.advanceOneCharacter(w
))
792 if (includePartialGlyphs
) {
793 if (delta
- w
/ 2 >= 0)
802 offset
= shaper
.currentOffset();
804 if (!shaper
.advanceOneCharacter(w
))
807 if (includePartialGlyphs
) {
808 if (delta
+ w
/ 2 <= 0)
820 bool Font::loadingCustomFonts() const
822 return m_fontFallbackList
&& m_fontFallbackList
->loadingCustomFonts();
825 bool Font::isFallbackValid() const
827 return !m_fontFallbackList
|| m_fontFallbackList
->isValid();