float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const { float initialAdvance; WidthIterator it(this, run, 0, false, forTextEmphasis); it.advance(from); float beforeWidth = it.m_runWidthSoFar; it.advance(to, &glyphBuffer); if (glyphBuffer.isEmpty()) return 0; float afterWidth = it.m_runWidthSoFar; if (run.rtl()) { it.advance(run.length()); initialAdvance = it.m_runWidthSoFar - afterWidth; } else initialAdvance = beforeWidth; if (run.rtl()) { for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end) glyphBuffer.swap(i, end); } return initialAdvance; }
// Tests that filling a glyph buffer for a specific range returns the same // results when shaping word by word as when shaping the full run in one go. TEST_F(CachingWordShaperTest, CommonAccentRightToLeftFillGlyphBuffer) { // "[] []" with an accent mark over the last square bracket. const UChar str[] = { 0x5B, 0x5D, 0x20, 0x5B, 0x301, 0x5D, 0x0 }; TextRun textRun(str, 6); textRun.setDirection(RTL); CachingWordShaper shaper(cache.get()); GlyphBuffer glyphBuffer; shaper.fillGlyphBuffer(&font, textRun, fallbackFonts, &glyphBuffer, 1, 6); OwnPtr<ShapeCache> referenceCache = adoptPtr(new ShapeCache()); CachingWordShaper referenceShaper(referenceCache.get()); GlyphBuffer referenceGlyphBuffer; font.setCanShapeWordByWordForTesting(false); referenceShaper.fillGlyphBuffer(&font, textRun, fallbackFonts, &referenceGlyphBuffer, 1, 6); ASSERT_EQ(5u, referenceGlyphBuffer.size()); ASSERT_EQ(referenceGlyphBuffer.size(), glyphBuffer.size()); ASSERT_EQ(referenceGlyphBuffer.glyphAt(0), glyphBuffer.glyphAt(0)); ASSERT_EQ(referenceGlyphBuffer.glyphAt(1), glyphBuffer.glyphAt(1)); ASSERT_EQ(referenceGlyphBuffer.glyphAt(2), glyphBuffer.glyphAt(2)); ASSERT_EQ(referenceGlyphBuffer.glyphAt(3), glyphBuffer.glyphAt(3)); ASSERT_EQ(referenceGlyphBuffer.glyphAt(4), glyphBuffer.glyphAt(4)); }
void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { // This glyph buffer holds our glyphs + advances + font data for each glyph. GlyphBuffer glyphBuffer; float startX = point.x(); CoreTextController controller(this, run); controller.advance(from); float beforeWidth = controller.runWidthSoFar(); controller.advance(to, &glyphBuffer); // We couldn't generate any glyphs for the run. Give up. if (glyphBuffer.isEmpty()) return; float afterWidth = controller.runWidthSoFar(); if (run.rtl()) { startX += controller.totalWidth() + controller.finalRoundingWidth() - afterWidth; for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end) glyphBuffer.swap(i, end); } else startX += beforeWidth; // Draw the glyph buffer now at the starting point returned in startX. FloatPoint startPoint(startX, point.y()); drawGlyphBuffer(context, glyphBuffer, run, startPoint); }
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)); }
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; }
FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const { GlyphBuffer glyphBuffer; WidthIterator it(this, run); it.advance(run.length(), &glyphBuffer); float totalWidth = it.m_runWidthSoFar; float beforeWidth = 0; int glyphPos = 0; for (; glyphPos < glyphBuffer.size() && it.m_characterIndexOfGlyph[glyphPos] < from; ++glyphPos) beforeWidth += glyphBuffer.advanceAt(glyphPos).width(); int glyphFrom = glyphPos; float afterWidth = totalWidth; glyphPos = glyphBuffer.size() - 1; for (; glyphPos >= glyphFrom && it.m_characterIndexOfGlyph[glyphPos] >= to; --glyphPos) afterWidth -= glyphBuffer.advanceAt(glyphPos).width(); // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning. if (run.rtl()) { return FloatRect(floorf(point.x() + totalWidth - afterWidth), point.y(), roundf(point.x() + totalWidth - beforeWidth) - floorf(point.x() + totalWidth - afterWidth), h); } return FloatRect(floorf(point.x() + beforeWidth), point.y(), roundf(point.x() + afterWidth) - floorf(point.x() + beforeWidth), h); }
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); }
void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { // This glyph buffer holds our glyphs+advances+font data for each glyph. GlyphBuffer glyphBuffer; float startX = point.x(); WidthIterator it(this, run); it.advance(from); float beforeWidth = it.m_runWidthSoFar; it.advance(to, &glyphBuffer); // We couldn't generate any glyphs for the run. Give up. if (glyphBuffer.isEmpty()) return; float afterWidth = it.m_runWidthSoFar; if (run.rtl()) { float finalRoundingWidth = it.m_finalRoundingWidth; it.advance(run.length()); startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth; } else startX += beforeWidth; // Swap the order of the glyphs if right-to-left. if (run.rtl()) for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end) glyphBuffer.swap(i, end); // Calculate the starting point of the glyphs to be displayed by adding // all the advances up to the first glyph. FloatPoint startPoint(startX, point.y()); drawGlyphBuffer(context, glyphBuffer, run, startPoint); }
bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer& glyphBuffer) { int oldSize = glyphBuffer.size(); advance(m_currentCharacter + 1, &glyphBuffer); float w = 0; for (int i = oldSize; i < glyphBuffer.size(); ++i) w += glyphBuffer.advanceAt(i); width = w; return glyphBuffer.size() > oldSize; }
float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const { float initialAdvance; WidthIterator it(this, run, 0, false, forTextEmphasis); // FIXME: Using separate glyph buffers for the prefix and the suffix is incorrect when kerning or // ligatures are enabled. GlyphBuffer localGlyphBuffer; it.advance(from, &localGlyphBuffer); float beforeWidth = it.m_runWidthSoFar; it.advance(to, &glyphBuffer); if (glyphBuffer.isEmpty()) return 0; float afterWidth = it.m_runWidthSoFar; if (run.rtl()) { float finalRoundingWidth = it.m_finalRoundingWidth; it.advance(run.length(), &localGlyphBuffer); initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth; } else { initialAdvance = beforeWidth; } if (run.rtl()) glyphBuffer.reverse(0, glyphBuffer.size()); return initialAdvance; }
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]); }
void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const { // Draw each contiguous run of glyphs that use the same font data. const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); FloatSize offset = glyphBuffer.offsetAt(0); FloatPoint startPoint(point); float nextX = startPoint.x(); int lastFrom = 0; int nextGlyph = 0; while (nextGlyph < glyphBuffer.size()) { const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph); if (nextFontData != fontData || nextOffset != offset) { drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); lastFrom = nextGlyph; fontData = nextFontData; offset = nextOffset; startPoint.setX(nextX); } nextX += glyphBuffer.advanceAt(nextGlyph); nextGlyph++; } drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); }
int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const { GlyphBuffer glyphBuffer; WidthIterator it(this, run); it.advance(run.length(), &glyphBuffer); int characterOffset = 0; if (run.rtl()) { float currentX = it.m_runWidthSoFar; for (int glyphPosition = 0; glyphPosition <= glyphBuffer.size(); ++glyphPosition) { if (glyphPosition == glyphBuffer.size()) { characterOffset = run.length(); break; } characterOffset = it.m_characterIndexOfGlyph[glyphPosition]; float glyphWidth = glyphBuffer.advanceAt(glyphPosition).width(); if (includePartialGlyphs) { if (currentX - glyphWidth / 2.0f <= x) break; } else { if (currentX - glyphWidth <= x) break; } currentX -= glyphWidth; } } else { float currentX = 0; for (int glyphPosition = 0; glyphPosition <= glyphBuffer.size(); ++glyphPosition) { if (glyphPosition == glyphBuffer.size()) { characterOffset = run.length(); break; } characterOffset = it.m_characterIndexOfGlyph[glyphPosition]; float glyphWidth = glyphBuffer.advanceAt(glyphPosition).width(); if (includePartialGlyphs) { if (currentX + glyphWidth / 2.0f >= x) break; } else { if (currentX + glyphWidth >= x) break; } currentX += glyphWidth; } } return characterOffset; }
DashArray FontCascade::dashesForIntersectionsWithRect(const TextRun& run, const FloatPoint& textOrigin, const FloatRect& lineExtents) const { if (isLoadingCustomFonts()) return DashArray(); GlyphBuffer glyphBuffer; glyphBuffer.saveOffsetsInString(); float deltaX; if (codePath(run) != FontCascade::Complex) deltaX = getGlyphsAndAdvancesForSimpleText(run, 0, run.length(), glyphBuffer); else deltaX = getGlyphsAndAdvancesForComplexText(run, 0, run.length(), glyphBuffer); if (!glyphBuffer.size()) return DashArray(); // FIXME: Handle SVG + non-SVG interleaved runs. https://bugs.webkit.org/show_bug.cgi?id=133778 FloatPoint origin = FloatPoint(textOrigin.x() + deltaX, textOrigin.y()); std::unique_ptr<GlyphToPathTranslator> translator = std::make_unique<CairoGlyphToPathTranslator>(run, glyphBuffer, origin); DashArray result; for (int index = 0; translator->containsMorePaths(); ++index, translator->advance()) { float centerOfLine = lineExtents.y() + (lineExtents.height() / 2); GlyphIterationState info = GlyphIterationState(FloatPoint(), FloatPoint(), centerOfLine, lineExtents.x() + lineExtents.width(), lineExtents.x()); const Font* localFontData = glyphBuffer.fontAt(index); if (!localFontData) { // The advances will get all messed up if we do anything other than bail here. result.clear(); break; } switch (translator->underlineType()) { case GlyphToPathTranslator::GlyphUnderlineType::SkipDescenders: { Path path = translator->path(); path.apply([&info](const PathElement& pathElement) { findPathIntersections(info, pathElement); }); if (info.minX < info.maxX) { result.append(info.minX - lineExtents.x()); result.append(info.maxX - lineExtents.x()); } break; } case GlyphToPathTranslator::GlyphUnderlineType::SkipGlyph: { std::pair<float, float> extents = translator->extents(); result.append(extents.first - lineExtents.x()); result.append(extents.second - lineExtents.x()); break; } case GlyphToPathTranslator::GlyphUnderlineType::DrawOverGlyph: // Nothing to do break; } } return result; }
void Font::drawGlyphBuffer(GraphicsContext* context, const TextRun& run, const GlyphBuffer& glyphBuffer, FloatPoint& point) const { #if !ENABLE(SVG_FONTS) UNUSED_PARAM(run); #endif // Draw each contiguous run of glyphs that use the same font data. const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); FloatSize offset = glyphBuffer.offsetAt(0); FloatPoint startPoint(point.x(), point.y() - glyphBuffer.initialAdvance().height()); float nextX = startPoint.x() + glyphBuffer.advanceAt(0).width(); float nextY = startPoint.y() + glyphBuffer.advanceAt(0).height(); int lastFrom = 0; int nextGlyph = 1; #if ENABLE(SVG_FONTS) TextRun::RenderingContext* renderingContext = run.renderingContext(); #endif while (nextGlyph < glyphBuffer.size()) { const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph); if (nextFontData != fontData || nextOffset != offset) { #if ENABLE(SVG_FONTS) if (renderingContext && fontData->isSVGFont()) renderingContext->drawSVGGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); else #endif drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); lastFrom = nextGlyph; fontData = nextFontData; offset = nextOffset; startPoint.setX(nextX); startPoint.setY(nextY); } nextX += glyphBuffer.advanceAt(nextGlyph).width(); nextY += glyphBuffer.advanceAt(nextGlyph).height(); nextGlyph++; } #if ENABLE(SVG_FONTS) if (renderingContext && fontData->isSVGFont()) renderingContext->drawSVGGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); else { #endif drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); point.setX(nextX); #if ENABLE(SVG_FONTS) } #endif }
float Font::getGlyphsAndAdvancesForComplexText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const { float initialAdvance; ComplexTextController controller(this, run, false, 0, forTextEmphasis); controller.advance(from); float beforeWidth = controller.runWidthSoFar(); controller.advance(to, &glyphBuffer); if (glyphBuffer.isEmpty()) return 0; float afterWidth = controller.runWidthSoFar(); if (run.rtl()) { initialAdvance = controller.totalWidth() - afterWidth; for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end) glyphBuffer.swap(i, end); } else initialAdvance = beforeWidth; return initialAdvance; }
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]); } }
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, 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]); }
SVGGlyphToPathTranslator::SVGGlyphToPathTranslator(const GlyphBuffer& glyphBuffer, const FloatPoint& point, const SVGFontData& svgFontData, SVGFontElement& fontElement, const int from, const int numGlyphs, float scale, bool isVerticalText) : m_glyphBuffer(glyphBuffer) , m_svgFontData(svgFontData) , m_currentPoint(point) , m_glyphOrigin(m_svgFontData.horizontalOriginX() * scale, m_svgFontData.horizontalOriginY() * scale) , m_index(from) , m_glyph(glyphBuffer.glyphAt(m_index)) , m_fontElement(fontElement) , m_stoppingPoint(numGlyphs + from) , m_scale(scale) , m_isVerticalText(isVerticalText) { ASSERT(glyphBuffer.size() > m_index); if (m_glyph) { m_svgGlyph = m_fontElement.svgGlyphForGlyph(m_glyph); ASSERT(!m_svgGlyph.isPartOfLigature); ASSERT(m_svgGlyph.tableEntry == m_glyph); SVGGlyphElement::inheritUnspecifiedAttributes(m_svgGlyph, &m_svgFontData); } moveToNextValidGlyph(); }
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]); }
float Font::getGlyphsAndAdvancesForComplexText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const { float initialAdvance; ComplexTextController controller(this, run, false, 0, forTextEmphasis); controller.advance(from); float beforeWidth = controller.runWidthSoFar(); controller.advance(to, &glyphBuffer); if (glyphBuffer.isEmpty()) return 0; float afterWidth = controller.runWidthSoFar(); if (run.rtl()) { initialAdvance = controller.totalWidth() + controller.finalRoundingWidth() - afterWidth; glyphBuffer.reverse(0, glyphBuffer.size()); } else initialAdvance = beforeWidth; return initialAdvance; }
void Font::drawGlyphBuffer(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const { // Draw each contiguous run of glyphs that use the same font data. const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); FloatPoint startPoint(point); float nextX = startPoint.x() + glyphBuffer.advanceAt(0); unsigned lastFrom = 0; unsigned nextGlyph = 1; #if ENABLE(SVG_FONTS) TextRun::RenderingContext* renderingContext = runInfo.run.renderingContext(); #endif while (nextGlyph < glyphBuffer.size()) { const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); if (nextFontData != fontData) { #if ENABLE(SVG_FONTS) if (renderingContext && fontData->isSVGFont()) renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); else #endif drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds); lastFrom = nextGlyph; fontData = nextFontData; startPoint.setX(nextX); } nextX += glyphBuffer.advanceAt(nextGlyph); nextGlyph++; } #if ENABLE(SVG_FONTS) if (renderingContext && fontData->isSVGFont()) renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); else #endif drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds); }
TEST(GlyphBufferTest, StartsEmpty) { GlyphBuffer glyphBuffer; EXPECT_TRUE(glyphBuffer.isEmpty()); EXPECT_EQ(0u, glyphBuffer.size()); }
void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { graphicsContext->save(); wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext()); wxFont* wxfont = font->getWxFont(); graphicsContext->setFillColor(graphicsContext->fillColor(), DeviceColorSpace); CGContextRef cgContext = static_cast<CGContextRef>(dc->GetGraphicsContext()->GetNativeContext()); CGFontRef cgFont; #ifdef wxOSX_USE_CORE_TEXT && wxOSX_USE_CORE_TEXT cgFont = CTFontCopyGraphicsFont((CTFontRef)wxfont->OSXGetCTFont(), NULL); #else ATSFontRef fontRef; fontRef = FMGetATSFontRefFromFont(wxfont->MacGetATSUFontID()); if (fontRef) cgFont = CGFontCreateWithPlatformFont((void*)&fontRef); #endif CGContextSetFont(cgContext, cgFont); CGContextSetFontSize(cgContext, wxfont->GetPointSize()); CGFloat red, green, blue, alpha; graphicsContext->fillColor().getRGBA(red, green, blue, alpha); CGContextSetRGBFillColor(cgContext, red, green, blue, alpha); CGAffineTransform matrix = CGAffineTransformIdentity; matrix.b = -matrix.b; matrix.d = -matrix.d; CGContextSetTextMatrix(cgContext, matrix); CGContextSetTextPosition(cgContext, point.x(), point.y()); const FloatSize* advanceSizes = static_cast<const FloatSize*>(glyphBuffer.advances(from)); int size = glyphBuffer.size() - from; CGSize sizes[size]; CGGlyph glyphs[numGlyphs]; // if the function doesn't exist, we're probably on tiger and need to grab the // function under its old name, CGFontGetGlyphsForUnicodes if (!CGFontGetGlyphsForUnichars) CGFontGetGlyphsForUnichars = (CGFontGetGlyphsForUnicharsPtr)dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnicodes"); // Let's make sure we got the function under one name or another! ASSERT(CGFontGetGlyphsForUnichars); CGFontGetGlyphsForUnichars(cgFont, glyphBuffer.glyphs(from), glyphs, numGlyphs); for (int i = 0; i < size; i++) { FloatSize fsize = advanceSizes[i]; sizes[i] = CGSizeMake(fsize.width(), fsize.height()); } CGContextShowGlyphsWithAdvances(cgContext, glyphs, sizes, numGlyphs); if (cgFont) CGFontRelease(cgFont); graphicsContext->restore(); }