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 "SkFixed.h" | 15 #include "SkFixed.h" |
16 #include "SkMaskFilter.h" | 16 #include "SkMaskFilter.h" |
17 #include "SkMatrix.h" | |
17 #include "SkPaint.h" | 18 #include "SkPaint.h" |
18 #include "SkPathEffect.h" | 19 #include "SkPathEffect.h" |
19 #include "SkRasterClip.h" | 20 #include "SkRasterClip.h" |
20 #include "SkRasterizer.h" | 21 #include "SkRasterizer.h" |
21 #include "SkRRect.h" | 22 #include "SkRRect.h" |
22 #include "SkScan.h" | 23 #include "SkScan.h" |
23 #include "SkShader.h" | 24 #include "SkShader.h" |
24 #include "SkSmallAllocator.h" | 25 #include "SkSmallAllocator.h" |
25 #include "SkString.h" | 26 #include "SkString.h" |
26 #include "SkStroke.h" | 27 #include "SkStroke.h" |
27 #include "SkStrokeRec.h" | 28 #include "SkStrokeRec.h" |
29 #include "SkTemplates.h" | |
28 #include "SkTextMapStateProc.h" | 30 #include "SkTextMapStateProc.h" |
29 #include "SkTLazy.h" | 31 #include "SkTLazy.h" |
32 #include "SkUtility.h" | |
30 #include "SkUtils.h" | 33 #include "SkUtils.h" |
31 #include "SkVertState.h" | 34 #include "SkVertState.h" |
32 | 35 |
33 #include "SkAutoKern.h" | 36 #include "SkAutoKern.h" |
34 #include "SkBitmapProcShader.h" | 37 #include "SkBitmapProcShader.h" |
35 #include "SkDrawProcs.h" | 38 #include "SkDrawProcs.h" |
36 #include "SkMatrixUtils.h" | 39 #include "SkMatrixUtils.h" |
37 | 40 |
38 //#define TRACE_BITMAP_DRAWS | 41 //#define TRACE_BITMAP_DRAWS |
39 | 42 |
(...skipping 1392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1432 prevXPos = xpos; | 1435 prevXPos = xpos; |
1433 } | 1436 } |
1434 } | 1437 } |
1435 | 1438 |
1436 // disable warning : local variable used without having been initialized | 1439 // disable warning : local variable used without having been initialized |
1437 #if defined _WIN32 && _MSC_VER >= 1300 | 1440 #if defined _WIN32 && _MSC_VER >= 1300 |
1438 #pragma warning ( push ) | 1441 #pragma warning ( push ) |
1439 #pragma warning ( disable : 4701 ) | 1442 #pragma warning ( disable : 4701 ) |
1440 #endif | 1443 #endif |
1441 | 1444 |
1442 ////////////////////////////////////////////////////////////////////////////// | 1445 //////////////////////////////////////////////////////////////////////////////// //////////////////// |
1443 | 1446 |
1444 static void D1G_RectClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy, const SkGlyph& glyph) { | 1447 static void D1G_RectClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy, const SkGlyph& glyph) { |
1445 // Prevent glyphs from being drawn outside of or straddling the edge of devi ce space. | 1448 // Prevent glyphs from being drawn outside of or straddling the edge of devi ce space. |
1446 if ((fx >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || | 1449 if ((fx >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || |
1447 (fx >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) || | 1450 (fx >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) || |
1448 (fy >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || | 1451 (fy >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || |
1449 (fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) | 1452 (fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) |
1450 { | 1453 { |
1451 return; | 1454 return; |
1452 } | 1455 } |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1719 fDevice->drawPath(*this, *path, paint, &matrix, false); | 1722 fDevice->drawPath(*this, *path, paint, &matrix, false); |
1720 } else { | 1723 } else { |
1721 this->drawPath(*path, paint, &matrix, false); | 1724 this->drawPath(*path, paint, &matrix, false); |
1722 } | 1725 } |
1723 } | 1726 } |
1724 } | 1727 } |
1725 pos += scalarsPerPosition; | 1728 pos += scalarsPerPosition; |
1726 } | 1729 } |
1727 } | 1730 } |
1728 | 1731 |
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 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
1744 // UntaggedVariant is a pile of memory that can hold one of the Ts. It provides a way | |
1745 // to initialize that memory in a typesafe way. | |
1746 template <typename... Ts> | |
1747 class UntaggedVariant { | |
1748 public: | |
1749 UntaggedVariant() {} | |
1750 ~UntaggedVariant() {} | |
1751 UntaggedVariant(const UntaggedVariant&) = delete; | |
1752 UntaggedVariant& operator=(const UntaggedVariant&) = delete; | |
1753 UntaggedVariant(UntaggedVariant&&) = delete; | |
1754 UntaggedVariant& operator=(UntaggedVariant&&) = delete; | |
1755 | |
1756 template <typename Variant, typename... Args> | |
1757 void initialize(Args &&... args) { | |
1758 SkASSERT(sizeof(Variant) <= sizeof(fSpace)); | |
1759 #if defined(_MSC_VER) && _MSC_VER < 1900 | |
1760 #define alignof __alignof | |
1761 #endif | |
1762 SkASSERT(alignof(Variant) <= alignof(Space)); | |
1763 new (&fSpace) Variant(skstd::forward<Args>(args)...); | |
1764 } | |
1765 | |
1766 private: | |
1767 typedef SkAlignedSStorage<MaxSizeOf<Ts...>::value> Space; | |
1768 Space fSpace; | |
1769 }; | |
1770 | |
1771 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
1772 // PolymorphicVariant holds subclasses of Base without slicing. Ts must be subcl asses of Base. | |
1773 template <typename Base, typename... Ts> | |
1774 class PolymorphicVariant { | |
1775 public: | |
1776 typedef UntaggedVariant<Ts...> Variants; | |
1777 template <typename Initializer> | |
1778 PolymorphicVariant(Initializer&& initializer) { | |
1779 initializer(&fVariants); | |
1780 } | |
1781 ~PolymorphicVariant() { get()->~Base(); } | |
1782 Base* get() const { return reinterpret_cast<Base*>(&fVariants); } | |
1783 Base* operator->() const { return get(); } | |
1784 Base& operator*() const { return *get(); } | |
1785 | |
1786 private: | |
1787 mutable Variants fVariants; | |
1788 }; | |
1789 | |
1790 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
1791 // PositionReaderInterface reads a point from the pos vector. | |
1792 // * HorizontalPositions - assumes a common Y for many X values. | |
1793 // * ArbitraryPositions - a list of (X,Y) pairs. | |
1794 class PositionReaderInterface : SkNoncopyable { | |
1795 public: | |
1796 virtual ~PositionReaderInterface() { } | |
1797 virtual const SkPoint nextPoint() = 0; | |
1798 }; | |
1799 | |
1800 class HorizontalPositions final : public PositionReaderInterface { | |
1801 public: | |
1802 HorizontalPositions(const SkScalar* positions) | |
1803 : fPositions(positions) { } | |
1804 | |
1805 const SkPoint nextPoint() override { | |
1806 SkScalar x = *fPositions++; | |
1807 return {x, 0}; | |
1808 } | |
1809 private: | |
1810 const SkScalar* fPositions; | |
1811 }; | |
1812 | |
1813 class ArbitraryPositions final : public PositionReaderInterface { | |
1814 public: | |
1815 ArbitraryPositions(const SkScalar* positions) | |
1816 : fPositions(positions) { } | |
1817 const SkPoint nextPoint() override { | |
1818 SkPoint to_return {fPositions[0], fPositions[1]}; | |
1819 fPositions += 2; | |
1820 return to_return; | |
1821 } | |
1822 | |
1823 private: | |
1824 const SkScalar* fPositions; | |
1825 }; | |
1826 | |
1827 typedef PolymorphicVariant<PositionReaderInterface, HorizontalPositions, Arbitra ryPositions> | |
1828 PositionReader; | |
1829 | |
1830 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
1831 // MapperInterface given a point map it through the matrix. There are several sh ortcut variants. | |
1832 // * TranslationMapper - assumes a translation only matrix. | |
1833 // * XScaleMapper - assumes an X scaling and a translation. | |
1834 // * GeneralMapper - Does all other matricies. | |
1835 class MapperInterface : SkNoncopyable { | |
1836 public: | |
1837 virtual ~MapperInterface() {} | |
1838 virtual SkPoint map(SkPoint position) const = 0; | |
1839 }; | |
1840 | |
1841 class TranslationMapper final : public MapperInterface { | |
1842 public: | |
1843 TranslationMapper(const SkMatrix& matrix, const SkPoint origin) | |
1844 : fTranslate(matrix.mapXY(origin.fX, origin.fY)) { } | |
1845 SkPoint map(SkPoint position) const override { | |
1846 return position + fTranslate; | |
1847 } | |
1848 | |
1849 private: | |
1850 const SkPoint fTranslate; | |
1851 }; | |
1852 | |
1853 class XScaleMapper final : public MapperInterface { | |
1854 public: | |
1855 XScaleMapper(const SkMatrix& matrix, const SkPoint origin) | |
1856 : fTranslate(matrix.mapXY(origin.fX, origin.fY)) | |
1857 , fXScale(matrix.getScaleX()) { } | |
1858 SkPoint map(SkPoint position) const override { | |
1859 return {SkScalarMul(fXScale, position.fX) + fTranslate.fX, fTranslate.fY }; | |
1860 } | |
1861 | |
1862 private: | |
1863 const SkPoint fTranslate; | |
1864 const SkScalar fXScale; | |
1865 }; | |
1866 | |
1867 // The caller must keep matrix alive while this class is used. | |
1868 class GeneralMapper final : public MapperInterface { | |
1869 public: | |
1870 GeneralMapper(const SkMatrix& matrix, const SkPoint origin) | |
1871 : fOrigin(origin) | |
1872 , fMatrix(matrix) | |
1873 , fMapProc(matrix.getMapXYProc()) { } | |
1874 SkPoint map(SkPoint position) const override { | |
1875 SkPoint result; | |
1876 fMapProc(fMatrix, position.fX + fOrigin.fX, position.fY + fOrigin.fY, &r esult); | |
1877 return result; | |
1878 } | |
1879 | |
1880 private: | |
1881 const SkPoint fOrigin; | |
1882 const SkMatrix& fMatrix; | |
1883 const SkMatrix::MapXYProc fMapProc; | |
1884 }; | |
1885 | |
1886 typedef PolymorphicVariant<MapperInterface, TranslationMapper, XScaleMapper, Gen eralMapper> Mapper; | |
1887 | |
1888 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
1889 // Text alignment handles shifting the glyph based on its width. | |
1890 static SkPoint text_alignment_adjustment(SkPaint::Align textAlignment, const SkG lyph& glyph) { | |
1891 switch (textAlignment) { | |
1892 case SkPaint::kLeft_Align: | |
1893 return {0.0f, 0.0f}; | |
1894 break; | |
1895 case SkPaint::kCenter_Align: | |
1896 return {SkFixedToScalar(glyph.fAdvanceX >> 1), | |
1897 SkFixedToScalar(glyph.fAdvanceY >> 1)}; | |
1898 break; | |
1899 case SkPaint::kRight_Align: | |
1900 return {SkFixedToScalar(glyph.fAdvanceX), | |
1901 SkFixedToScalar(glyph.fAdvanceY)}; | |
1902 break; | |
1903 } | |
1904 // Even though the entire enum is covered above, MVSC doesn't think so. Make it happy. | |
1905 SkFAIL("Should never get here."); | |
1906 return {0.0f, 0.0f}; | |
1907 } | |
1908 | |
1909 // The "call" to SkFixedToScalar is actually a macro. It's macros all the way do wn. | |
1910 static const SkScalar kSubpixelRounding = SkFixedToScalar(SkGlyph::kSubpixelRoun d); | |
1911 | |
1912 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
1913 // Functions for handling sub-pixel aligned positions. | |
1914 // The subpixel_position_rounding function returns a point suitable for rounding a sub-pixel | |
1915 // positioned glyph. | |
1916 static SkPoint subpixel_position_rounding(SkAxisAlignment axisAlignment) { | |
1917 switch (axisAlignment) { | |
1918 case kX_SkAxisAlignment: | |
1919 return {SkFixedToScalar(SkGlyph::kSubpixelRound), SK_ScalarHalf}; | |
1920 case kY_SkAxisAlignment: | |
1921 return {SK_ScalarHalf, kSubpixelRounding}; | |
1922 case kNone_SkAxisAlignment: | |
1923 return {kSubpixelRounding, kSubpixelRounding}; | |
1924 default: | |
1925 SkFAIL("Should not get here."); | |
1926 return {0.0f, 0.0f}; | |
1927 } | |
1928 } | |
1929 | |
1930 // The subpixel_position_alignment function produces a suitable position for the glyph cache to | |
1931 // produce the correct sub-pixel alignment. If a position is aligned with an axi s a shortcut of 0 | |
1932 // is used for the sub-pixel position. | |
1933 static SkIPoint subpixel_position_alignment(SkAxisAlignment axisAlignment, SkPoi nt position) { | |
1934 switch (axisAlignment) { | |
1935 case kX_SkAxisAlignment: | |
1936 return {SkScalarToFixed(position.fX + kSubpixelRounding), 0}; | |
1937 case kY_SkAxisAlignment: | |
1938 return {0, SkScalarToFixed(position.fY + kSubpixelRounding)}; | |
1939 case kNone_SkAxisAlignment: | |
1940 return {SkScalarToFixed(position.fX + kSubpixelRounding), | |
1941 SkScalarToFixed(position.fY + kSubpixelRounding)}; | |
1942 default: | |
1943 SkFAIL("Should not get here."); | |
1944 return {0, 0}; | |
1945 } | |
1946 } | |
1947 | |
1948 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
1949 // GlyphFindAndPlaceInterface given the text and position finds the correct glyp h and does glyph | |
1950 // specific position adjustment. The findAndPositionGlyph method takes text and position and calls | |
1951 // processOneGlyph with the correct glyph, final position and rounding terms. Th e final position | |
1952 // is not rounded yet and is the responsibility of processOneGlyph. | |
1953 template <typename GlyphProcessor> | |
1954 class GlyphFindAndPlaceInterface : SkNoncopyable { | |
1955 public: | |
1956 struct Result { | |
1957 const SkGlyph* fGlyph; | |
1958 Sk48Dot16 fX; | |
1959 Sk48Dot16 fY; | |
1960 }; | |
1961 virtual ~GlyphFindAndPlaceInterface() { }; | |
1962 // This should be a pure virtual, but some versions of GCC <= 4.8 have a bug that causes a | |
1963 // compile error. | |
1964 // See GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60277 | |
1965 virtual void findAndPositionGlyph(const char** text, SkPoint position, | |
mtklein
2015/11/05 18:33:08
How come this is const char**?
herb_g
2015/11/06 17:21:25
Because the internal call to the GlyphCacheProc ad
| |
1966 GlyphProcessor&& processOneGlyph) {}; | |
1967 }; | |
1968 | |
1969 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
mtklein
2015/11/05 18:33:08
let's cut out the ////////////////// section marke
herb_g
2015/11/06 17:21:25
Done.
| |
1970 // GlyphFindAndPlaceForSubpixel handles finding and placing glyphs when sub-pixe l positioning is | |
1971 // requested. After it has found a placed the glyph it calls the templated funct ion | |
mtklein
2015/11/05 18:33:08
found and placed
herb_g
2015/11/06 17:21:25
Done.
| |
1972 // GlyphProcessor in order to actually perform an action. | |
1973 template <typename GlyphProcessor, SkPaint::Align textAlignment, SkAxisAlignment axisAlignment> | |
mtklein
2015/11/05 18:33:08
I think code like this reads a little more clearly
herb_g
2015/11/06 17:21:25
Done.
| |
1974 class GlyphFindAndPlaceForSubpixel final : public GlyphFindAndPlaceInterface<Gly phProcessor> { | |
1975 public: | |
1976 GlyphFindAndPlaceForSubpixel(SkGlyphCache* cache, SkDrawCacheProc glyphCache Proc) | |
1977 : fCache(cache) | |
1978 , fGlyphCacheProc(glyphCacheProc) { | |
1979 } | |
1980 void findAndPositionGlyph(const char** text, SkPoint position, | |
1981 GlyphProcessor&& processOneGlyph) override { | |
1982 SkPoint finalPosition = position; | |
1983 if (textAlignment != SkPaint::kLeft_Align) { | |
1984 // Get the width of an un-sub-pixel positioned glyph for calculating the alignment. | |
1985 // This is not needed for kLeftAlign because its adjustment is alway s {0, 0}. | |
1986 const char* tempText = *text; | |
1987 const SkGlyph& metricGlyph = fGlyphCacheProc(fCache, &tempText, 0, 0 ); | |
1988 | |
1989 if (metricGlyph.fWidth <= 0) { | |
1990 return; | |
1991 } | |
1992 | |
1993 // Adjust the final position by the alignment adjustment. | |
1994 finalPosition -= text_alignment_adjustment(textAlignment, metricGlyp h); | |
1995 } | |
1996 | |
1997 // Find the glyph. | |
1998 SkIPoint lookupPosition = subpixel_position_alignment(axisAlignment, fin alPosition); | |
1999 const SkGlyph& renderGlyph = fGlyphCacheProc( | |
2000 fCache, text, lookupPosition.fX, lookupPosition.fY); | |
2001 | |
2002 // If the glyph has no width (no pixels) then don't bother processing it . | |
2003 if (renderGlyph.fWidth > 0) { | |
2004 processOneGlyph(renderGlyph, finalPosition, subpixel_position_roundi ng(axisAlignment)); | |
2005 } | |
2006 } | |
2007 | |
2008 private: | |
2009 SkGlyphCache* const fCache; | |
2010 SkDrawCacheProc fGlyphCacheProc; | |
2011 }; | |
2012 | |
2013 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
2014 // GlyphFindAndPlaceForFullPixel handles finding and placing glyphs when no sub- pixel positioning | |
2015 // is requested. | |
2016 template <typename GlyphProcessor, SkPaint::Align textAlignment> | |
2017 class GlyphFindAndPlaceForFullPixel final : public GlyphFindAndPlaceInterface<Gl yphProcessor> { | |
2018 public: | |
2019 GlyphFindAndPlaceForFullPixel(SkGlyphCache* cache, SkDrawCacheProc glyphCach eProc) | |
2020 : fCache(cache) | |
2021 , fGlyphCacheProc(glyphCacheProc) { } | |
2022 void findAndPositionGlyph(const char** text, SkPoint position, | |
2023 GlyphProcessor&& processOneGlyph) override { | |
2024 SkPoint finalPosition = position; | |
2025 const SkGlyph& glyph = fGlyphCacheProc(fCache, text, 0, 0); | |
2026 if (glyph.fWidth <= 0) { | |
2027 return; | |
2028 } | |
2029 finalPosition -= text_alignment_adjustment(textAlignment, glyph); | |
2030 processOneGlyph(glyph, finalPosition, {SK_ScalarHalf, SK_ScalarHalf}); | |
2031 } | |
2032 | |
2033 private: | |
2034 SkGlyphCache* const fCache; | |
2035 SkDrawCacheProc fGlyphCacheProc; | |
2036 }; | |
2037 | |
2038 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
2039 // GlyphFindAndPlace is a large variant that encapsulates the multiple types of finding and | |
2040 // placing a glyph. There are three factors that go into the different factors. | |
2041 // * Is sub-pixel positioned - a boolean that says whether to use sub-pixel posi tioning. | |
2042 // * Text alignment - indicates if the glyph should be placed to the right, cent ered or left of a | |
2043 // given position. | |
2044 // * Axis alignment - indicates if the glyphs final sub-pixel position should be rounded to a | |
2045 // whole pixel if the glyph is aligned with an axis. This is only used for sub -pixel positioning | |
2046 // and allows the baseline to look crisp. | |
2047 template <typename GlyphProcessor> | |
2048 using GlyphFindAndPlace = | |
2049 PolymorphicVariant< | |
2050 GlyphFindAndPlaceInterface<GlyphProcessor>, | |
2051 // Subpixel | |
2052 GlyphFindAndPlaceForSubpixel<GlyphProcessor, SkPaint::kLeft_Align, kNo ne_SkAxisAlignment>, | |
2053 GlyphFindAndPlaceForSubpixel<GlyphProcessor, SkPaint::kLeft_Align, kX_ SkAxisAlignment >, | |
2054 GlyphFindAndPlaceForSubpixel<GlyphProcessor, SkPaint::kLeft_Align, kY_ SkAxisAlignment >, | |
2055 GlyphFindAndPlaceForSubpixel<GlyphProcessor, SkPaint::kCenter_Align, kNo ne_SkAxisAlignment>, | |
2056 GlyphFindAndPlaceForSubpixel<GlyphProcessor, SkPaint::kCenter_Align, kX_ SkAxisAlignment >, | |
2057 GlyphFindAndPlaceForSubpixel<GlyphProcessor, SkPaint::kCenter_Align, kY_ SkAxisAlignment >, | |
2058 GlyphFindAndPlaceForSubpixel<GlyphProcessor, SkPaint::kRight_Align, kNo ne_SkAxisAlignment>, | |
2059 GlyphFindAndPlaceForSubpixel<GlyphProcessor, SkPaint::kRight_Align, kX_ SkAxisAlignment >, | |
2060 GlyphFindAndPlaceForSubpixel<GlyphProcessor, SkPaint::kRight_Align, kY_ SkAxisAlignment >, | |
2061 // Full pixel | |
2062 GlyphFindAndPlaceForFullPixel<GlyphProcessor, SkPaint::kLeft_Align >, | |
2063 GlyphFindAndPlaceForFullPixel<GlyphProcessor, SkPaint::kCenter_Align>, | |
2064 GlyphFindAndPlaceForFullPixel<GlyphProcessor, SkPaint::kRight_Align > | |
2065 >; | |
2066 | |
2067 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
2068 // init_subpixel is a helper function for initializing all the variants of | |
2069 // GlyphFindAndPlaceForSubpixel. | |
2070 template <typename GlyphProcessor, SkPaint::Align textAlignment> | |
2071 static void init_subpixel( | |
2072 typename GlyphFindAndPlace<GlyphProcessor>::Variants* to_init, | |
2073 SkAxisAlignment axisAlignment, | |
2074 SkGlyphCache* cache, | |
2075 SkDrawCacheProc glyphCacheProc) { | |
2076 switch (axisAlignment) { | |
2077 case kX_SkAxisAlignment: | |
2078 to_init->template initialize<GlyphFindAndPlaceForSubpixel< | |
2079 GlyphProcessor, textAlignment, kX_SkAxisAlignment>>( | |
2080 cache, glyphCacheProc); | |
2081 break; | |
2082 case kNone_SkAxisAlignment: | |
2083 to_init->template initialize<GlyphFindAndPlaceForSubpixel< | |
2084 GlyphProcessor, textAlignment, kNone_SkAxisAlignment>>( | |
2085 cache, glyphCacheProc); | |
2086 break; | |
2087 case kY_SkAxisAlignment: | |
2088 to_init->template initialize<GlyphFindAndPlaceForSubpixel< | |
2089 GlyphProcessor, textAlignment, kY_SkAxisAlignment>>( | |
2090 cache, glyphCacheProc); | |
2091 break; | |
2092 } | |
2093 } | |
2094 | |
2095 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
2096 // specialized_process_pos_text is a version of ProcessPosText that de-virtualiz es the different | |
2097 // components used. This allows greater inlining freedom to the compiler. Curren tly, there is | |
2098 // only one variant that is used: sub-pixel position, left-aligned, x-axis-align ed, translation, | |
mtklein
2015/11/05 18:33:08
used -> specialized ?
Might also add // This is b
herb_g
2015/11/06 17:21:25
Done.
| |
2099 // and one scalar per position entry. | |
2100 template <typename GlyphProcessor> | |
2101 static void specialized_process_pos_text(const char *const text, size_t byteLeng th, | |
mtklein
2015/11/05 18:33:08
I'd like to find a way to get the can-we-use-this
herb_g
2015/11/06 17:21:25
Done.
| |
2102 const SkPoint &offset, const SkMatrix &m atrix, | |
2103 const SkScalar *const pos, SkDrawCachePr oc &glyphCacheProc, | |
2104 SkGlyphCache *cache, GlyphProcessor &&pr ocessOneGlyph) { | |
2105 typedef GlyphFindAndPlaceForSubpixel< | |
2106 GlyphProcessor, SkPaint::kLeft_Align, kX_SkAxisAlignment> Positioner; | |
2107 HorizontalPositions positions{pos}; | |
2108 TranslationMapper mapper{matrix, offset}; | |
2109 Positioner positioner(cache, glyphCacheProc); | |
2110 const char* cursor = text; | |
2111 const char* stop = text + byteLength; | |
2112 while (cursor < stop) { | |
2113 SkPoint mappedPoint = mapper.TranslationMapper::map( | |
2114 positions.HorizontalPositions::nextPoint()); | |
2115 positioner.Positioner::findAndPositionGlyph( | |
2116 &cursor, mappedPoint, skstd::forward<GlyphProcessor>(processOneGlyph )); | |
2117 } | |
2118 } | |
2119 | |
2120 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
2121 // ProcessPosText handles all cases for finding and positioning glyphs. It has a very large | |
2122 // multiplicity. It figures out the glpyh, position and rounding and pass those parameters to | |
2123 // processOneGlyph. | |
2124 // | |
2125 // The routine processOneGlyph passed in by the client has the following signatu re: | |
2126 // void f(const SkGlyph& glyph, SkPoint position, SkPoint rounding); | |
2127 // | |
2128 // * Sub-pixel positioning (2) - use sub-pixel positioning. | |
2129 // * Text alignment (3) - text alignment with respect to the glyph's width. | |
2130 // * Matrix type (3) - special cases for translation and X-coordinate scaling. | |
2131 // * Components per position (2) - the positions vector can have a common Y with different Xs, or | |
2132 // XY-pairs. | |
2133 // * Axis Alignment (for sub-pixel positioning) (3) - when using sub-pixel posit ioning, round to | |
2134 // a whole coordinate instead of using sub-pixel positioning. | |
2135 // The number of variations is 108 for sub-pixel and 36 for full-pixel. | |
2136 // This routine handles all of them using inline polymorphic variable (no heap a llocation). | |
2137 template <typename GlyphProcessor> | |
2138 static void ProcessPosText(const char text[], size_t byteLength, | |
mtklein
2015/11/05 18:33:08
process_pos_text
herb_g
2015/11/06 17:21:25
Done.
| |
2139 const SkPoint& offset, const SkMatrix& matrix, | |
2140 const SkScalar pos[], int scalarsPerPosition, | |
2141 SkPaint::Align textAlignment, SkDrawCacheProc& glyph CacheProc, | |
2142 SkGlyphCache* cache, GlyphProcessor&& processOneGlyp h) { | |
2143 | |
2144 PositionReader positionReader { | |
2145 [&](PositionReader::Variants* to_init) { | |
2146 if (2 == scalarsPerPosition) { | |
2147 to_init->initialize<ArbitraryPositions>(pos); | |
2148 } else { | |
2149 to_init->initialize<HorizontalPositions>(pos); | |
2150 } | |
2151 } | |
2152 }; | |
2153 | |
2154 Mapper mapper { | |
2155 [&] (Mapper::Variants* to_init) { | |
2156 uint32_t mtype = matrix.getType(); | |
2157 if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask) | |
2158 || scalarsPerPosition == 2) { | |
2159 to_init->initialize<GeneralMapper>(matrix, offset); | |
2160 } else if (mtype & SkMatrix::kScale_Mask) { | |
2161 to_init->initialize<XScaleMapper>(matrix, offset); | |
2162 } else { | |
2163 to_init->initialize<TranslationMapper>(matrix, offset); | |
2164 } | |
2165 } | |
2166 }; | |
2167 | |
2168 GlyphFindAndPlace<GlyphProcessor> findAndPosition{ | |
2169 [&](typename GlyphFindAndPlace<GlyphProcessor>::Variants* to_init) { | |
2170 if (cache->isSubpixel()) { | |
2171 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(m atrix); | |
2172 switch (textAlignment) { | |
2173 case SkPaint::kLeft_Align: | |
2174 init_subpixel<GlyphProcessor, SkPaint::kLeft_Align>( | |
2175 to_init, axisAlignment, cache, glyphCacheProc); | |
2176 break; | |
2177 case SkPaint::kCenter_Align: | |
2178 init_subpixel<GlyphProcessor, SkPaint::kCenter_Align>( | |
2179 to_init, axisAlignment, cache, glyphCacheProc); | |
2180 break; | |
2181 case SkPaint::kRight_Align: | |
2182 init_subpixel<GlyphProcessor, SkPaint::kRight_Align>( | |
2183 to_init, axisAlignment, cache, glyphCacheProc); | |
2184 break; | |
2185 } | |
2186 } else { | |
2187 switch (textAlignment) { | |
2188 case SkPaint::kLeft_Align: | |
2189 to_init->template initialize<GlyphFindAndPlaceForFullPix el<GlyphProcessor, | |
2190 SkPaint::kLeft_Align>>( | |
2191 cache, glyphCacheProc); | |
2192 break; | |
2193 case SkPaint::kCenter_Align: | |
2194 to_init->template initialize<GlyphFindAndPlaceForFullPix el<GlyphProcessor, | |
2195 SkPaint::kCenter_Align>>( | |
2196 cache, glyphCacheProc); | |
2197 break; | |
2198 case SkPaint::kRight_Align: | |
2199 to_init->template initialize<GlyphFindAndPlaceForFullPix el<GlyphProcessor, | |
2200 SkPaint::kRight_Align>>( | |
2201 cache, glyphCacheProc); | |
2202 break; | |
2203 } | |
2204 } | |
2205 } | |
2206 }; | |
2207 | |
2208 const char* stop = text + byteLength; | |
2209 while (text < stop) { | |
2210 SkPoint mappedPoint = mapper->map(positionReader->nextPoint()); | |
2211 findAndPosition->findAndPositionGlyph( | |
2212 &text, mappedPoint, skstd::forward<GlyphProcessor>(processOneGlyph)) ; | |
2213 } | |
2214 } | |
2215 | |
1729 void SkDraw::drawPosText(const char text[], size_t byteLength, | 2216 void SkDraw::drawPosText(const char text[], size_t byteLength, |
1730 const SkScalar pos[], int scalarsPerPosition, | 2217 const SkScalar pos[], int scalarsPerPosition, |
1731 const SkPoint& offset, const SkPaint& paint) const { | 2218 const SkPoint& offset, const SkPaint& paint) const { |
1732 SkASSERT(byteLength == 0 || text != nullptr); | 2219 SkASSERT(byteLength == 0 || text != nullptr); |
1733 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | 2220 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
1734 | 2221 |
1735 SkDEBUGCODE(this->validate();) | 2222 SkDEBUGCODE(this->validate();) |
1736 | 2223 |
1737 // nothing to draw | 2224 // nothing to draw |
1738 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { | 2225 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { |
(...skipping 14 matching lines...) Expand all Loading... | |
1753 SkBlitter* blitter = nullptr; | 2240 SkBlitter* blitter = nullptr; |
1754 if (needsRasterTextBlit(*this)) { | 2241 if (needsRasterTextBlit(*this)) { |
1755 blitterChooser.choose(fDst, *fMatrix, paint); | 2242 blitterChooser.choose(fDst, *fMatrix, paint); |
1756 blitter = blitterChooser.get(); | 2243 blitter = blitterChooser.get(); |
1757 if (fRC->isAA()) { | 2244 if (fRC->isAA()) { |
1758 wrapper.init(*fRC, blitter); | 2245 wrapper.init(*fRC, blitter); |
1759 blitter = wrapper.getBlitter(); | 2246 blitter = wrapper.getBlitter(); |
1760 } | 2247 } |
1761 } | 2248 } |
1762 | 2249 |
1763 const char* stop = text + byteLength; | |
1764 SkTextAlignProc alignProc(paint.getTextAlign()); | |
1765 SkDraw1Glyph d1g; | 2250 SkDraw1Glyph d1g; |
1766 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); | 2251 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); |
1767 SkTextMapStateProc tmsProc(*fMatrix, offset, scalarsPerPosition); | |
1768 | 2252 |
1769 if (cache->isSubpixel()) { | 2253 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(*fMatrix); |
1770 // maybe we should skip the rounding if linearText is set | 2254 uint32_t mtype = fMatrix->getType(); |
1771 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix); | 2255 SkPaint::Align textAlignment = paint.getTextAlign(); |
1772 | 2256 if (scalarsPerPosition == 1 |
1773 SkFixed fxMask = ~0; | 2257 && textAlignment == SkPaint::kLeft_Align |
1774 SkFixed fyMask = ~0; | 2258 && axisAlignment == kX_SkAxisAlignment |
1775 if (kX_SkAxisAlignment == baseline) { | 2259 && cache->isSubpixel() |
1776 fyMask = 0; | 2260 && (mtype |
mtklein
2015/11/05 18:33:08
I think SkMatrix::getType() does this mask for you
herb_g
2015/11/06 17:21:25
Done.
| |
1777 d1g.fHalfSampleY = SK_ScalarHalf; | 2261 & (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask |
1778 } else if (kY_SkAxisAlignment == baseline) { | 2262 | SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) <= |
1779 fxMask = 0; | 2263 SkMatrix::kTranslate_Mas k) { |
1780 d1g.fHalfSampleX = SK_ScalarHalf; | 2264 specialized_process_pos_text( |
1781 } | 2265 text, byteLength, offset, *fMatrix, pos, glyphCacheProc, cache, |
1782 | 2266 [&](const SkGlyph &glyph, SkPoint position, SkPoint rounding) { |
1783 if (SkPaint::kLeft_Align == paint.getTextAlign()) { | 2267 position += rounding; |
1784 while (text < stop) { | 2268 proc(d1g, SkScalarToFixed(position.fX), SkScalarToFixed(position .fY), glyph); |
1785 SkPoint tmsLoc; | |
1786 tmsProc(pos, &tmsLoc); | |
1787 | |
1788 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + d1g.fHalfSampleX); | |
1789 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + d1g.fHalfSampleY); | |
1790 | |
1791 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask); | |
1792 | |
1793 if (glyph.fWidth) { | |
1794 proc(d1g, fx, fy, glyph); | |
1795 } | |
1796 pos += scalarsPerPosition; | |
1797 } | 2269 } |
1798 } else { | 2270 ); |
1799 while (text < stop) { | 2271 } else { |
1800 const char* currentText = text; | 2272 ProcessPosText( |
1801 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); | 2273 text, byteLength, offset, *fMatrix, pos, scalarsPerPosition, |
1802 | 2274 textAlignment, glyphCacheProc, cache, |
1803 if (metricGlyph.fWidth) { | 2275 [&](const SkGlyph &glyph, SkPoint position, SkPoint rounding) { |
mtklein
2015/11/05 18:33:08
These are the same lambda, right? Why don't we gi
herb_g
2015/11/06 17:21:25
Done.
| |
1804 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) | 2276 position += rounding; |
1805 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) | 2277 proc(d1g, SkScalarToFixed(position.fX), SkScalarToFixed(position .fY), glyph); |
1806 SkPoint tmsLoc; | |
1807 tmsProc(pos, &tmsLoc); | |
1808 | |
1809 SkPoint alignLoc; | |
1810 alignProc(tmsLoc, metricGlyph, &alignLoc); | |
1811 | |
1812 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + d1g.fHalfSamp leX); | |
1813 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + d1g.fHalfSamp leY); | |
1814 | |
1815 // have to call again, now that we've been "aligned" | |
1816 const SkGlyph& glyph = glyphCacheProc(cache, ¤tText, | |
1817 fx & fxMask, fy & fyMa sk); | |
1818 // the assumption is that the metrics haven't changed | |
1819 SkASSERT(prevAdvX == glyph.fAdvanceX); | |
1820 SkASSERT(prevAdvY == glyph.fAdvanceY); | |
1821 SkASSERT(glyph.fWidth); | |
1822 | |
1823 proc(d1g, fx, fy, glyph); | |
1824 } | |
1825 pos += scalarsPerPosition; | |
1826 } | 2278 } |
1827 } | 2279 ); |
1828 } else { // not subpixel | |
1829 if (SkPaint::kLeft_Align == paint.getTextAlign()) { | |
1830 while (text < stop) { | |
1831 // the last 2 parameters are ignored | |
1832 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | |
1833 | |
1834 if (glyph.fWidth) { | |
1835 SkPoint tmsLoc; | |
1836 tmsProc(pos, &tmsLoc); | |
1837 | |
1838 proc(d1g, | |
1839 SkScalarTo48Dot16(tmsLoc.fX + SK_ScalarHalf), //d1g.fHa lfSampleX, | |
1840 SkScalarTo48Dot16(tmsLoc.fY + SK_ScalarHalf), //d1g.fHa lfSampleY, | |
1841 glyph); | |
1842 } | |
1843 pos += scalarsPerPosition; | |
1844 } | |
1845 } else { | |
1846 while (text < stop) { | |
1847 // the last 2 parameters are ignored | |
1848 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | |
1849 | |
1850 if (glyph.fWidth) { | |
1851 SkPoint tmsLoc; | |
1852 tmsProc(pos, &tmsLoc); | |
1853 | |
1854 SkPoint alignLoc; | |
1855 alignProc(tmsLoc, glyph, &alignLoc); | |
1856 | |
1857 proc(d1g, | |
1858 SkScalarTo48Dot16(alignLoc.fX + SK_ScalarHalf), //d1g.f HalfSampleX, | |
1859 SkScalarTo48Dot16(alignLoc.fY + SK_ScalarHalf), //d1g.f HalfSampleY, | |
1860 glyph); | |
1861 } | |
1862 pos += scalarsPerPosition; | |
1863 } | |
1864 } | |
1865 } | 2280 } |
1866 } | 2281 } |
1867 | 2282 |
1868 #if defined _WIN32 && _MSC_VER >= 1300 | 2283 #if defined _WIN32 && _MSC_VER >= 1300 |
1869 #pragma warning ( pop ) | 2284 #pragma warning ( pop ) |
1870 #endif | 2285 #endif |
1871 | 2286 |
1872 /////////////////////////////////////////////////////////////////////////////// | 2287 /////////////////////////////////////////////////////////////////////////////// |
1873 | 2288 |
1874 static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) { | 2289 static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) { |
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2258 mask->fImage = SkMask::AllocImage(size); | 2673 mask->fImage = SkMask::AllocImage(size); |
2259 memset(mask->fImage, 0, mask->computeImageSize()); | 2674 memset(mask->fImage, 0, mask->computeImageSize()); |
2260 } | 2675 } |
2261 | 2676 |
2262 if (SkMask::kJustComputeBounds_CreateMode != mode) { | 2677 if (SkMask::kJustComputeBounds_CreateMode != mode) { |
2263 draw_into_mask(*mask, devPath, style); | 2678 draw_into_mask(*mask, devPath, style); |
2264 } | 2679 } |
2265 | 2680 |
2266 return true; | 2681 return true; |
2267 } | 2682 } |
OLD | NEW |