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 // 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 : SkNoncopyable { |
| 1792 public: |
| 1793 virtual ~PositionReaderInterface() { } |
| 1794 virtual SkPoint nextPoint() = 0; |
| 1795 }; |
| 1796 |
| 1797 class HorizontalPositions final : public PositionReaderInterface { |
| 1798 public: |
| 1799 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 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 : SkNoncopyable { |
| 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 |
1729 void SkDraw::drawPosText(const char text[], size_t byteLength, | 2217 void SkDraw::drawPosText(const char text[], size_t byteLength, |
1730 const SkScalar pos[], int scalarsPerPosition, | 2218 const SkScalar pos[], int scalarsPerPosition, |
1731 const SkPoint& offset, const SkPaint& paint) const { | 2219 const SkPoint& offset, const SkPaint& paint) const { |
1732 SkASSERT(byteLength == 0 || text != nullptr); | 2220 SkASSERT(byteLength == 0 || text != nullptr); |
1733 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | 2221 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
1734 | 2222 |
1735 SkDEBUGCODE(this->validate();) | 2223 SkDEBUGCODE(this->validate();) |
1736 | 2224 |
1737 // nothing to draw | 2225 // nothing to draw |
1738 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { | 2226 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { |
(...skipping 14 matching lines...) Expand all Loading... |
1753 SkBlitter* blitter = nullptr; | 2241 SkBlitter* blitter = nullptr; |
1754 if (needsRasterTextBlit(*this)) { | 2242 if (needsRasterTextBlit(*this)) { |
1755 blitterChooser.choose(fDst, *fMatrix, paint); | 2243 blitterChooser.choose(fDst, *fMatrix, paint); |
1756 blitter = blitterChooser.get(); | 2244 blitter = blitterChooser.get(); |
1757 if (fRC->isAA()) { | 2245 if (fRC->isAA()) { |
1758 wrapper.init(*fRC, blitter); | 2246 wrapper.init(*fRC, blitter); |
1759 blitter = wrapper.getBlitter(); | 2247 blitter = wrapper.getBlitter(); |
1760 } | 2248 } |
1761 } | 2249 } |
1762 | 2250 |
1763 const char* stop = text + byteLength; | |
1764 SkTextAlignProc alignProc(paint.getTextAlign()); | |
1765 SkDraw1Glyph d1g; | 2251 SkDraw1Glyph d1g; |
1766 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); | 2252 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); |
1767 SkTextMapStateProc tmsProc(*fMatrix, offset, scalarsPerPosition); | |
1768 | 2253 |
1769 if (cache->isSubpixel()) { | 2254 auto processOneGlyph = |
1770 // maybe we should skip the rounding if linearText is set | 2255 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { |
1771 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix); | 2256 position += rounding; |
| 2257 proc(d1g, SkScalarToFixed(position.fX), SkScalarToFixed(position.fY)
, glyph); |
| 2258 }; |
1772 | 2259 |
1773 SkFixed fxMask = ~0; | 2260 SkPaint::Align textAlignment = paint.getTextAlign(); |
1774 SkFixed fyMask = ~0; | 2261 if (!specialized_process_pos_text(text, byteLength, offset, *fMatrix, pos, s
calarsPerPosition, |
1775 if (kX_SkAxisAlignment == baseline) { | 2262 textAlignment, glyphCacheProc, cache, processOneGlyph)) { |
1776 fyMask = 0; | 2263 process_pos_text(text, byteLength, offset, *fMatrix, pos, scalarsPerPosi
tion, |
1777 d1g.fHalfSampleY = SK_ScalarHalf; | 2264 textAlignment, glyphCacheProc, cache, processOneGlyph); |
1778 } else if (kY_SkAxisAlignment == baseline) { | |
1779 fxMask = 0; | |
1780 d1g.fHalfSampleX = SK_ScalarHalf; | |
1781 } | |
1782 | |
1783 if (SkPaint::kLeft_Align == paint.getTextAlign()) { | |
1784 while (text < stop) { | |
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 } | |
1798 } else { | |
1799 while (text < stop) { | |
1800 const char* currentText = text; | |
1801 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); | |
1802 | |
1803 if (metricGlyph.fWidth) { | |
1804 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) | |
1805 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) | |
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 } | |
1827 } | |
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 } | 2265 } |
1866 } | 2266 } |
1867 | 2267 |
1868 #if defined _WIN32 && _MSC_VER >= 1300 | 2268 #if defined _WIN32 && _MSC_VER >= 1300 |
1869 #pragma warning ( pop ) | 2269 #pragma warning ( pop ) |
1870 #endif | 2270 #endif |
1871 | 2271 |
1872 /////////////////////////////////////////////////////////////////////////////// | 2272 /////////////////////////////////////////////////////////////////////////////// |
1873 | 2273 |
1874 static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) { | 2274 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); | 2658 mask->fImage = SkMask::AllocImage(size); |
2259 memset(mask->fImage, 0, mask->computeImageSize()); | 2659 memset(mask->fImage, 0, mask->computeImageSize()); |
2260 } | 2660 } |
2261 | 2661 |
2262 if (SkMask::kJustComputeBounds_CreateMode != mode) { | 2662 if (SkMask::kJustComputeBounds_CreateMode != mode) { |
2263 draw_into_mask(*mask, devPath, style); | 2663 draw_into_mask(*mask, devPath, style); |
2264 } | 2664 } |
2265 | 2665 |
2266 return true; | 2666 return true; |
2267 } | 2667 } |
OLD | NEW |