void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const { FontCachePurgePreventer purgePreventer; GlyphData markGlyphData; if (!getEmphasisMarkGlyphData(mark, markGlyphData)) return; const SimpleFontData* markFontData = markGlyphData.fontData; ASSERT(markFontData); if (!markFontData) return; Glyph markGlyph = markGlyphData.glyph; Glyph spaceGlyph = markFontData->spaceGlyph(); float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0); FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y()); GlyphBuffer markBuffer; for (int i = 0; i + 1 < glyphBuffer.size(); ++i) { float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1); float advance = glyphBuffer.advanceAt(i).width() - middleOfLastGlyph + middleOfNextGlyph; markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance); middleOfLastGlyph = middleOfNextGlyph; } markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0); drawGlyphBuffer(context, run, markBuffer, startPoint); }
TEST(GlyphBufferTest, StoresVerticalOffsets) { RefPtr<SimpleFontData> font1 = TestSimpleFontData::create(); RefPtr<SimpleFontData> font2 = TestSimpleFontData::create(); GlyphBuffer glyphBuffer; EXPECT_FALSE(glyphBuffer.hasVerticalOffsets()); glyphBuffer.add(42, font1.get(), FloatPoint(10, 0)); glyphBuffer.add(43, font1.get(), FloatPoint(15, 0)); glyphBuffer.add(44, font2.get(), FloatPoint(12, 2)); EXPECT_FALSE(glyphBuffer.isEmpty()); EXPECT_TRUE(glyphBuffer.hasVerticalOffsets()); EXPECT_EQ(3u, glyphBuffer.size()); const float* offsets = glyphBuffer.offsets(0); EXPECT_EQ(10, glyphBuffer.xOffsetAt(0)); EXPECT_EQ(0, glyphBuffer.yOffsetAt(0)); EXPECT_EQ(15, glyphBuffer.xOffsetAt(1)); EXPECT_EQ(0, glyphBuffer.yOffsetAt(1)); EXPECT_EQ(12, glyphBuffer.xOffsetAt(2)); EXPECT_EQ(2, glyphBuffer.yOffsetAt(2)); EXPECT_EQ(10, offsets[0]); EXPECT_EQ(0, offsets[1]); EXPECT_EQ(15, offsets[2]); EXPECT_EQ(0, offsets[3]); EXPECT_EQ(12, offsets[4]); EXPECT_EQ(2, offsets[5]); }
TEST(GlyphBufferTest, ReverseForSimpleRTL) { RefPtr<SimpleFontData> font1 = TestSimpleFontData::create(); RefPtr<SimpleFontData> font2 = TestSimpleFontData::create(); GlyphBuffer glyphBuffer; glyphBuffer.add(42, font1.get(), 10); glyphBuffer.add(43, font1.get(), 15); glyphBuffer.add(44, font2.get(), 25); EXPECT_FALSE(glyphBuffer.isEmpty()); EXPECT_EQ(3u, glyphBuffer.size()); glyphBuffer.reverseForSimpleRTL(30, 100); EXPECT_FALSE(glyphBuffer.isEmpty()); EXPECT_EQ(3u, glyphBuffer.size()); EXPECT_EQ(44, glyphBuffer.glyphAt(0)); EXPECT_EQ(43, glyphBuffer.glyphAt(1)); EXPECT_EQ(42, glyphBuffer.glyphAt(2)); EXPECT_EQ(font2.get(), glyphBuffer.fontDataAt(0)); EXPECT_EQ(font1.get(), glyphBuffer.fontDataAt(1)); EXPECT_EQ(font1.get(), glyphBuffer.fontDataAt(2)); EXPECT_EQ(70, glyphBuffer.xOffsetAt(0)); EXPECT_EQ(75, glyphBuffer.xOffsetAt(1)); EXPECT_EQ(85, glyphBuffer.xOffsetAt(2)); }
inline GlyphBuffer DrawGlyphs::generateGlyphBuffer() const { GlyphBuffer result; for (size_t i = 0; i < m_glyphs.size(); ++i) { #if USE(CAIRO) result.add(m_glyphs[i].index, &m_font.get(), m_advances[i]); #else result.add(m_glyphs[i], &m_font.get(), m_advances[i]); #endif } return result; }
float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const { WidthIterator it(this, run, 0, false, forTextEmphasis); GlyphBuffer localGlyphBuffer; it.advance(run.length(), &localGlyphBuffer); if (localGlyphBuffer.isEmpty()) return 0; float totalWidth = it.m_runWidthSoFar; float beforeWidth = 0; int glyphPos = 0; for (; glyphPos < localGlyphBuffer.size() && it.m_characterIndexOfGlyph[glyphPos] < from; ++glyphPos) beforeWidth += localGlyphBuffer.advanceAt(glyphPos).width(); int glyphFrom = glyphPos; float afterWidth = totalWidth; glyphPos = localGlyphBuffer.size() - 1; for (; glyphPos >= glyphFrom && it.m_characterIndexOfGlyph[glyphPos] >= to; --glyphPos) afterWidth -= localGlyphBuffer.advanceAt(glyphPos).width(); int glyphTo = glyphPos + 1; glyphBuffer.add(&localGlyphBuffer, glyphFrom, glyphTo - glyphFrom); if (run.rtl()) { glyphBuffer.reverse(0, glyphBuffer.size()); return totalWidth - afterWidth; } return beforeWidth; }
TEST(GlyphBufferTest, GlyphArrayWithOffset) { RefPtr<SimpleFontData> font1 = TestSimpleFontData::create(); RefPtr<SimpleFontData> font2 = TestSimpleFontData::create(); GlyphBuffer glyphBuffer; glyphBuffer.add(42, font1.get(), 10); glyphBuffer.add(43, font1.get(), 15); glyphBuffer.add(44, font2.get(), 12); EXPECT_FALSE(glyphBuffer.isEmpty()); EXPECT_EQ(3u, glyphBuffer.size()); const Glyph* glyphs = glyphBuffer.glyphs(1); EXPECT_EQ(43, glyphs[0]); EXPECT_EQ(44, glyphs[1]); }
TEST(GlyphBufferTest, StoresSimpleFontData) { RefPtr<SimpleFontData> font1 = TestSimpleFontData::create(); RefPtr<SimpleFontData> font2 = TestSimpleFontData::create(); GlyphBuffer glyphBuffer; glyphBuffer.add(42, font1.get(), 10); glyphBuffer.add(43, font1.get(), 15); glyphBuffer.add(44, font2.get(), 12); EXPECT_FALSE(glyphBuffer.isEmpty()); EXPECT_EQ(3u, glyphBuffer.size()); EXPECT_EQ(font1.get(), glyphBuffer.fontDataAt(0)); EXPECT_EQ(font1.get(), glyphBuffer.fontDataAt(1)); EXPECT_EQ(font2.get(), glyphBuffer.fontDataAt(2)); }
TEST(GlyphBufferTest, StoresGlyphs) { RefPtr<SimpleFontData> font1 = TestSimpleFontData::create(); RefPtr<SimpleFontData> font2 = TestSimpleFontData::create(); GlyphBuffer glyphBuffer; glyphBuffer.add(42, font1.get(), 10); glyphBuffer.add(43, font1.get(), 15); glyphBuffer.add(44, font2.get(), 22); EXPECT_FALSE(glyphBuffer.isEmpty()); EXPECT_FALSE(glyphBuffer.hasVerticalOffsets()); EXPECT_EQ(3u, glyphBuffer.size()); EXPECT_EQ(42, glyphBuffer.glyphAt(0)); EXPECT_EQ(43, glyphBuffer.glyphAt(1)); EXPECT_EQ(44, glyphBuffer.glyphAt(2)); const Glyph* glyphs = glyphBuffer.glyphs(0); EXPECT_EQ(42, glyphs[0]); EXPECT_EQ(43, glyphs[1]); EXPECT_EQ(44, glyphs[2]); }
TEST(GlyphBufferTest, OffsetArrayWithNonZeroIndex) { RefPtr<SimpleFontData> font1 = TestSimpleFontData::create(); RefPtr<SimpleFontData> font2 = TestSimpleFontData::create(); { GlyphBuffer glyphBuffer; glyphBuffer.add(42, font1.get(), 10); glyphBuffer.add(43, font1.get(), 15); glyphBuffer.add(43, font2.get(), 12); EXPECT_FALSE(glyphBuffer.isEmpty()); EXPECT_FALSE(glyphBuffer.hasVerticalOffsets()); EXPECT_EQ(3u, glyphBuffer.size()); const float* offsets = glyphBuffer.offsets(1); EXPECT_EQ(15, offsets[0]); EXPECT_EQ(12, offsets[1]); } { GlyphBuffer glyphBuffer; glyphBuffer.add(42, font1.get(), FloatPoint(10, 0)); glyphBuffer.add(43, font1.get(), FloatPoint(15, 0)); glyphBuffer.add(43, font2.get(), FloatPoint(12, 2)); EXPECT_FALSE(glyphBuffer.isEmpty()); EXPECT_TRUE(glyphBuffer.hasVerticalOffsets()); EXPECT_EQ(3u, glyphBuffer.size()); const float* offsets = glyphBuffer.offsets(1); EXPECT_EQ(15, offsets[0]); EXPECT_EQ(0, offsets[1]); EXPECT_EQ(12, offsets[2]); EXPECT_EQ(2, offsets[3]); } }
void RenderMathMLToken::paint(PaintInfo& info, const LayoutPoint& paintOffset) { RenderMathMLBlock::paint(info, paintOffset); // FIXME: Instead of using DrawGlyph, we may consider using the more general TextPainter so that we can apply mathvariant to strings with an arbitrary number of characters and preserve advanced CSS effects (text-shadow, etc). if (info.context().paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE || !m_mathVariantCodePoint) return; auto mathVariantGlyph = style().fontCascade().glyphDataForCharacter(m_mathVariantCodePoint.value(), m_mathVariantIsMirrored); if (!mathVariantGlyph.font) return; GraphicsContextStateSaver stateSaver(info.context()); info.context().setFillColor(style().visitedDependentColor(CSSPropertyColor)); GlyphBuffer buffer; buffer.add(mathVariantGlyph.glyph, mathVariantGlyph.font, mathVariantGlyph.font->widthForGlyph(mathVariantGlyph.glyph)); LayoutUnit glyphAscent = static_cast<int>(lroundf(-mathVariantGlyph.font->boundsForGlyph(mathVariantGlyph.glyph).y())); info.context().drawGlyphs(style().fontCascade(), *mathVariantGlyph.font, buffer, 0, 1, paintOffset + location() + LayoutPoint(0, glyphAscent)); }