Changeset 237845 in webkit
- Timestamp:
- Nov 5, 2018 8:35:50 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 17 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/PerformanceTests/ChangeLog
r237442 r237845 1 2018-11-05 Myles C. Maxfield <mmaxfield@apple.com> 2 3 Cache glyph paths and share underline skipping code between all the ports 4 https://bugs.webkit.org/show_bug.cgi?id=191239 5 6 Reviewed by Alex Christensen. 7 8 Measures the performance of drawing a whole lot of underlines 9 10 * Layout/underline.html: Added. 11 1 12 2018-10-25 Saam Barati <sbarati@apple.com> 2 13 -
trunk/Source/WTF/ChangeLog
r237803 r237845 1 2018-11-05 Myles C. Maxfield <mmaxfield@apple.com> 2 3 Cache glyph paths and share underline skipping code between all the ports 4 https://bugs.webkit.org/show_bug.cgi?id=191239 5 6 Reviewed by Alex Christensen. 7 8 Remove CSS3_TEXT_DECORATION_SKIP_INK. It's now interoperable and part of the Web Platform. 9 10 * wtf/Platform.h: 11 1 12 2018-11-05 Dominik Infuehr <dinfuehr@igalia.com> 2 13 -
trunk/Source/WTF/wtf/Platform.h
r237803 r237845 1264 1264 #undef ENABLE_OPENTYPE_VERTICAL 1265 1265 #define ENABLE_OPENTYPE_VERTICAL 1 1266 #define ENABLE_CSS3_TEXT_DECORATION_SKIP_INK 11267 #endif1268 1269 #if PLATFORM(COCOA)1270 #define ENABLE_CSS3_TEXT_DECORATION_SKIP_INK 11271 1266 #endif 1272 1267 -
trunk/Source/WebCore/ChangeLog
r237844 r237845 1 2018-11-05 Myles C. Maxfield <mmaxfield@apple.com> 2 3 Cache glyph paths and share underline skipping code between all the ports 4 https://bugs.webkit.org/show_bug.cgi?id=191239 5 6 Reviewed by Alex Christensen. 7 8 I was hoping that caching the glyph paths was going to be a performance progression, 9 but it turns out that the additional overhead of WebCore::Path compensated for it. 10 In total, the performance is the same (my testing says that this patch is a 1% 11 progression, but that's within the noise). 12 13 Because the ink skipping logic is now shared among all ports, Windows now gets it for 14 free. 15 16 Test: PerformanceTests/Layout/underline.html 17 18 * platform/graphics/Font.cpp: 19 (WebCore::Font::pathForGlyph const): 20 * platform/graphics/Font.h: 21 * platform/graphics/FontCascade.cpp: 22 (WebCore::computeUnderlineType): 23 (WebCore::GlyphIterationState::GlyphIterationState): 24 (WebCore::findIntersectionPoint): 25 (WebCore::updateX): 26 (WebCore::findPathIntersections): 27 (WebCore::GlyphToPathTranslator::GlyphToPathTranslator): 28 (WebCore::GlyphToPathTranslator::containsMorePaths): 29 (WebCore::GlyphToPathTranslator::path): 30 (WebCore::GlyphToPathTranslator::extents): 31 (WebCore::GlyphToPathTranslator::underlineType): 32 (WebCore::GlyphToPathTranslator::advance): 33 (WebCore::FontCascade::dashesForIntersectionsWithRect const): 34 * platform/graphics/FontCascade.h: 35 * platform/graphics/GlyphMetricsMap.h: 36 (WebCore::GlyphMetricsMap::existingMetricsForGlyph): 37 (WebCore::GlyphMetricsMap::GlyphMetricsPage::existingMetricsForGlyph const): 38 (WebCore::GlyphMetricsMap<std::optional<Path>>::unknownMetrics): 39 * platform/graphics/TextRun.h: 40 * platform/graphics/cairo/FontCairo.cpp: 41 (WebCore::Font::platformPathForGlyph const): 42 (WebCore::GlyphIterationState::GlyphIterationState): Deleted. 43 (WebCore::findIntersectionPoint): Deleted. 44 (WebCore::updateX): Deleted. 45 (WebCore::findPathIntersections): Deleted. 46 (): Deleted. 47 (WebCore::CairoGlyphToPathTranslator::path): Deleted. 48 (WebCore::CairoGlyphToPathTranslator::extents): Deleted. 49 (WebCore::CairoGlyphToPathTranslator::underlineType): Deleted. 50 (WebCore::CairoGlyphToPathTranslator::advance): Deleted. 51 (WebCore::FontCascade::dashesForIntersectionsWithRect const): Deleted. 52 * platform/graphics/cocoa/FontCascadeCocoa.mm: 53 (WebCore::GlyphIterationState::GlyphIterationState): Deleted. 54 (WebCore::findIntersectionPoint): Deleted. 55 (WebCore::updateX): Deleted. 56 (WebCore::findPathIntersections): Deleted. 57 (): Deleted. 58 (WebCore::MacGlyphToPathTranslator::path): Deleted. 59 (WebCore::MacGlyphToPathTranslator::extents): Deleted. 60 (WebCore::MacGlyphToPathTranslator::underlineType): Deleted. 61 (WebCore::MacGlyphToPathTranslator::advance): Deleted. 62 (WebCore::FontCascade::dashesForIntersectionsWithRect const): Deleted. 63 * platform/graphics/cocoa/FontCocoa.mm: 64 (WebCore::Font::platformPathForGlyph const): 65 * rendering/TextDecorationPainter.cpp: 66 (WebCore::drawSkipInkUnderline): 67 (WebCore::TextDecorationPainter::paintTextDecoration): 68 1 69 2018-11-05 Myles C. Maxfield <mmaxfield@apple.com> 2 70 -
trunk/Source/WebCore/PAL/pal/spi/win/CoreTextSPIWin.h
r220809 r237845 58 58 CFDataRef CTFontCopyTable(CTFontRef, CTFontTableTag, CTFontTableOptions); 59 59 CFArrayRef CTFontCopyAvailableTables(CTFontRef, CTFontTableOptions); 60 CGPathRef CTFontCreatePathForGlyph(CTFontRef, CGGlyph, const CGAffineTransform*); 60 61 61 62 WTF_EXTERN_C_END -
trunk/Source/WebCore/platform/graphics/Font.cpp
r237487 r237845 664 664 return true; 665 665 } 666 667 // Don't store the result of this! The hash map is free to rehash at any point, leaving this reference dangling. 668 const Path& Font::pathForGlyph(Glyph glyph) const 669 { 670 if (const auto& path = m_glyphPathMap.existingMetricsForGlyph(glyph)) 671 return *path; 672 auto path = platformPathForGlyph(glyph); 673 m_glyphPathMap.setMetricsForGlyph(glyph, path); 674 return *m_glyphPathMap.existingMetricsForGlyph(glyph); 675 } 676 666 677 } // namespace WebCore -
trunk/Source/WebCore/platform/graphics/Font.h
r237487 r237845 147 147 FloatRect boundsForGlyph(Glyph) const; 148 148 float widthForGlyph(Glyph) const; 149 const Path& pathForGlyph(Glyph) const; // Don't store the result of this! The hash map is free to rehash at any point, leaving this reference dangling. 149 150 FloatRect platformBoundsForGlyph(Glyph) const; 150 151 float platformWidthForGlyph(Glyph) const; 152 Path platformPathForGlyph(Glyph) const; 151 153 152 154 float spaceWidth() const { return m_spaceWidth; } … … 254 256 mutable std::unique_ptr<GlyphMetricsMap<FloatRect>> m_glyphToBoundsMap; 255 257 mutable GlyphMetricsMap<float> m_glyphToWidthMap; 258 mutable GlyphMetricsMap<std::optional<Path>> m_glyphPathMap; 256 259 mutable BitVector m_codePointSupport; 257 260 -
trunk/Source/WebCore/platform/graphics/FontCascade.cpp
r237463 r237845 1238 1238 return m_fonts && m_fonts->isLoadingCustomFonts(); 1239 1239 } 1240 1241 enum class GlyphUnderlineType : uint8_t { 1242 SkipDescenders, 1243 SkipGlyph, 1244 DrawOverGlyph 1245 }; 1240 1246 1241 GlyphToPathTranslator::GlyphUnderlineType computeUnderlineType(const TextRun& textRun, const GlyphBuffer& glyphBuffer, unsigned index)1247 static GlyphUnderlineType computeUnderlineType(const TextRun& textRun, const GlyphBuffer& glyphBuffer, unsigned index) 1242 1248 { 1243 1249 // In general, we want to skip descenders. However, skipping descenders on CJK characters leads to undesirable renderings, 1244 1250 // so we want to draw through CJK characters (on a character-by-character basis). 1251 // FIXME: The CSS spec says this should instead be done by the user-agent stylesheet using the lang= attribute. 1245 1252 UChar32 baseCharacter; 1246 1253 unsigned offsetInString = glyphBuffer.offsetInString(index); … … 1249 1256 // We have no idea which character spawned this glyph. Bail. 1250 1257 ASSERT_WITH_SECURITY_IMPLICATION(offsetInString < textRun.length()); 1251 return Glyph ToPathTranslator::GlyphUnderlineType::DrawOverGlyph;1258 return GlyphUnderlineType::DrawOverGlyph; 1252 1259 } 1253 1260 … … 1286 1293 case UBLOCK_HANGUL_JAMO_EXTENDED_A: 1287 1294 case UBLOCK_HANGUL_JAMO_EXTENDED_B: 1288 return Glyph ToPathTranslator::GlyphUnderlineType::DrawOverGlyph;1295 return GlyphUnderlineType::DrawOverGlyph; 1289 1296 default: 1290 return Glyph ToPathTranslator::GlyphUnderlineType::SkipDescenders;1297 return GlyphUnderlineType::SkipDescenders; 1291 1298 } 1292 1299 } … … 1659 1666 } 1660 1667 1661 } 1668 struct GlyphIterationState { 1669 FloatPoint startingPoint; 1670 FloatPoint currentPoint; 1671 float y1; 1672 float y2; 1673 float minX; 1674 float maxX; 1675 }; 1676 1677 static std::optional<float> findIntersectionPoint(float y, FloatPoint p1, FloatPoint p2) 1678 { 1679 if ((p1.y() < y && p2.y() > y) || (p1.y() > y && p2.y() < y)) 1680 return p1.x() + (y - p1.y()) * (p2.x() - p1.x()) / (p2.y() - p1.y()); 1681 return std::nullopt; 1682 } 1683 1684 static void updateX(GlyphIterationState& state, float x) 1685 { 1686 state.minX = std::min(state.minX, x); 1687 state.maxX = std::max(state.maxX, x); 1688 } 1689 1690 // This function is called by CGPathApply and is therefore invoked for each 1691 // contour in a glyph. This function models each contours as a straight line 1692 // and calculates the intersections between each pseudo-contour and 1693 // two horizontal lines (the upper and lower bounds of an underline) found in 1694 // GlyphIterationState::y1 and GlyphIterationState::y2. It keeps track of the 1695 // leftmost and rightmost intersection in GlyphIterationState::minX and 1696 // GlyphIterationState::maxX. 1697 static void findPathIntersections(GlyphIterationState& state, const PathElement& element) 1698 { 1699 bool doIntersection = false; 1700 FloatPoint point = FloatPoint(); 1701 switch (element.type) { 1702 case PathElementMoveToPoint: 1703 state.startingPoint = element.points[0]; 1704 state.currentPoint = element.points[0]; 1705 break; 1706 case PathElementAddLineToPoint: 1707 doIntersection = true; 1708 point = element.points[0]; 1709 break; 1710 case PathElementAddQuadCurveToPoint: 1711 doIntersection = true; 1712 point = element.points[1]; 1713 break; 1714 case PathElementAddCurveToPoint: 1715 doIntersection = true; 1716 point = element.points[2]; 1717 break; 1718 case PathElementCloseSubpath: 1719 doIntersection = true; 1720 point = state.startingPoint; 1721 break; 1722 } 1723 if (!doIntersection) 1724 return; 1725 if (auto intersectionPoint = findIntersectionPoint(state.y1, state.currentPoint, point)) 1726 updateX(state, *intersectionPoint); 1727 if (auto intersectionPoint = findIntersectionPoint(state.y2, state.currentPoint, point)) 1728 updateX(state, *intersectionPoint); 1729 if ((state.currentPoint.y() >= state.y1 && state.currentPoint.y() <= state.y2) 1730 || (state.currentPoint.y() <= state.y1 && state.currentPoint.y() >= state.y2)) 1731 updateX(state, state.currentPoint.x()); 1732 state.currentPoint = point; 1733 } 1734 1735 class GlyphToPathTranslator { 1736 public: 1737 GlyphToPathTranslator(const TextRun& textRun, const GlyphBuffer& glyphBuffer, const FloatPoint& textOrigin) 1738 : m_index(0) 1739 , m_textRun(textRun) 1740 , m_glyphBuffer(glyphBuffer) 1741 , m_fontData(glyphBuffer.fontAt(m_index)) 1742 , m_translation(AffineTransform::translation(textOrigin.x(), textOrigin.y()).scale(1, -1)) 1743 { 1744 } 1745 1746 bool containsMorePaths() { return m_index != m_glyphBuffer.size(); } 1747 Path path(); 1748 std::pair<float, float> extents(); 1749 GlyphUnderlineType underlineType(); 1750 void advance(); 1751 1752 private: 1753 unsigned m_index; 1754 const TextRun& m_textRun; 1755 const GlyphBuffer& m_glyphBuffer; 1756 const Font* m_fontData; 1757 AffineTransform m_translation; 1758 }; 1759 1760 Path GlyphToPathTranslator::path() 1761 { 1762 Path path = m_fontData->pathForGlyph(m_glyphBuffer.glyphAt(m_index)); 1763 path.transform(m_translation); 1764 return path; 1765 } 1766 1767 std::pair<float, float> GlyphToPathTranslator::extents() 1768 { 1769 auto beginning = m_translation.mapPoint(FloatPoint(0, 0)); 1770 auto advance = m_glyphBuffer.advanceAt(m_index); 1771 auto end = m_translation.mapSize(FloatSize(advance.width(), advance.height())); 1772 return std::make_pair(beginning.x(), beginning.x() + end.width()); 1773 } 1774 1775 auto GlyphToPathTranslator::underlineType() -> GlyphUnderlineType 1776 { 1777 return computeUnderlineType(m_textRun, m_glyphBuffer, m_index); 1778 } 1779 1780 void GlyphToPathTranslator::advance() 1781 { 1782 GlyphBufferAdvance advance = m_glyphBuffer.advanceAt(m_index); 1783 m_translation.translate(FloatSize(advance.width(), advance.height())); 1784 ++m_index; 1785 if (m_index < m_glyphBuffer.size()) 1786 m_fontData = m_glyphBuffer.fontAt(m_index); 1787 } 1788 1789 DashArray FontCascade::dashesForIntersectionsWithRect(const TextRun& run, const FloatPoint& textOrigin, const FloatRect& lineExtents) const 1790 { 1791 if (isLoadingCustomFonts()) 1792 return DashArray(); 1793 1794 GlyphBuffer glyphBuffer; 1795 glyphBuffer.saveOffsetsInString(); 1796 float deltaX; 1797 if (codePath(run) != FontCascade::Complex) 1798 deltaX = getGlyphsAndAdvancesForSimpleText(run, 0, run.length(), glyphBuffer); 1799 else 1800 deltaX = getGlyphsAndAdvancesForComplexText(run, 0, run.length(), glyphBuffer); 1801 1802 if (!glyphBuffer.size()) 1803 return DashArray(); 1804 1805 FloatPoint origin = FloatPoint(textOrigin.x() + deltaX, textOrigin.y()); 1806 GlyphToPathTranslator translator(run, glyphBuffer, origin); 1807 DashArray result; 1808 for (unsigned index = 0; translator.containsMorePaths(); ++index, translator.advance()) { 1809 GlyphIterationState info = { FloatPoint(0, 0), FloatPoint(0, 0), lineExtents.y(), lineExtents.y() + lineExtents.height(), lineExtents.x() + lineExtents.width(), lineExtents.x() }; 1810 const Font* localFont = glyphBuffer.fontAt(index); 1811 if (!localFont) { 1812 // The advances will get all messed up if we do anything other than bail here. 1813 result.clear(); 1814 break; 1815 } 1816 switch (translator.underlineType()) { 1817 case GlyphUnderlineType::SkipDescenders: { 1818 Path path = translator.path(); 1819 path.apply([&](const PathElement& element) { 1820 findPathIntersections(info, element); 1821 }); 1822 if (info.minX < info.maxX) { 1823 result.append(info.minX - lineExtents.x()); 1824 result.append(info.maxX - lineExtents.x()); 1825 } 1826 break; 1827 } 1828 case GlyphUnderlineType::SkipGlyph: { 1829 std::pair<float, float> extents = translator.extents(); 1830 result.append(extents.first - lineExtents.x()); 1831 result.append(extents.second - lineExtents.x()); 1832 break; 1833 } 1834 case GlyphUnderlineType::DrawOverGlyph: 1835 // Nothing to do 1836 break; 1837 } 1838 } 1839 return result; 1840 } 1841 1842 } -
trunk/Source/WebCore/platform/graphics/FontCascade.h
r237813 r237845 82 82 }; 83 83 84 class GlyphToPathTranslator {85 public:86 enum class GlyphUnderlineType {SkipDescenders, SkipGlyph, DrawOverGlyph};87 virtual bool containsMorePaths() = 0;88 virtual Path path() = 0;89 virtual std::pair<float, float> extents() = 0;90 virtual GlyphUnderlineType underlineType() = 0;91 virtual void advance() = 0;92 virtual ~GlyphToPathTranslator() = default;93 };94 GlyphToPathTranslator::GlyphUnderlineType computeUnderlineType(const TextRun&, const GlyphBuffer&, unsigned index);95 96 84 class TextLayoutDeleter { 97 85 public: -
trunk/Source/WebCore/platform/graphics/GlyphMetricsMap.h
r205703 r237845 31 31 32 32 #include "Glyph.h" 33 #include "Path.h" 33 34 #include <array> 34 35 #include <wtf/HashMap.h> … … 44 45 { 45 46 return locatePage(glyph / GlyphMetricsPage::size).metricsForGlyph(glyph); 47 } 48 49 const T& existingMetricsForGlyph(Glyph glyph) 50 { 51 return locatePage(glyph / GlyphMetricsPage::size).existingMetricsForGlyph(glyph); 46 52 } 47 53 … … 69 75 70 76 T metricsForGlyph(Glyph glyph) const { return m_metrics[glyph % size]; } 77 const T& existingMetricsForGlyph(Glyph glyph) const { return m_metrics[glyph % size]; } 71 78 void setMetricsForGlyph(Glyph glyph, const T& metrics) 72 79 { … … 109 116 } 110 117 118 template<> inline std::optional<Path> GlyphMetricsMap<std::optional<Path>>::unknownMetrics() 119 { 120 return std::nullopt; 121 } 122 111 123 template<class T> typename GlyphMetricsMap<T>::GlyphMetricsPage& GlyphMetricsMap<T>::locatePageSlowCase(unsigned pageNumber) 112 124 { -
trunk/Source/WebCore/platform/graphics/TextRun.h
r235721 r237845 36 36 class GraphicsContext; 37 37 class GlyphBuffer; 38 class GlyphToPathTranslator;39 38 class Font; 40 39 -
trunk/Source/WebCore/platform/graphics/cairo/FontCairo.cpp
r235521 r237845 79 79 } 80 80 81 #if ENABLE(CSS3_TEXT_DECORATION_SKIP_INK) 82 struct GlyphIterationState { 83 GlyphIterationState(FloatPoint startingPoint, FloatPoint currentPoint, float centerOfLine, float minX, float maxX) 84 : startingPoint(startingPoint) 85 , currentPoint(currentPoint) 86 , centerOfLine(centerOfLine) 87 , minX(minX) 88 , maxX(maxX) 89 { 90 } 91 FloatPoint startingPoint; 92 FloatPoint currentPoint; 93 float centerOfLine; 94 float minX; 95 float maxX; 96 }; 97 98 static bool findIntersectionPoint(float y, FloatPoint p1, FloatPoint p2, float& x) 99 { 100 x = p1.x() + (y - p1.y()) * (p2.x() - p1.x()) / (p2.y() - p1.y()); 101 return (p1.y() < y && p2.y() > y) || (p1.y() > y && p2.y() < y); 102 } 103 104 static void updateX(GlyphIterationState& state, float x) 105 { 106 state.minX = std::min(state.minX, x); 107 state.maxX = std::max(state.maxX, x); 108 } 109 110 // This function is called by Path::apply and is therefore invoked for each contour in a glyph. This 111 // function models each contours as a straight line and calculates the intersections between each 112 // pseudo-contour and the vertical center of the underline found in GlyphIterationState::centerOfLine. 113 // It keeps track of the leftmost and rightmost intersection in GlyphIterationState::minX and 114 // GlyphIterationState::maxX. 115 static void findPathIntersections(GlyphIterationState& state, const PathElement& element) 116 { 117 bool doIntersection = false; 118 FloatPoint point = FloatPoint(); 119 switch (element.type) { 120 case PathElementMoveToPoint: 121 state.startingPoint = element.points[0]; 122 state.currentPoint = element.points[0]; 123 break; 124 case PathElementAddLineToPoint: 125 doIntersection = true; 126 point = element.points[0]; 127 break; 128 case PathElementAddQuadCurveToPoint: 129 doIntersection = true; 130 point = element.points[1]; 131 break; 132 case PathElementAddCurveToPoint: 133 doIntersection = true; 134 point = element.points[2]; 135 break; 136 case PathElementCloseSubpath: 137 doIntersection = true; 138 point = state.startingPoint; 139 break; 140 } 141 142 if (!doIntersection) 143 return; 144 145 float x; 146 if (findIntersectionPoint(state.centerOfLine, state.currentPoint, point, x)) 147 updateX(state, x); 148 149 state.currentPoint = point; 150 } 151 152 class CairoGlyphToPathTranslator final : public GlyphToPathTranslator { 153 public: 154 CairoGlyphToPathTranslator(const TextRun& textRun, const GlyphBuffer& glyphBuffer, const FloatPoint& textOrigin) 155 : m_index(0) 156 , m_textRun(textRun) 157 , m_glyphBuffer(glyphBuffer) 158 , m_fontData(glyphBuffer.fontAt(m_index)) 159 , m_translation(AffineTransform().translate(textOrigin.x(), textOrigin.y())) 160 { 161 } 162 163 bool containsMorePaths() final { return m_index != m_glyphBuffer.size(); } 164 Path path() final; 165 std::pair<float, float> extents() final; 166 GlyphUnderlineType underlineType() final; 167 void advance() final; 168 169 private: 170 unsigned m_index; 171 const TextRun& m_textRun; 172 const GlyphBuffer& m_glyphBuffer; 173 const Font* m_fontData; 174 AffineTransform m_translation; 175 }; 176 177 Path CairoGlyphToPathTranslator::path() 81 Path Font::platformPathForGlyph(Glyph glyph) const 178 82 { 179 83 Path path; 180 84 path.ensurePlatformPath(); 181 85 182 cairo_glyph_t cairoGlyph = { m_glyphBuffer.glyphAt(m_index), 0, 0 };183 cairo_set_scaled_font(path.platformPath()->context(), m_fontData->platformData().scaledFont());86 cairo_glyph_t cairoGlyph = { glyph, 0, 0 }; 87 cairo_set_scaled_font(path.platformPath()->context(), platformData().scaledFont()); 184 88 cairo_glyph_path(path.platformPath()->context(), &cairoGlyph, 1); 185 89 186 float syntheticBoldOffset = m_fontData->syntheticBoldOffset();90 float syntheticBoldOffset = this->syntheticBoldOffset(); 187 91 if (syntheticBoldOffset) { 188 92 cairo_translate(path.platformPath()->context(), syntheticBoldOffset, 0); 189 93 cairo_glyph_path(path.platformPath()->context(), &cairoGlyph, 1); 190 94 } 191 192 path.transform(m_translation);193 95 return path; 194 96 } 195 196 std::pair<float, float> CairoGlyphToPathTranslator::extents()197 {198 FloatPoint beginning = m_translation.mapPoint(FloatPoint());199 FloatSize end = m_translation.mapSize(m_glyphBuffer.advanceAt(m_index));200 return std::make_pair(static_cast<float>(beginning.x()), static_cast<float>(beginning.x() + end.width()));201 }202 203 GlyphToPathTranslator::GlyphUnderlineType CairoGlyphToPathTranslator::underlineType()204 {205 return computeUnderlineType(m_textRun, m_glyphBuffer, m_index);206 }207 208 void CairoGlyphToPathTranslator::advance()209 {210 GlyphBufferAdvance advance = m_glyphBuffer.advanceAt(m_index);211 m_translation = m_translation.translate(advance.width(), advance.height());212 ++m_index;213 if (m_index < m_glyphBuffer.size())214 m_fontData = m_glyphBuffer.fontAt(m_index);215 }216 217 DashArray FontCascade::dashesForIntersectionsWithRect(const TextRun& run, const FloatPoint& textOrigin, const FloatRect& lineExtents) const218 {219 if (isLoadingCustomFonts())220 return DashArray();221 222 GlyphBuffer glyphBuffer;223 glyphBuffer.saveOffsetsInString();224 float deltaX;225 if (codePath(run) != FontCascade::Complex)226 deltaX = getGlyphsAndAdvancesForSimpleText(run, 0, run.length(), glyphBuffer);227 else228 deltaX = getGlyphsAndAdvancesForComplexText(run, 0, run.length(), glyphBuffer);229 230 if (!glyphBuffer.size())231 return DashArray();232 233 // FIXME: Handle SVG + non-SVG interleaved runs. https://bugs.webkit.org/show_bug.cgi?id=133778234 FloatPoint origin = FloatPoint(textOrigin.x() + deltaX, textOrigin.y());235 CairoGlyphToPathTranslator translator(run, glyphBuffer, origin);236 DashArray result;237 for (int index = 0; translator.containsMorePaths(); ++index, translator.advance()) {238 float centerOfLine = lineExtents.y() + (lineExtents.height() / 2);239 GlyphIterationState info = GlyphIterationState(FloatPoint(), FloatPoint(), centerOfLine, lineExtents.x() + lineExtents.width(), lineExtents.x());240 const Font* localFontData = glyphBuffer.fontAt(index);241 if (!localFontData) {242 // The advances will get all messed up if we do anything other than bail here.243 result.clear();244 break;245 }246 switch (translator.underlineType()) {247 case GlyphToPathTranslator::GlyphUnderlineType::SkipDescenders: {248 Path path = translator.path();249 path.apply([&info](const PathElement& pathElement) {250 findPathIntersections(info, pathElement);251 });252 if (info.minX < info.maxX) {253 result.append(info.minX - lineExtents.x());254 result.append(info.maxX - lineExtents.x());255 }256 break;257 }258 case GlyphToPathTranslator::GlyphUnderlineType::SkipGlyph: {259 std::pair<float, float> extents = translator.extents();260 result.append(extents.first - lineExtents.x());261 result.append(extents.second - lineExtents.x());262 break;263 }264 case GlyphToPathTranslator::GlyphUnderlineType::DrawOverGlyph:265 // Nothing to do266 break;267 }268 }269 return result;270 }271 #endif // ENABLE(CSS3_TEXT_DECORATION_SKIP_INK)272 97 273 98 } // namespace WebCore -
trunk/Source/WebCore/platform/graphics/cocoa/FontCascadeCocoa.mm
r237765 r237845 304 304 } 305 305 306 #if ENABLE(CSS3_TEXT_DECORATION_SKIP_INK)307 struct GlyphIterationState {308 GlyphIterationState(CGPoint startingPoint, CGPoint currentPoint, CGFloat y1, CGFloat y2, CGFloat minX, CGFloat maxX)309 : startingPoint(startingPoint)310 , currentPoint(currentPoint)311 , y1(y1)312 , y2(y2)313 , minX(minX)314 , maxX(maxX)315 {316 }317 CGPoint startingPoint;318 CGPoint currentPoint;319 CGFloat y1;320 CGFloat y2;321 CGFloat minX;322 CGFloat maxX;323 };324 325 static bool findIntersectionPoint(float y, CGPoint p1, CGPoint p2, CGFloat& x)326 {327 x = p1.x + (y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y);328 return (p1.y < y && p2.y > y) || (p1.y > y && p2.y < y);329 }330 331 static void updateX(GlyphIterationState& state, CGFloat x)332 {333 state.minX = std::min(state.minX, x);334 state.maxX = std::max(state.maxX, x);335 }336 337 // This function is called by CGPathApply and is therefore invoked for each338 // contour in a glyph. This function models each contours as a straight line339 // and calculates the intersections between each pseudo-contour and340 // two horizontal lines (the upper and lower bounds of an underline) found in341 // GlyphIterationState::y1 and GlyphIterationState::y2. It keeps track of the342 // leftmost and rightmost intersection in GlyphIterationState::minX and343 // GlyphIterationState::maxX.344 static void findPathIntersections(void* stateAsVoidPointer, const CGPathElement* e)345 {346 auto& state = *static_cast<GlyphIterationState*>(stateAsVoidPointer);347 bool doIntersection = false;348 CGPoint point = CGPointZero;349 switch (e->type) {350 case kCGPathElementMoveToPoint:351 state.startingPoint = e->points[0];352 state.currentPoint = e->points[0];353 break;354 case kCGPathElementAddLineToPoint:355 doIntersection = true;356 point = e->points[0];357 break;358 case kCGPathElementAddQuadCurveToPoint:359 doIntersection = true;360 point = e->points[1];361 break;362 case kCGPathElementAddCurveToPoint:363 doIntersection = true;364 point = e->points[2];365 break;366 case kCGPathElementCloseSubpath:367 doIntersection = true;368 point = state.startingPoint;369 break;370 }371 if (!doIntersection)372 return;373 CGFloat x;374 if (findIntersectionPoint(state.y1, state.currentPoint, point, x))375 updateX(state, x);376 if (findIntersectionPoint(state.y2, state.currentPoint, point, x))377 updateX(state, x);378 if ((state.currentPoint.y >= state.y1 && state.currentPoint.y <= state.y2)379 || (state.currentPoint.y <= state.y1 && state.currentPoint.y >= state.y2))380 updateX(state, state.currentPoint.x);381 state.currentPoint = point;382 }383 384 class MacGlyphToPathTranslator final : public GlyphToPathTranslator {385 public:386 MacGlyphToPathTranslator(const TextRun& textRun, const GlyphBuffer& glyphBuffer, const FloatPoint& textOrigin)387 : m_index(0)388 , m_textRun(textRun)389 , m_glyphBuffer(glyphBuffer)390 , m_fontData(glyphBuffer.fontAt(m_index))391 , m_translation(CGAffineTransformScale(CGAffineTransformMakeTranslation(textOrigin.x(), textOrigin.y()), 1, -1))392 {393 }394 bool containsMorePaths() final { return m_index != m_glyphBuffer.size(); }395 Path path() final;396 std::pair<float, float> extents() final;397 GlyphUnderlineType underlineType() final;398 void advance() final;399 400 private:401 unsigned m_index;402 const TextRun& m_textRun;403 const GlyphBuffer& m_glyphBuffer;404 const Font* m_fontData;405 CGAffineTransform m_translation;406 };407 408 Path MacGlyphToPathTranslator::path()409 {410 RetainPtr<CGPathRef> result = adoptCF(CTFontCreatePathForGlyph(m_fontData->platformData().ctFont(), m_glyphBuffer.glyphAt(m_index), &m_translation));411 return adoptCF(CGPathCreateMutableCopy(result.get()));412 }413 414 std::pair<float, float> MacGlyphToPathTranslator::extents()415 {416 CGPoint beginning = CGPointApplyAffineTransform(CGPointMake(0, 0), m_translation);417 CGSize end = CGSizeApplyAffineTransform(m_glyphBuffer.advanceAt(m_index), m_translation);418 return std::make_pair(static_cast<float>(beginning.x), static_cast<float>(beginning.x + end.width));419 }420 421 auto MacGlyphToPathTranslator::underlineType() -> GlyphUnderlineType422 {423 return computeUnderlineType(m_textRun, m_glyphBuffer, m_index);424 }425 426 void MacGlyphToPathTranslator::advance()427 {428 GlyphBufferAdvance advance = m_glyphBuffer.advanceAt(m_index);429 m_translation = CGAffineTransformTranslate(m_translation, advance.width(), advance.height());430 ++m_index;431 if (m_index < m_glyphBuffer.size())432 m_fontData = m_glyphBuffer.fontAt(m_index);433 }434 435 DashArray FontCascade::dashesForIntersectionsWithRect(const TextRun& run, const FloatPoint& textOrigin, const FloatRect& lineExtents) const436 {437 if (isLoadingCustomFonts())438 return DashArray();439 440 GlyphBuffer glyphBuffer;441 glyphBuffer.saveOffsetsInString();442 float deltaX;443 if (codePath(run) != FontCascade::Complex)444 deltaX = getGlyphsAndAdvancesForSimpleText(run, 0, run.length(), glyphBuffer);445 else446 deltaX = getGlyphsAndAdvancesForComplexText(run, 0, run.length(), glyphBuffer);447 448 if (!glyphBuffer.size())449 return DashArray();450 451 // FIXME: Handle SVG + non-SVG interleaved runs. https://bugs.webkit.org/show_bug.cgi?id=133778452 FloatPoint origin = FloatPoint(textOrigin.x() + deltaX, textOrigin.y());453 MacGlyphToPathTranslator translator(run, glyphBuffer, origin);454 DashArray result;455 for (unsigned index = 0; translator.containsMorePaths(); ++index, translator.advance()) {456 GlyphIterationState info = GlyphIterationState(CGPointMake(0, 0), CGPointMake(0, 0), lineExtents.y(), lineExtents.y() + lineExtents.height(), lineExtents.x() + lineExtents.width(), lineExtents.x());457 const Font* localFont = glyphBuffer.fontAt(index);458 if (!localFont) {459 // The advances will get all messed up if we do anything other than bail here.460 result.clear();461 break;462 }463 switch (translator.underlineType()) {464 case GlyphToPathTranslator::GlyphUnderlineType::SkipDescenders: {465 Path path = translator.path();466 CGPathApply(path.platformPath(), &info, &findPathIntersections);467 if (info.minX < info.maxX) {468 result.append(info.minX - lineExtents.x());469 result.append(info.maxX - lineExtents.x());470 }471 break;472 }473 case GlyphToPathTranslator::GlyphUnderlineType::SkipGlyph: {474 std::pair<float, float> extents = translator.extents();475 result.append(extents.first - lineExtents.x());476 result.append(extents.second - lineExtents.x());477 break;478 }479 case GlyphToPathTranslator::GlyphUnderlineType::DrawOverGlyph:480 // Nothing to do481 break;482 }483 }484 return result;485 }486 #endif487 488 306 bool FontCascade::primaryFontIsSystemFont() const 489 307 { -
trunk/Source/WebCore/platform/graphics/cocoa/FontCocoa.mm
r237266 r237845 598 598 } 599 599 600 Path Font::platformPathForGlyph(Glyph glyph) const 601 { 602 auto result = adoptCF(CTFontCreatePathForGlyph(platformData().ctFont(), glyph, nullptr)); 603 auto syntheticBoldOffset = this->syntheticBoldOffset(); 604 if (syntheticBoldOffset) { 605 auto newPath = adoptCF(CGPathCreateMutable()); 606 CGPathAddPath(newPath.get(), nullptr, result.get()); 607 auto translation = CGAffineTransformMakeTranslation(syntheticBoldOffset, 0); 608 CGPathAddPath(newPath.get(), &translation, result.get()); 609 return newPath; 610 } 611 return adoptCF(CGPathCreateMutableCopy(result.get())); 612 } 613 600 614 bool Font::platformSupportsCodePoint(UChar32 character) const 601 615 { -
trunk/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
r229400 r237845 153 153 } 154 154 155 Path Font::platformPathForGlyph(Glyph glyph) const 156 { 157 auto ctFont = adoptCF(CTFontCreateWithGraphicsFont(platformData().cgFont(), platformData().size(), nullptr, nullptr)); 158 auto result = adoptCF(CTFontCreatePathForGlyph(ctFont.get(), glyph, nullptr)); 159 auto syntheticBoldOffset = this->syntheticBoldOffset(); 160 if (syntheticBoldOffset) { 161 auto newPath = adoptCF(CGPathCreateMutable()); 162 CGPathAddPath(newPath.get(), nullptr, result.get()); 163 auto translation = CGAffineTransformMakeTranslation(syntheticBoldOffset, 0); 164 CGPathAddPath(newPath.get(), &translation, result.get()); 165 return newPath; 166 } 167 return adoptCF(CGPathCreateMutableCopy(result.get())); 168 } 169 155 170 } 156 171 -
trunk/Source/WebCore/platform/graphics/win/SimpleFontDataDirect2D.cpp
r233851 r237845 35 35 #include "GraphicsContext.h" 36 36 #include "HWndDC.h" 37 #include "NotImplemented.h" 37 38 #include <comutil.h> 38 39 #include <dwrite.h> … … 231 232 } 232 233 234 Path Font::platformPathForGlyph(Glyph) const 235 { 236 notImplemented(); 237 return Path(); 238 } 239 233 240 } 234 241 -
trunk/Source/WebCore/rendering/TextDecorationPainter.cpp
r237844 r237845 117 117 } 118 118 119 #if ENABLE(CSS3_TEXT_DECORATION_SKIP_INK)120 119 static bool compareTuples(std::pair<float, float> l, std::pair<float, float> r) 121 120 { … … 168 167 return result; 169 168 } 170 #endif171 169 172 170 static StrokeStyle textDecorationStyleToStrokeStyle(TextDecorationStyle decorationStyle) … … 213 211 void TextDecorationPainter::paintTextDecoration(const TextRun& textRun, const FloatPoint& textOrigin, const FloatPoint& boxOrigin) 214 212 { 215 #if !ENABLE(CSS3_TEXT_DECORATION_SKIP_INK)216 UNUSED_PARAM(textRun);217 UNUSED_PARAM(textOrigin);218 #endif219 213 const auto& fontMetrics = m_lineStyle.fontMetrics(); 220 214 float textDecorationThickness = textDecorationStrokeThickness(m_lineStyle.computedFontPixelSize()); … … 229 223 strokeWavyTextDecoration(m_context, rect, m_lineStyle.computedFontPixelSize()); 230 224 else if (decoration == TextDecoration::Underline || decoration == TextDecoration::Overline) { 231 #if ENABLE(CSS3_TEXT_DECORATION_SKIP_INK)232 225 if ((m_lineStyle.textDecorationSkip() == TextDecorationSkip::Ink || m_lineStyle.textDecorationSkip() == TextDecorationSkip::Auto) && m_isHorizontal) { 233 226 if (!m_context.paintingDisabled()) { … … 239 232 m_context.drawLinesForText(rect.location(), rect.height(), boundaries, m_isPrinting, style == TextDecorationStyle::Double, strokeStyle); 240 233 } 241 } else 234 } else { 242 235 // FIXME: Need to support text-decoration-skip: none. 243 #endif244 236 m_context.drawLineForText(rect, m_isPrinting, style == TextDecorationStyle::Double, strokeStyle); 245 237 } 246 238 } else { 247 239 ASSERT(decoration == TextDecoration::LineThrough);
Note: See TracChangeset
for help on using the changeset viewer.