OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 #define __STDC_LIMIT_MACROS | 7 #define __STDC_LIMIT_MACROS |
8 | 8 |
9 #include "SkDraw.h" | 9 #include "SkDraw.h" |
10 #include "SkBlitter.h" | 10 #include "SkBlitter.h" |
11 #include "SkCanvas.h" | 11 #include "SkCanvas.h" |
12 #include "SkColorPriv.h" | 12 #include "SkColorPriv.h" |
13 #include "SkDevice.h" | 13 #include "SkDevice.h" |
14 #include "SkDeviceLooper.h" | 14 #include "SkDeviceLooper.h" |
| 15 #include "SkFindAndPlaceGlyph.h" |
15 #include "SkFixed.h" | 16 #include "SkFixed.h" |
16 #include "SkMaskFilter.h" | 17 #include "SkMaskFilter.h" |
17 #include "SkMatrix.h" | 18 #include "SkMatrix.h" |
18 #include "SkPaint.h" | 19 #include "SkPaint.h" |
19 #include "SkPathEffect.h" | 20 #include "SkPathEffect.h" |
20 #include "SkRasterClip.h" | 21 #include "SkRasterClip.h" |
21 #include "SkRasterizer.h" | 22 #include "SkRasterizer.h" |
22 #include "SkRRect.h" | 23 #include "SkRRect.h" |
23 #include "SkScan.h" | 24 #include "SkScan.h" |
24 #include "SkShader.h" | 25 #include "SkShader.h" |
(...skipping 1697 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1722 fDevice->drawPath(*this, *path, paint, &matrix, false); | 1723 fDevice->drawPath(*this, *path, paint, &matrix, false); |
1723 } else { | 1724 } else { |
1724 this->drawPath(*path, paint, &matrix, false); | 1725 this->drawPath(*path, paint, &matrix, false); |
1725 } | 1726 } |
1726 } | 1727 } |
1727 } | 1728 } |
1728 pos += scalarsPerPosition; | 1729 pos += scalarsPerPosition; |
1729 } | 1730 } |
1730 } | 1731 } |
1731 | 1732 |
1732 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | |
1733 // Calculate a type with the same size as the max of all the Ts. | |
1734 template <typename... Ts> struct MaxSizeOf; | |
1735 | |
1736 template <> struct MaxSizeOf<> { static const size_t value = 0; }; | |
1737 | |
1738 template <typename H, typename... Ts> struct MaxSizeOf<H, Ts...> { | |
1739 static const size_t value = | |
1740 sizeof(H) >= MaxSizeOf<Ts...>::value ? sizeof(H) : MaxSizeOf<Ts...>::val
ue; | |
1741 }; | |
1742 | |
1743 // UntaggedVariant is a pile of memory that can hold one of the Ts. It provides
a way | |
1744 // to initialize that memory in a typesafe way. | |
1745 template <typename... Ts> | |
1746 class UntaggedVariant { | |
1747 public: | |
1748 UntaggedVariant() {} | |
1749 ~UntaggedVariant() {} | |
1750 UntaggedVariant(const UntaggedVariant&) = delete; | |
1751 UntaggedVariant& operator=(const UntaggedVariant&) = delete; | |
1752 UntaggedVariant(UntaggedVariant&&) = delete; | |
1753 UntaggedVariant& operator=(UntaggedVariant&&) = delete; | |
1754 | |
1755 template <typename Variant, typename... Args> | |
1756 void initialize(Args &&... args) { | |
1757 SkASSERT(sizeof(Variant) <= sizeof(fSpace)); | |
1758 #if defined(_MSC_VER) && _MSC_VER < 1900 | |
1759 #define alignof __alignof | |
1760 #endif | |
1761 SkASSERT(alignof(Variant) <= alignof(Space)); | |
1762 new (&fSpace) Variant(skstd::forward<Args>(args)...); | |
1763 } | |
1764 | |
1765 private: | |
1766 typedef SkAlignedSStorage<MaxSizeOf<Ts...>::value> Space; | |
1767 Space fSpace; | |
1768 }; | |
1769 | |
1770 // PolymorphicVariant holds subclasses of Base without slicing. Ts must be subcl
asses of Base. | |
1771 template <typename Base, typename... Ts> | |
1772 class PolymorphicVariant { | |
1773 public: | |
1774 typedef UntaggedVariant<Ts...> Variants; | |
1775 template <typename Initializer> | |
1776 PolymorphicVariant(Initializer&& initializer) { | |
1777 initializer(&fVariants); | |
1778 } | |
1779 ~PolymorphicVariant() { get()->~Base(); } | |
1780 Base* get() const { return reinterpret_cast<Base*>(&fVariants); } | |
1781 Base* operator->() const { return get(); } | |
1782 Base& operator*() const { return *get(); } | |
1783 | |
1784 private: | |
1785 mutable Variants fVariants; | |
1786 }; | |
1787 | |
1788 // PositionReaderInterface reads a point from the pos vector. | |
1789 // * HorizontalPositions - assumes a common Y for many X values. | |
1790 // * ArbitraryPositions - a list of (X,Y) pairs. | |
1791 class PositionReaderInterface { | |
1792 public: | |
1793 virtual ~PositionReaderInterface() { } | |
1794 virtual SkPoint nextPoint() = 0; | |
1795 }; | |
1796 | |
1797 class HorizontalPositions final : public PositionReaderInterface { | |
1798 public: | |
1799 explicit HorizontalPositions(const SkScalar* positions) | |
1800 : fPositions(positions) { } | |
1801 | |
1802 SkPoint nextPoint() override { | |
1803 SkScalar x = *fPositions++; | |
1804 return {x, 0}; | |
1805 } | |
1806 private: | |
1807 const SkScalar* fPositions; | |
1808 }; | |
1809 | |
1810 class ArbitraryPositions final : public PositionReaderInterface { | |
1811 public: | |
1812 explicit ArbitraryPositions(const SkScalar* positions) | |
1813 : fPositions(positions) { } | |
1814 SkPoint nextPoint() override { | |
1815 SkPoint to_return {fPositions[0], fPositions[1]}; | |
1816 fPositions += 2; | |
1817 return to_return; | |
1818 } | |
1819 | |
1820 private: | |
1821 const SkScalar* fPositions; | |
1822 }; | |
1823 | |
1824 typedef PolymorphicVariant<PositionReaderInterface, HorizontalPositions, Arbitra
ryPositions> | |
1825 PositionReader; | |
1826 | |
1827 // MapperInterface given a point map it through the matrix. There are several sh
ortcut variants. | |
1828 // * TranslationMapper - assumes a translation only matrix. | |
1829 // * XScaleMapper - assumes an X scaling and a translation. | |
1830 // * GeneralMapper - Does all other matricies. | |
1831 class MapperInterface { | |
1832 public: | |
1833 virtual ~MapperInterface() {} | |
1834 virtual SkPoint map(SkPoint position) const = 0; | |
1835 }; | |
1836 | |
1837 class TranslationMapper final : public MapperInterface { | |
1838 public: | |
1839 TranslationMapper(const SkMatrix& matrix, const SkPoint origin) | |
1840 : fTranslate(matrix.mapXY(origin.fX, origin.fY)) { } | |
1841 SkPoint map(SkPoint position) const override { | |
1842 return position + fTranslate; | |
1843 } | |
1844 | |
1845 private: | |
1846 const SkPoint fTranslate; | |
1847 }; | |
1848 | |
1849 class XScaleMapper final : public MapperInterface { | |
1850 public: | |
1851 XScaleMapper(const SkMatrix& matrix, const SkPoint origin) | |
1852 : fTranslate(matrix.mapXY(origin.fX, origin.fY)) | |
1853 , fXScale(matrix.getScaleX()) { } | |
1854 SkPoint map(SkPoint position) const override { | |
1855 return {fXScale * position.fX + fTranslate.fX, fTranslate.fY}; | |
1856 } | |
1857 | |
1858 private: | |
1859 const SkPoint fTranslate; | |
1860 const SkScalar fXScale; | |
1861 }; | |
1862 | |
1863 // The caller must keep matrix alive while this class is used. | |
1864 class GeneralMapper final : public MapperInterface { | |
1865 public: | |
1866 GeneralMapper(const SkMatrix& matrix, const SkPoint origin) | |
1867 : fOrigin(origin) | |
1868 , fMatrix(matrix) | |
1869 , fMapProc(matrix.getMapXYProc()) { } | |
1870 SkPoint map(SkPoint position) const override { | |
1871 SkPoint result; | |
1872 fMapProc(fMatrix, position.fX + fOrigin.fX, position.fY + fOrigin.fY, &r
esult); | |
1873 return result; | |
1874 } | |
1875 | |
1876 private: | |
1877 const SkPoint fOrigin; | |
1878 const SkMatrix& fMatrix; | |
1879 const SkMatrix::MapXYProc fMapProc; | |
1880 }; | |
1881 | |
1882 typedef PolymorphicVariant<MapperInterface, TranslationMapper, XScaleMapper, Gen
eralMapper> Mapper; | |
1883 | |
1884 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | |
1885 // Text alignment handles shifting the glyph based on its width. | |
1886 static SkPoint text_alignment_adjustment(SkPaint::Align textAlignment, const SkG
lyph& glyph) { | |
1887 switch (textAlignment) { | |
1888 case SkPaint::kLeft_Align: | |
1889 return {0.0f, 0.0f}; | |
1890 break; | |
1891 case SkPaint::kCenter_Align: | |
1892 return {SkFixedToScalar(glyph.fAdvanceX >> 1), | |
1893 SkFixedToScalar(glyph.fAdvanceY >> 1)}; | |
1894 break; | |
1895 case SkPaint::kRight_Align: | |
1896 return {SkFixedToScalar(glyph.fAdvanceX), | |
1897 SkFixedToScalar(glyph.fAdvanceY)}; | |
1898 break; | |
1899 } | |
1900 // Even though the entire enum is covered above, MVSC doesn't think so. Make
it happy. | |
1901 SkFAIL("Should never get here."); | |
1902 return {0.0f, 0.0f}; | |
1903 } | |
1904 | |
1905 // The "call" to SkFixedToScalar is actually a macro. It's macros all the way do
wn. | |
1906 static const SkScalar kSubpixelRounding = SkFixedToScalar(SkGlyph::kSubpixelRoun
d); | |
1907 | |
1908 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | |
1909 // Functions for handling sub-pixel aligned positions. | |
1910 // The subpixel_position_rounding function returns a point suitable for rounding
a sub-pixel | |
1911 // positioned glyph. | |
1912 static SkPoint subpixel_position_rounding(SkAxisAlignment axisAlignment) { | |
1913 switch (axisAlignment) { | |
1914 case kX_SkAxisAlignment: | |
1915 return {SkFixedToScalar(SkGlyph::kSubpixelRound), SK_ScalarHalf}; | |
1916 case kY_SkAxisAlignment: | |
1917 return {SK_ScalarHalf, kSubpixelRounding}; | |
1918 case kNone_SkAxisAlignment: | |
1919 return {kSubpixelRounding, kSubpixelRounding}; | |
1920 } | |
1921 SkFAIL("Should not get here."); | |
1922 return {0.0f, 0.0f}; | |
1923 } | |
1924 | |
1925 // The subpixel_position_alignment function produces a suitable position for the
glyph cache to | |
1926 // produce the correct sub-pixel alignment. If a position is aligned with an axi
s a shortcut of 0 | |
1927 // is used for the sub-pixel position. | |
1928 static SkIPoint subpixel_position_alignment(SkAxisAlignment axisAlignment, SkPoi
nt position) { | |
1929 switch (axisAlignment) { | |
1930 case kX_SkAxisAlignment: | |
1931 return {SkScalarToFixed(position.fX + kSubpixelRounding), 0}; | |
1932 case kY_SkAxisAlignment: | |
1933 return {0, SkScalarToFixed(position.fY + kSubpixelRounding)}; | |
1934 case kNone_SkAxisAlignment: | |
1935 return {SkScalarToFixed(position.fX + kSubpixelRounding), | |
1936 SkScalarToFixed(position.fY + kSubpixelRounding)}; | |
1937 } | |
1938 SkFAIL("Should not get here."); | |
1939 return {0, 0}; | |
1940 } | |
1941 | |
1942 // GlyphFindAndPlaceInterface given the text and position finds the correct glyp
h and does glyph | |
1943 // specific position adjustment. The findAndPositionGlyph method takes text and
position and calls | |
1944 // processOneGlyph with the correct glyph, final position and rounding terms. Th
e final position | |
1945 // is not rounded yet and is the responsibility of processOneGlyph. | |
1946 template <typename ProcessOneGlyph> | |
1947 class GlyphFindAndPlaceInterface : SkNoncopyable { | |
1948 public: | |
1949 struct Result { | |
1950 const SkGlyph* fGlyph; | |
1951 Sk48Dot16 fX; | |
1952 Sk48Dot16 fY; | |
1953 }; | |
1954 virtual ~GlyphFindAndPlaceInterface() { }; | |
1955 // This should be a pure virtual, but some versions of GCC <= 4.8 have a bug
that causes a | |
1956 // compile error. | |
1957 // See GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60277 | |
1958 virtual void findAndPositionGlyph(const char** text, SkPoint position, | |
1959 ProcessOneGlyph&& processOneGlyph) {}; | |
1960 }; | |
1961 | |
1962 // GlyphFindAndPlaceForSubpixel handles finding and placing glyphs when sub-pixe
l positioning is | |
1963 // requested. After it has found and placed the glyph it calls the templated fun
ction | |
1964 // ProcessOneGlyph in order to actually perform an action. | |
1965 template <typename ProcessOneGlyph, SkPaint::Align kTextAlignment, SkAxisAlignme
nt kAxisAlignment> | |
1966 class GlyphFindAndPlaceForSubpixel final : public GlyphFindAndPlaceInterface<Pro
cessOneGlyph> { | |
1967 public: | |
1968 GlyphFindAndPlaceForSubpixel(SkGlyphCache* cache, SkDrawCacheProc glyphCache
Proc) | |
1969 : fCache(cache) | |
1970 , fGlyphCacheProc(glyphCacheProc) { | |
1971 } | |
1972 void findAndPositionGlyph(const char** text, SkPoint position, | |
1973 ProcessOneGlyph&& processOneGlyph) override { | |
1974 SkPoint finalPosition = position; | |
1975 if (kTextAlignment != SkPaint::kLeft_Align) { | |
1976 // Get the width of an un-sub-pixel positioned glyph for calculating
the alignment. | |
1977 // This is not needed for kLeftAlign because its adjustment is alway
s {0, 0}. | |
1978 const char* tempText = *text; | |
1979 const SkGlyph& metricGlyph = fGlyphCacheProc(fCache, &tempText, 0, 0
); | |
1980 | |
1981 if (metricGlyph.fWidth <= 0) { | |
1982 return; | |
1983 } | |
1984 | |
1985 // Adjust the final position by the alignment adjustment. | |
1986 finalPosition -= text_alignment_adjustment(kTextAlignment, metricGly
ph); | |
1987 } | |
1988 | |
1989 // Find the glyph. | |
1990 SkIPoint lookupPosition = subpixel_position_alignment(kAxisAlignment, fi
nalPosition); | |
1991 const SkGlyph& renderGlyph = fGlyphCacheProc( | |
1992 fCache, text, lookupPosition.fX, lookupPosition.fY); | |
1993 | |
1994 // If the glyph has no width (no pixels) then don't bother processing it
. | |
1995 if (renderGlyph.fWidth > 0) { | |
1996 processOneGlyph(renderGlyph, finalPosition, subpixel_position_roundi
ng(kAxisAlignment)); | |
1997 } | |
1998 } | |
1999 | |
2000 private: | |
2001 SkGlyphCache* const fCache; | |
2002 SkDrawCacheProc fGlyphCacheProc; | |
2003 }; | |
2004 | |
2005 // GlyphFindAndPlaceForFullPixel handles finding and placing glyphs when no sub-
pixel positioning | |
2006 // is requested. | |
2007 template <typename ProcessOneGlyph, SkPaint::Align kTextAlignment> | |
2008 class GlyphFindAndPlaceForFullPixel final : public GlyphFindAndPlaceInterface<Pr
ocessOneGlyph> { | |
2009 public: | |
2010 GlyphFindAndPlaceForFullPixel(SkGlyphCache* cache, SkDrawCacheProc glyphCach
eProc) | |
2011 : fCache(cache) | |
2012 , fGlyphCacheProc(glyphCacheProc) { } | |
2013 void findAndPositionGlyph(const char** text, SkPoint position, | |
2014 ProcessOneGlyph&& processOneGlyph) override { | |
2015 SkPoint finalPosition = position; | |
2016 const SkGlyph& glyph = fGlyphCacheProc(fCache, text, 0, 0); | |
2017 if (glyph.fWidth <= 0) { | |
2018 return; | |
2019 } | |
2020 finalPosition -= text_alignment_adjustment(kTextAlignment, glyph); | |
2021 processOneGlyph(glyph, finalPosition, {SK_ScalarHalf, SK_ScalarHalf}); | |
2022 } | |
2023 | |
2024 private: | |
2025 SkGlyphCache* const fCache; | |
2026 SkDrawCacheProc fGlyphCacheProc; | |
2027 }; | |
2028 | |
2029 // GlyphFindAndPlace is a large variant that encapsulates the multiple types of
finding and | |
2030 // placing a glyph. There are three factors that go into the different factors. | |
2031 // * Is sub-pixel positioned - a boolean that says whether to use sub-pixel posi
tioning. | |
2032 // * Text alignment - indicates if the glyph should be placed to the right, cent
ered or left of a | |
2033 // given position. | |
2034 // * Axis alignment - indicates if the glyphs final sub-pixel position should be
rounded to a | |
2035 // whole pixel if the glyph is aligned with an axis. This is only used for sub
-pixel positioning | |
2036 // and allows the baseline to look crisp. | |
2037 template <typename ProcessOneGlyph> | |
2038 using GlyphFindAndPlace = | |
2039 PolymorphicVariant< | |
2040 GlyphFindAndPlaceInterface<ProcessOneGlyph>, | |
2041 // Subpixel | |
2042 GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kN
one_SkAxisAlignment>, | |
2043 GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kX
_SkAxisAlignment >, | |
2044 GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kY
_SkAxisAlignment >, | |
2045 GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kN
one_SkAxisAlignment>, | |
2046 GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kX
_SkAxisAlignment >, | |
2047 GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kY
_SkAxisAlignment >, | |
2048 GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kN
one_SkAxisAlignment>, | |
2049 GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kX
_SkAxisAlignment >, | |
2050 GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kY
_SkAxisAlignment >, | |
2051 // Full pixel | |
2052 GlyphFindAndPlaceForFullPixel<ProcessOneGlyph, SkPaint::kLeft_Align >, | |
2053 GlyphFindAndPlaceForFullPixel<ProcessOneGlyph, SkPaint::kCenter_Align>, | |
2054 GlyphFindAndPlaceForFullPixel<ProcessOneGlyph, SkPaint::kRight_Align > | |
2055 >; | |
2056 | |
2057 // init_subpixel is a helper function for initializing all the variants of | |
2058 // GlyphFindAndPlaceForSubpixel. | |
2059 template <typename ProcessOneGlyph, SkPaint::Align kTextAlignment> | |
2060 static void init_subpixel( | |
2061 typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init, | |
2062 SkAxisAlignment axisAlignment, | |
2063 SkGlyphCache* cache, | |
2064 SkDrawCacheProc glyphCacheProc) { | |
2065 switch (axisAlignment) { | |
2066 case kX_SkAxisAlignment: | |
2067 to_init->template initialize<GlyphFindAndPlaceForSubpixel< | |
2068 ProcessOneGlyph, kTextAlignment, kX_SkAxisAlignment>>( | |
2069 cache, glyphCacheProc); | |
2070 break; | |
2071 case kNone_SkAxisAlignment: | |
2072 to_init->template initialize<GlyphFindAndPlaceForSubpixel< | |
2073 ProcessOneGlyph, kTextAlignment, kNone_SkAxisAlignment>>( | |
2074 cache, glyphCacheProc); | |
2075 break; | |
2076 case kY_SkAxisAlignment: | |
2077 to_init->template initialize<GlyphFindAndPlaceForSubpixel< | |
2078 ProcessOneGlyph, kTextAlignment, kY_SkAxisAlignment>>( | |
2079 cache, glyphCacheProc); | |
2080 break; | |
2081 } | |
2082 } | |
2083 | |
2084 // specialized_process_pos_text is a version of ProcessPosText that de-virtualiz
es the different | |
2085 // components used. It returns true if it can handle the situation, otherwise it
returns false. | |
2086 // This allows greater inlining freedom to the compiler. Currently, there is onl
y one specialized | |
2087 // variant: sub-pixel position, left-aligned, x-axis-aligned, translation, and o
ne scalar per | |
2088 // position entry. | |
2089 // * This is by far the most common type of text Blink draws. | |
2090 template <typename ProcessOneGlyph> | |
2091 static bool specialized_process_pos_text(const char* const text, size_t byteLeng
th, | |
2092 const SkPoint& offset, const SkMatrix&
matrix, | |
2093 const SkScalar pos[], int scalarsPerPos
ition, | |
2094 SkPaint::Align textAlignment, | |
2095 SkDrawCacheProc& glyphCacheProc, | |
2096 SkGlyphCache* cache, ProcessOneGlyph&&
processOneGlyph) { | |
2097 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(matrix); | |
2098 uint32_t mtype = matrix.getType(); | |
2099 if (scalarsPerPosition == 1 | |
2100 && textAlignment == SkPaint::kLeft_Align | |
2101 && axisAlignment == kX_SkAxisAlignment | |
2102 && cache->isSubpixel() | |
2103 && mtype <= SkMatrix::kTranslate_Mask) { | |
2104 typedef GlyphFindAndPlaceForSubpixel< | |
2105 ProcessOneGlyph, SkPaint::kLeft_Align, kX_SkAxisAlignment> Positione
r; | |
2106 HorizontalPositions positions{pos}; | |
2107 TranslationMapper mapper{matrix, offset}; | |
2108 Positioner positioner(cache, glyphCacheProc); | |
2109 const char *cursor = text; | |
2110 const char *stop = text + byteLength; | |
2111 while (cursor < stop) { | |
2112 SkPoint mappedPoint = mapper.TranslationMapper::map( | |
2113 positions.HorizontalPositions::nextPoint()); | |
2114 positioner.Positioner::findAndPositionGlyph( | |
2115 &cursor, mappedPoint, skstd::forward<ProcessOneGlyph>(processOne
Glyph)); | |
2116 } | |
2117 return true; | |
2118 } | |
2119 return false; | |
2120 } | |
2121 | |
2122 // ProcessPosText handles all cases for finding and positioning glyphs. It has a
very large | |
2123 // multiplicity. It figures out the glyph, position and rounding and pass those
parameters to | |
2124 // processOneGlyph. | |
2125 // | |
2126 // The routine processOneGlyph passed in by the client has the following signatu
re: | |
2127 // void f(const SkGlyph& glyph, SkPoint position, SkPoint rounding); | |
2128 // | |
2129 // * Sub-pixel positioning (2) - use sub-pixel positioning. | |
2130 // * Text alignment (3) - text alignment with respect to the glyph's width. | |
2131 // * Matrix type (3) - special cases for translation and X-coordinate scaling. | |
2132 // * Components per position (2) - the positions vector can have a common Y with
different Xs, or | |
2133 // XY-pairs. | |
2134 // * Axis Alignment (for sub-pixel positioning) (3) - when using sub-pixel posit
ioning, round to | |
2135 // a whole coordinate instead of using sub-pixel positioning. | |
2136 // The number of variations is 108 for sub-pixel and 36 for full-pixel. | |
2137 // This routine handles all of them using inline polymorphic variable (no heap a
llocation). | |
2138 template <typename ProcessOneGlyph> | |
2139 static void process_pos_text(const char text[], size_t byteLength, | |
2140 const SkPoint& offset, const SkMatrix& matrix, | |
2141 const SkScalar pos[], int scalarsPerPosition, | |
2142 SkPaint::Align textAlignment, SkDrawCacheProc& glyp
hCacheProc, | |
2143 SkGlyphCache* cache, ProcessOneGlyph&& processOneGl
yph) { | |
2144 | |
2145 PositionReader positionReader { | |
2146 [&](PositionReader::Variants* to_init) { | |
2147 if (2 == scalarsPerPosition) { | |
2148 to_init->initialize<ArbitraryPositions>(pos); | |
2149 } else { | |
2150 to_init->initialize<HorizontalPositions>(pos); | |
2151 } | |
2152 } | |
2153 }; | |
2154 | |
2155 Mapper mapper { | |
2156 [&] (Mapper::Variants* to_init) { | |
2157 uint32_t mtype = matrix.getType(); | |
2158 if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask) | |
2159 || scalarsPerPosition == 2) { | |
2160 to_init->initialize<GeneralMapper>(matrix, offset); | |
2161 } else if (mtype & SkMatrix::kScale_Mask) { | |
2162 to_init->initialize<XScaleMapper>(matrix, offset); | |
2163 } else { | |
2164 to_init->initialize<TranslationMapper>(matrix, offset); | |
2165 } | |
2166 } | |
2167 }; | |
2168 | |
2169 GlyphFindAndPlace<ProcessOneGlyph> findAndPosition{ | |
2170 [&](typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init) { | |
2171 if (cache->isSubpixel()) { | |
2172 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(m
atrix); | |
2173 switch (textAlignment) { | |
2174 case SkPaint::kLeft_Align: | |
2175 init_subpixel<ProcessOneGlyph, SkPaint::kLeft_Align>( | |
2176 to_init, axisAlignment, cache, glyphCacheProc); | |
2177 break; | |
2178 case SkPaint::kCenter_Align: | |
2179 init_subpixel<ProcessOneGlyph, SkPaint::kCenter_Align>( | |
2180 to_init, axisAlignment, cache, glyphCacheProc); | |
2181 break; | |
2182 case SkPaint::kRight_Align: | |
2183 init_subpixel<ProcessOneGlyph, SkPaint::kRight_Align>( | |
2184 to_init, axisAlignment, cache, glyphCacheProc); | |
2185 break; | |
2186 } | |
2187 } else { | |
2188 switch (textAlignment) { | |
2189 case SkPaint::kLeft_Align: | |
2190 to_init->template initialize<GlyphFindAndPlaceForFullPix
el<ProcessOneGlyph, | |
2191 SkPaint::kLeft_Align>>( | |
2192 cache, glyphCacheProc); | |
2193 break; | |
2194 case SkPaint::kCenter_Align: | |
2195 to_init->template initialize<GlyphFindAndPlaceForFullPix
el<ProcessOneGlyph, | |
2196 SkPaint::kCenter_Align>>( | |
2197 cache, glyphCacheProc); | |
2198 break; | |
2199 case SkPaint::kRight_Align: | |
2200 to_init->template initialize<GlyphFindAndPlaceForFullPix
el<ProcessOneGlyph, | |
2201 SkPaint::kRight_Align>>( | |
2202 cache, glyphCacheProc); | |
2203 break; | |
2204 } | |
2205 } | |
2206 } | |
2207 }; | |
2208 | |
2209 const char* stop = text + byteLength; | |
2210 while (text < stop) { | |
2211 SkPoint mappedPoint = mapper->map(positionReader->nextPoint()); | |
2212 findAndPosition->findAndPositionGlyph( | |
2213 &text, mappedPoint, skstd::forward<ProcessOneGlyph>(processOneGlyph)
); | |
2214 } | |
2215 } | |
2216 | |
2217 void SkDraw::drawPosText(const char text[], size_t byteLength, | 1733 void SkDraw::drawPosText(const char text[], size_t byteLength, |
2218 const SkScalar pos[], int scalarsPerPosition, | 1734 const SkScalar pos[], int scalarsPerPosition, |
2219 const SkPoint& offset, const SkPaint& paint) const { | 1735 const SkPoint& offset, const SkPaint& paint) const { |
2220 SkASSERT(byteLength == 0 || text != nullptr); | 1736 SkASSERT(byteLength == 0 || text != nullptr); |
2221 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | 1737 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
2222 | 1738 |
2223 SkDEBUGCODE(this->validate();) | 1739 SkDEBUGCODE(this->validate();) |
2224 | 1740 |
2225 // nothing to draw | 1741 // nothing to draw |
2226 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { | 1742 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { |
(...skipping 24 matching lines...) Expand all Loading... |
2251 SkDraw1Glyph d1g; | 1767 SkDraw1Glyph d1g; |
2252 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); | 1768 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); |
2253 | 1769 |
2254 auto processOneGlyph = | 1770 auto processOneGlyph = |
2255 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { | 1771 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { |
2256 position += rounding; | 1772 position += rounding; |
2257 proc(d1g, SkScalarToFixed(position.fX), SkScalarToFixed(position.fY)
, glyph); | 1773 proc(d1g, SkScalarToFixed(position.fX), SkScalarToFixed(position.fY)
, glyph); |
2258 }; | 1774 }; |
2259 | 1775 |
2260 SkPaint::Align textAlignment = paint.getTextAlign(); | 1776 SkPaint::Align textAlignment = paint.getTextAlign(); |
2261 if (!specialized_process_pos_text(text, byteLength, offset, *fMatrix, pos, s
calarsPerPosition, | 1777 if (!SkFindAndPlaceGlyph::SpecializedProcessPosText( |
2262 textAlignment, glyphCacheProc, cache, processOneGlyph)) { | 1778 text, byteLength, offset, *fMatrix, pos, scalarsPerPosition, |
2263 process_pos_text(text, byteLength, offset, *fMatrix, pos, scalarsPerPosi
tion, | 1779 textAlignment, glyphCacheProc, cache, processOneGlyph)) { |
| 1780 SkFindAndPlaceGlyph::ProcessPosText( |
| 1781 text, byteLength, offset, *fMatrix, pos, scalarsPerPosition, |
2264 textAlignment, glyphCacheProc, cache, processOneGlyph); | 1782 textAlignment, glyphCacheProc, cache, processOneGlyph); |
2265 } | 1783 } |
2266 } | 1784 } |
2267 | 1785 |
2268 #if defined _WIN32 && _MSC_VER >= 1300 | 1786 #if defined _WIN32 && _MSC_VER >= 1300 |
2269 #pragma warning ( pop ) | 1787 #pragma warning ( pop ) |
2270 #endif | 1788 #endif |
2271 | 1789 |
2272 /////////////////////////////////////////////////////////////////////////////// | 1790 /////////////////////////////////////////////////////////////////////////////// |
2273 | 1791 |
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2658 mask->fImage = SkMask::AllocImage(size); | 2176 mask->fImage = SkMask::AllocImage(size); |
2659 memset(mask->fImage, 0, mask->computeImageSize()); | 2177 memset(mask->fImage, 0, mask->computeImageSize()); |
2660 } | 2178 } |
2661 | 2179 |
2662 if (SkMask::kJustComputeBounds_CreateMode != mode) { | 2180 if (SkMask::kJustComputeBounds_CreateMode != mode) { |
2663 draw_into_mask(*mask, devPath, style); | 2181 draw_into_mask(*mask, devPath, style); |
2664 } | 2182 } |
2665 | 2183 |
2666 return true; | 2184 return true; |
2667 } | 2185 } |
OLD | NEW |