Chromium Code Reviews| 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 and alignment as a list of types Ts. | |
|
mtklein
2015/11/04 17:54:11
You might just drop the AndAlignment on these name
herb_g
2015/11/04 21:58:42
Done.
| |
| 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 template <typename... Ts> struct SameSizeAndAlignmentAs { | |
| 1744 private: | |
| 1745 SkAlignedSStorage<MaxSizeOf<Ts...>::value> unused; | |
|
mtklein
2015/11/04 17:54:11
Even
template <typename... Ts>
using SameSizeAndA
herb_g
2015/11/04 21:58:41
I just embeded SkAlignedSStorage<MaxSizeOf<Ts...>:
| |
| 1746 }; | |
| 1747 | |
| 1748 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
| 1749 // UntaggedVariant is a pile of memory that can hold one of the Ts. It provides a way | |
| 1750 // to initialize that memory in a typesafe way. | |
| 1751 template <typename... Ts> | |
| 1752 class UntaggedVariant { | |
|
mtklein
2015/11/04 17:54:12
I'm not sure I see why SameSizeAndAlignmentAs is s
herb_g
2015/11/04 21:58:42
I agree with the SameSizeAndAlignmentAs. This is f
| |
| 1753 public: | |
| 1754 UntaggedVariant() {} | |
| 1755 ~UntaggedVariant() {} | |
| 1756 UntaggedVariant(const UntaggedVariant&) = delete; | |
| 1757 UntaggedVariant& operator=(const UntaggedVariant&) = delete; | |
| 1758 UntaggedVariant(UntaggedVariant&&) = delete; | |
| 1759 UntaggedVariant& operator=(UntaggedVariant&&) = delete; | |
| 1760 template <typename Variant, typename... Args> | |
|
mtklein
2015/11/04 17:54:11
It'd be nice to add a newline before template.
herb_g
2015/11/04 21:58:42
Done.
| |
| 1761 void Init(Args&&... args) { | |
|
mtklein
2015/11/04 17:54:11
-> init
| |
| 1762 SkASSERT(sizeof(Variant) <= sizeof(fSpace)); | |
| 1763 #ifndef SK_BUILD_FOR_WIN32 | |
|
mtklein
2015/11/04 17:54:11
Alternatively, I think we could do
#if defined(_M
herb_g
2015/11/04 21:58:42
Done.
| |
| 1764 SkASSERT(alignof(Variant) <= alignof(SameSizeAndAlignmentAs<Ts...>)); | |
| 1765 #endif | |
| 1766 new (&fSpace) Variant(skstd::forward<Args>(args)...); | |
| 1767 } | |
| 1768 | |
| 1769 private: | |
| 1770 SameSizeAndAlignmentAs<Ts...> fSpace; | |
| 1771 }; | |
| 1772 | |
| 1773 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
| 1774 // PolymorphicVariant holds supclasses of Base without slicing. Ts must be subcl asses of Base. | |
|
mtklein
2015/11/04 17:54:12
sup -> sub
herb_g
2015/11/04 21:58:42
Done.
| |
| 1775 template <typename Base, typename... Ts> | |
| 1776 class PolymorphicVariant { | |
| 1777 public: | |
| 1778 typedef UntaggedVariant<Ts...> Variants; | |
| 1779 template <typename Initializer> | |
| 1780 PolymorphicVariant(Initializer&& initializer) { | |
| 1781 skstd::forward<Initializer>(initializer)(&fVariants); | |
|
mtklein
2015/11/04 17:54:12
What's the deal with forward here? We don't seem
herb_g
2015/11/04 21:58:42
Forgotten experiment.
| |
| 1782 } | |
| 1783 ~PolymorphicVariant() { get()->~Base(); } | |
| 1784 Base* get() const { return (Base*) &fVariants; } | |
|
mtklein
2015/11/04 17:54:11
This seems like a spot where reinterpret_cast<> wo
herb_g
2015/11/04 21:58:41
Done.
| |
| 1785 Base* operator->() const { return get(); } | |
| 1786 Base& operator*() const { return *get(); } | |
| 1787 | |
| 1788 private: | |
| 1789 Variants fVariants; | |
| 1790 }; | |
| 1791 | |
| 1792 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
| 1793 // PositionReaderInterface read a point from the pos vector. | |
|
mtklein
2015/11/04 17:54:11
reads
herb_g
2015/11/04 21:58:42
Done.
| |
| 1794 // * LinearPositions - assumes a common Y for many X values. | |
| 1795 // * ArbitraryPositions - a list of (X,Y) pairs. | |
| 1796 class PositionReaderInterface : SkNoncopyable { | |
| 1797 public: | |
| 1798 virtual ~PositionReaderInterface() { } | |
| 1799 virtual const SkPoint NextPoint() = 0; | |
|
mtklein
2015/11/04 17:54:11
nextPoint()
herb_g
2015/11/04 21:58:42
Done.
| |
| 1800 }; | |
| 1801 | |
| 1802 class LinearPositions final : public PositionReaderInterface { | |
|
mtklein
2015/11/04 17:54:12
Even, HorizontalPositions.
herb_g
2015/11/04 21:58:43
Done.
| |
| 1803 public: | |
| 1804 LinearPositions(const SkScalar* positions) | |
|
mtklein
2015/11/04 17:54:11
It seems surprising we don't pass the shared y her
herb_g
2015/11/04 21:58:42
Right. This is a confusion with the existing code.
| |
| 1805 : fPositions(positions) { } | |
| 1806 | |
| 1807 const SkPoint NextPoint() override { | |
| 1808 SkScalar x = *fPositions++; | |
| 1809 return {x, 0}; | |
| 1810 } | |
| 1811 private: | |
| 1812 const SkScalar* fPositions; | |
| 1813 }; | |
| 1814 | |
| 1815 class ArbitraryPositions final : public PositionReaderInterface { | |
| 1816 public: | |
| 1817 ArbitraryPositions(const SkScalar* positions) | |
| 1818 : fPositions(positions) { } | |
| 1819 : fPositions(positions) { } | |
|
mtklein
2015/11/04 17:54:12
Typo?
herb_g
2015/11/04 21:58:43
Done.
| |
| 1820 const SkPoint NextPoint() override { | |
| 1821 SkPoint to_return {fPositions[0], fPositions[1]}; | |
| 1822 fPositions += 2; | |
| 1823 return to_return; | |
| 1824 } | |
| 1825 | |
| 1826 private: | |
| 1827 const SkScalar* fPositions; | |
| 1828 }; | |
| 1829 | |
| 1830 typedef PolymorphicVariant<PositionReaderInterface, LinearPositions, ArbitraryPo sitions> | |
| 1831 PositionReader; | |
| 1832 | |
| 1833 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
| 1834 // MapperInterface given a point map it through the matrix. There are several sh ortcut variants. | |
| 1835 // * TranslationMapper - assumes a translation only matrix. | |
| 1836 // * XScaleMapper - assumes an X scaling and a translation. | |
| 1837 // * GeneralMapper - Does all other matricies. | |
| 1838 class MapperInterface : SkNoncopyable { | |
| 1839 public: | |
| 1840 virtual ~MapperInterface() {} | |
| 1841 virtual SkPoint Map(SkPoint position) const = 0; | |
|
mtklein
2015/11/04 17:54:11
map
herb_g
2015/11/04 21:58:42
Done.
| |
| 1842 }; | |
| 1843 | |
|
mtklein
2015/11/04 17:54:11
Let's write down a formula for Map explicitly in t
herb_g
2015/11/04 21:58:42
This code faithfully reproduces the existing code.
| |
| 1844 class TranslationMapper final : public MapperInterface { | |
| 1845 public: | |
| 1846 TranslationMapper(const SkMatrix& matrix, const SkPoint origin) | |
| 1847 : fTranslate(matrix.mapXY(origin.fX, origin.fY)) { } | |
| 1848 SkPoint Map(SkPoint position) const override { | |
| 1849 return position + fTranslate; | |
| 1850 } | |
| 1851 | |
| 1852 private: | |
| 1853 const SkPoint fTranslate; | |
| 1854 }; | |
| 1855 | |
| 1856 class XScaleMapper final : public MapperInterface { | |
| 1857 public: | |
| 1858 XScaleMapper(const SkMatrix& matrix, const SkPoint origin) | |
| 1859 : fTranslate(matrix.mapXY(origin.fX, origin.fY)) | |
| 1860 , fXScale(matrix.getScaleX()) { } | |
| 1861 SkPoint Map(SkPoint position) const override { | |
| 1862 return {SkScalarMul(fXScale, position.fX) + fTranslate.fX, fTranslate.fY }; | |
| 1863 } | |
| 1864 | |
| 1865 private: | |
| 1866 const SkPoint fTranslate; | |
| 1867 const SkScalar fXScale; | |
| 1868 }; | |
| 1869 | |
| 1870 class GeneralMapper final : public MapperInterface { | |
| 1871 public: | |
| 1872 GeneralMapper(const SkMatrix& matrix, const SkPoint origin) | |
|
mtklein
2015/11/04 17:54:11
// Caller must keep matrix alive.
herb_g
2015/11/04 21:58:42
Done.
| |
| 1873 : fOrigin(origin) | |
| 1874 , fMatrix(matrix) | |
| 1875 , fMapProc(matrix.getMapXYProc()) { } | |
| 1876 SkPoint Map(SkPoint position) const override { | |
| 1877 SkPoint result; | |
| 1878 fMapProc(fMatrix, position.fX + fOrigin.fX, position.fY + fOrigin.fY, &r esult); | |
| 1879 return result; | |
| 1880 } | |
| 1881 | |
| 1882 private: | |
| 1883 const SkPoint fOrigin; | |
| 1884 const SkMatrix& fMatrix; | |
| 1885 const SkMatrix::MapXYProc fMapProc; | |
| 1886 }; | |
| 1887 | |
| 1888 typedef PolymorphicVariant<MapperInterface, TranslationMapper, XScaleMapper, Gen eralMapper> Mapper; | |
|
mtklein
2015/11/04 17:54:12
So, under this scheme, we're always going to occup
herb_g
2015/11/04 21:58:42
The maximum this stores is an SkPoint and two poin
| |
| 1889 | |
| 1890 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
| 1891 // Text alignment handles shifting the glyph based on its width. | |
| 1892 template <SkPaint::Align textAlignment> | |
|
mtklein
2015/11/04 17:54:12
Reading this file is a serious cognitive load. Gi
herb_g
2015/11/04 21:58:41
Done.
| |
| 1893 static SkPoint text_alignment_adjustment(const SkGlyph& glyph) { | |
| 1894 switch (textAlignment) { | |
| 1895 case SkPaint::kLeft_Align: | |
| 1896 return {0.0f, 0.0f}; | |
| 1897 break; | |
| 1898 case SkPaint::kCenter_Align: | |
| 1899 return {SkFixedToScalar(glyph.fAdvanceX >> 1), | |
| 1900 SkFixedToScalar(glyph.fAdvanceY >> 1)}; | |
| 1901 break; | |
| 1902 case SkPaint::kRight_Align: | |
| 1903 return {SkFixedToScalar(glyph.fAdvanceX), | |
| 1904 SkFixedToScalar(glyph.fAdvanceY)}; | |
| 1905 break; | |
| 1906 } | |
| 1907 // Even though the entire enum is covered above, MVSC doesn't think so. Make it happy. | |
|
mtklein
2015/11/04 17:54:12
Might be nice to SkASSERT(false); too.
herb_g
2015/11/04 21:58:42
Done.
| |
| 1908 return {0.0f, 0.0f}; | |
| 1909 } | |
| 1910 | |
| 1911 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
| 1912 // Axis alignment are handled by NoAlignment, XAxisAlignment, and YAxisAlignment . They | |
| 1913 // handle aligning rounding to whole pixels of either the X axis or the Y axis. The XAlignment | |
| 1914 // and YAlignment functions produce a suitable position for the glyph cache to p roduce the | |
| 1915 // correct alignment. If a position is aligned with an axis a shortcut of 0 is u sed for the | |
| 1916 // sub-pixel position. | |
| 1917 | |
| 1918 static const SkScalar kSubpixelRounding = SkFixedToScalar(SkGlyph::kSubpixelRoun d); | |
|
mtklein
2015/11/04 17:54:12
Doesn't this require a pre-main call?
herb_g
2015/11/04 21:58:42
No. SkFixedToScalar is actually a macro. There are
| |
| 1919 | |
| 1920 struct NoAlignment { | |
| 1921 static SkPoint Rounding() { return {kSubpixelRounding, kSubpixelRounding}; } | |
|
mtklein
2015/11/04 17:54:12
rounding, xAlignment, yAlignment
herb_g
2015/11/04 21:58:42
Re-did all of this.
| |
| 1922 static SkFixed XAlignment(SkScalar x) { return SkScalarToFixed(x + kSubpixel Rounding); } | |
| 1923 static SkFixed YAlignment(SkScalar y) { return SkScalarToFixed(y + kSubpixel Rounding); } | |
| 1924 }; | |
|
mtklein
2015/11/04 17:54:11
Again, simplifying, think there's any harm in expr
herb_g
2015/11/04 21:58:43
Done.
| |
| 1925 | |
| 1926 struct XAxisAlignment { | |
| 1927 static SkPoint Rounding() { return {SkFixedToScalar(SkGlyph::kSubpixelRound) , SK_ScalarHalf}; } | |
| 1928 static SkFixed XAlignment(SkScalar x) { return SkScalarToFixed(x + kSubpixel Rounding); } | |
| 1929 static SkFixed YAlignment(SkScalar y) { return 0; } | |
| 1930 }; | |
| 1931 | |
| 1932 struct YAxisAlignment { | |
| 1933 static SkPoint Rounding() { return {SK_ScalarHalf, kSubpixelRounding}; } | |
| 1934 static SkFixed XAlignment(SkScalar x) { return 0; } | |
| 1935 static SkFixed YAlignment(SkScalar y) { return SkScalarToFixed(y + kSubpixel Rounding); } | |
| 1936 }; | |
| 1937 | |
| 1938 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
| 1939 // GlyphFindAndPlaceInterface given the text and position finds the correct glyp h and does glyph | |
| 1940 // specific position adjustment. The FindAndPositionGlyph method takes text and position and calls | |
| 1941 // processOneGlyph with the correct glyph, final position and rounding terms. Th e final position | |
| 1942 // is not rounded yet and is the responsibility of processOneGlyph. | |
| 1943 template <typename GlyphProcessor> | |
| 1944 class GlyphFindAndPlaceInterface : SkNoncopyable { | |
| 1945 public: | |
| 1946 struct Result { | |
| 1947 const SkGlyph* fGlyph; | |
| 1948 Sk48Dot16 fX; | |
| 1949 Sk48Dot16 fY; | |
| 1950 }; | |
| 1951 virtual ~GlyphFindAndPlaceInterface() { }; | |
|
mtklein
2015/11/04 17:54:11
Mixing templates and virtuals is getting me kind o
herb_g
2015/11/04 21:58:42
Acknowledged.
| |
| 1952 // This should be a pure virtual, but older versions of clang have a bug tha t causes a | |
| 1953 // compile error. | |
|
mtklein
2015/11/04 17:54:11
Can you tack on Clang <= vX.Y so we know when to t
herb_g
2015/11/04 21:58:42
Done.
| |
| 1954 virtual void FindAndPositionGlyph(const char **text, SkPoint position, | |
|
mtklein
2015/11/04 17:54:12
findAndPositionGlyph
herb_g
2015/11/04 21:58:42
Done.
| |
| 1955 GlyphProcessor&& processOneGlyph) {}; | |
| 1956 }; | |
| 1957 | |
| 1958 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
| 1959 // GlyphFindAndPlaceForSubpixel handles finding and placing glyphs when sub-pixe l positioning is | |
| 1960 // requested. After it has found a placed the glyph it calls the templated funct ion | |
| 1961 // GlyphProcessor in order to actually perform an action. | |
| 1962 template <typename GlyphProcessor, SkPaint::Align textAlignment, typename axisAl ignment> | |
| 1963 class GlyphFindAndPlaceForSubpixel final : public GlyphFindAndPlaceInterface<Gly phProcessor> { | |
| 1964 public: | |
| 1965 GlyphFindAndPlaceForSubpixel(SkGlyphCache* cache, SkDrawCacheProc glyphCache Proc) | |
| 1966 : fCache(cache) | |
| 1967 , fGlyphCacheProc(glyphCacheProc) { | |
| 1968 } | |
| 1969 void FindAndPositionGlyph(const char** text, SkPoint position, | |
| 1970 GlyphProcessor&& processOneGlyph) override { | |
| 1971 SkPoint finalPosition = position; | |
| 1972 if (textAlignment != SkPaint::kLeft_Align) { | |
| 1973 // Get the width of an un-sub-pixel positioned glyph for calculating the alignment. | |
| 1974 // This is not needed for kLeftAlign because its adjustment is alway s {0, 0}. | |
| 1975 const char* tempText = *text; | |
| 1976 const SkGlyph& metricGlyph = fGlyphCacheProc(fCache, &tempText, 0, 0 ); | |
| 1977 | |
| 1978 if (metricGlyph.fWidth <= 0) { | |
| 1979 return; | |
| 1980 } | |
| 1981 | |
| 1982 // Adjust the final position by the alignment adjustment. | |
| 1983 finalPosition -= text_alignment_adjustment<textAlignment>(metricGlyp h); | |
| 1984 } | |
| 1985 | |
| 1986 // Find the glyph. | |
| 1987 const SkGlyph& renderGlyph = fGlyphCacheProc( | |
| 1988 fCache, text, | |
| 1989 axisAlignment::XAlignment(finalPosition.fX), | |
| 1990 axisAlignment::YAlignment(finalPosition.fY)); | |
| 1991 | |
| 1992 // If the glyph has no width (no pixels) then don't bother processing it . | |
| 1993 if (renderGlyph.fWidth > 0) { | |
| 1994 processOneGlyph(renderGlyph, finalPosition, axisAlignment::Rounding( )); | |
| 1995 } | |
| 1996 } | |
| 1997 | |
| 1998 private: | |
| 1999 SkGlyphCache* const fCache; | |
| 2000 SkDrawCacheProc fGlyphCacheProc; | |
| 2001 }; | |
| 2002 | |
| 2003 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
| 2004 // GlyphFindAndPlaceForFullPixel handles finding and placing glyphs when no sub- pixel positioning | |
| 2005 // is requested. | |
| 2006 template <typename GlyphProcessor, SkPaint::Align textAlignment> | |
| 2007 class GlyphFindAndPlaceForFullPixel final : public GlyphFindAndPlaceInterface<Gl yphProcessor> { | |
| 2008 public: | |
| 2009 GlyphFindAndPlaceForFullPixel(SkGlyphCache* cache, SkDrawCacheProc glyphCach eProc) | |
| 2010 : fCache(cache) | |
| 2011 , fGlyphCacheProc(glyphCacheProc) { } | |
| 2012 void FindAndPositionGlyph(const char** text, SkPoint position, | |
| 2013 GlyphProcessor&& processOneGlyph) override { | |
| 2014 SkPoint finalPosition = position; | |
| 2015 const SkGlyph& glyph = fGlyphCacheProc(fCache, text, 0, 0); | |
| 2016 if (glyph.fWidth <= 0) { | |
| 2017 return; | |
| 2018 } | |
| 2019 finalPosition -= text_alignment_adjustment<textAlignment>(glyph); | |
| 2020 processOneGlyph(glyph, finalPosition, {SK_ScalarHalf, SK_ScalarHalf}); | |
| 2021 } | |
| 2022 | |
| 2023 private: | |
| 2024 SkGlyphCache* const fCache; | |
| 2025 SkDrawCacheProc fGlyphCacheProc; | |
| 2026 }; | |
| 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. | |
|
mtklein
2015/11/04 17:54:12
What's the code-size impact of all these new class
herb_g
2015/11/04 21:58:42
According too objdump
The sub-pixel variants take
| |
| 2037 template <typename GlyphProcessor> | |
| 2038 using GlyphFindAndPlace = | |
| 2039 PolymorphicVariant< | |
| 2040 GlyphFindAndPlaceInterface<GlyphProcessor>, | |
| 2041 // Subpixel | |
| 2042 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kLeft_Align, No Alignment >, | |
| 2043 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kLeft_Align, XA xisAlignment>, | |
| 2044 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kLeft_Align, YA xisAlignment>, | |
| 2045 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kCenter_Align, No Alignment >, | |
| 2046 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kCenter_Align, XA xisAlignment>, | |
| 2047 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kCenter_Align, YA xisAlignment>, | |
| 2048 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kRight_Align, No Alignment >, | |
| 2049 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kRight_Align, XA xisAlignment>, | |
| 2050 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kRight_Align, YA xisAlignment>, | |
| 2051 // Full pixel | |
| 2052 GlyphFindAndPlaceForFullPixel<GlyphProcessor, SkPaint::kLeft_Align >, | |
| 2053 GlyphFindAndPlaceForFullPixel<GlyphProcessor, SkPaint::kCenter_Align>, | |
| 2054 GlyphFindAndPlaceForFullPixel<GlyphProcessor, SkPaint::kRight_Align > | |
| 2055 >; | |
| 2056 | |
| 2057 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
| 2058 // init_subpixel is a helper function for initializing all the variants of | |
| 2059 // GlyphFindAndPlaceForSubpixel. | |
| 2060 template <typename GlyphProcessor, SkPaint::Align textAlignment> | |
| 2061 static void init_subpixel( | |
| 2062 typename GlyphFindAndPlace<GlyphProcessor>::Variants* to_init, | |
| 2063 SkAxisAlignment axisAlignment, | |
| 2064 SkGlyphCache* cache, | |
| 2065 SkDrawCacheProc glyphCacheProc) { | |
| 2066 switch (axisAlignment) { | |
| 2067 case kX_SkAxisAlignment: | |
| 2068 to_init->template Init<GlyphFindAndPlaceForSubpixel< | |
| 2069 GlyphProcessor, textAlignment, XAxisAlignment>>( | |
| 2070 cache, glyphCacheProc); | |
| 2071 break; | |
| 2072 case kNone_SkAxisAlignment: | |
| 2073 to_init->template Init<GlyphFindAndPlaceForSubpixel< | |
| 2074 GlyphProcessor, textAlignment, NoAlignment>>( | |
| 2075 cache, glyphCacheProc); | |
| 2076 break; | |
| 2077 case kY_SkAxisAlignment: | |
| 2078 to_init->template Init<GlyphFindAndPlaceForSubpixel< | |
| 2079 GlyphProcessor, textAlignment, YAxisAlignment>>( | |
| 2080 cache, glyphCacheProc); | |
| 2081 break; | |
| 2082 } | |
| 2083 } | |
| 2084 | |
| 2085 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
| 2086 // SpecializedProcessPosText is a version of ProcessPosText that de-virtualizes the different | |
| 2087 // components used. This allows greater inlining freedom to the compiler. Curren tly, there is | |
| 2088 // only one variant that is used: sub-pixel position, left-aligned, x-axis-align ed, translation, | |
| 2089 // and one scalar per position entry. | |
| 2090 template <typename GlyphProcessor> | |
| 2091 static void SpecializedProcessPosText(const char *const text, size_t byteLength, | |
|
mtklein
2015/11/04 17:54:11
specialized_process_pos_text
herb_g
2015/11/04 21:58:43
Done.
| |
| 2092 const SkPoint &offset, const SkMatrix &mat rix, | |
| 2093 const SkScalar *const pos, SkDrawCacheProc &glyphCacheProc, | |
| 2094 SkGlyphCache *cache, GlyphProcessor &&proc essOneGlyph) { | |
| 2095 typedef GlyphFindAndPlaceForSubpixel< | |
| 2096 GlyphProcessor, SkPaint::kLeft_Align, XAxisAlignment> Positioner; | |
| 2097 LinearPositions positions{pos}; | |
| 2098 TranslationMapper mapper{matrix, offset}; | |
| 2099 Positioner positioner{cache, glyphCacheProc}; | |
| 2100 const char* cursor = text; | |
| 2101 const char* stop = text + byteLength; | |
| 2102 while (cursor < stop) { | |
| 2103 SkPoint mappedPoint = mapper.TranslationMapper::Map(positions.LinearPosi tions::NextPoint()); | |
| 2104 positioner.Positioner::FindAndPositionGlyph( | |
| 2105 &cursor, mappedPoint, skstd::forward<GlyphProcessor>(processOneGlyph )); | |
| 2106 } | |
| 2107 } | |
| 2108 | |
| 2109 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
| 2110 // ProcessPosText handles all cases for finding and positioning glyphs. It has a very large | |
| 2111 // multiplicity. | |
| 2112 // * Sub-pixel positioning (2) - use sub-pixel positioning. | |
| 2113 // * Text alignment (3) - text alignment with respect to the glyph's width. | |
| 2114 // * Matrix type (3) - special cases for translation and X-coordinate scaling. | |
| 2115 // * Components per position (2) - the positions vector can have a common Y with different Xs, or | |
| 2116 // XY-pairs. | |
| 2117 // * Axis Alignment (for sub-pixel positioning) (3) - when using sub-pixel posit ioning, round to | |
| 2118 // a whole coordinate instead of using sub-pixel positioning. | |
| 2119 // The number of variations is 108 for sub-pixel and 36 for full-pixel. | |
| 2120 // This routine handles all of them using inline polymorphic variable (no heap a llocation). | |
| 2121 template <typename GlyphProcessor> | |
| 2122 static void ProcessPosText(const char text[], size_t byteLength, | |
| 2123 const SkPoint& offset, const SkMatrix& matrix, | |
| 2124 const SkScalar pos[], int scalarsPerPosition, | |
| 2125 SkPaint::Align textAlignment, SkDrawCacheProc& glyph CacheProc, | |
| 2126 SkGlyphCache* cache, GlyphProcessor&& processOneGlyp h) { | |
| 2127 | |
| 2128 PositionReader positionReader { | |
|
mtklein
2015/11/04 17:54:12
I think I'd still prefer these to be written with
herb_g
2015/11/04 21:58:42
Done.
| |
| 2129 [&](PositionReader::Variants* to_init) { | |
| 2130 if (2 == scalarsPerPosition) { | |
| 2131 to_init->Init<ArbitraryPositions>(pos); | |
| 2132 } else { | |
| 2133 to_init->Init<LinearPositions>(pos); | |
| 2134 } | |
| 2135 } | |
| 2136 }; | |
| 2137 | |
| 2138 Mapper mapper { | |
| 2139 [&] (Mapper::Variants* to_init) { | |
| 2140 uint32_t mtype = matrix.getType(); | |
| 2141 if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask) | |
| 2142 || scalarsPerPosition == 2) { | |
|
mtklein
2015/11/04 17:54:12
What's scalarsPerPosition have to do with what map
herb_g
2015/11/04 21:58:43
Unfortunately, the original code uses that to dete
| |
| 2143 to_init->Init<GeneralMapper>(matrix, offset); | |
| 2144 } else if (mtype & SkMatrix::kScale_Mask) { | |
|
mtklein
2015/11/04 17:54:12
Is y-scale impossible?
herb_g
2015/11/04 21:58:41
The Skia API does not have a drawVPosText, so it i
| |
| 2145 to_init->Init<XScaleMapper>(matrix, offset); | |
| 2146 } else { | |
| 2147 to_init->Init<TranslationMapper>(matrix, offset); | |
| 2148 } | |
| 2149 } | |
| 2150 }; | |
| 2151 | |
| 2152 GlyphFindAndPlace<GlyphProcessor> findAndPosition{ | |
| 2153 [&](typename GlyphFindAndPlace<GlyphProcessor>::Variants* to_init) { | |
| 2154 if (cache->isSubpixel()) { | |
| 2155 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(m atrix); | |
| 2156 switch (textAlignment) { | |
| 2157 case SkPaint::kLeft_Align: | |
| 2158 init_subpixel<GlyphProcessor, SkPaint::kLeft_Align>( | |
| 2159 to_init, axisAlignment, cache, glyphCacheProc); | |
| 2160 break; | |
| 2161 case SkPaint::kCenter_Align: | |
| 2162 init_subpixel<GlyphProcessor, SkPaint::kCenter_Align>( | |
| 2163 to_init, axisAlignment, cache, glyphCacheProc); | |
| 2164 break; | |
| 2165 case SkPaint::kRight_Align: | |
| 2166 init_subpixel<GlyphProcessor, SkPaint::kRight_Align>( | |
| 2167 to_init, axisAlignment, cache, glyphCacheProc); | |
| 2168 break; | |
| 2169 } | |
| 2170 } else { | |
| 2171 switch (textAlignment) { | |
| 2172 case SkPaint::kLeft_Align: | |
| 2173 to_init->template Init<GlyphFindAndPlaceForFullPixel<Gly phProcessor, | |
| 2174 SkPaint::kLeft_Align>>( | |
| 2175 cache, glyphCacheProc); | |
| 2176 break; | |
| 2177 case SkPaint::kCenter_Align: | |
| 2178 to_init->template Init<GlyphFindAndPlaceForFullPixel<Gly phProcessor, | |
| 2179 SkPaint::kCenter_Align>>( | |
| 2180 cache, glyphCacheProc); | |
| 2181 break; | |
| 2182 case SkPaint::kRight_Align: | |
| 2183 to_init->template Init<GlyphFindAndPlaceForFullPixel<Gly phProcessor, | |
| 2184 SkPaint::kRight_Align>>( | |
| 2185 cache, glyphCacheProc); | |
| 2186 break; | |
| 2187 } | |
| 2188 } | |
| 2189 } | |
| 2190 }; | |
| 2191 | |
| 2192 const char* stop = text + byteLength; | |
| 2193 while (text < stop) { | |
| 2194 SkPoint mappedPoint = mapper->Map(positionReader->NextPoint()); | |
| 2195 findAndPosition->FindAndPositionGlyph( | |
| 2196 &text, mappedPoint, skstd::forward<GlyphProcessor>(processOneGlyph)) ; | |
| 2197 } | |
| 2198 } | |
| 2199 | |
| 1729 void SkDraw::drawPosText(const char text[], size_t byteLength, | 2200 void SkDraw::drawPosText(const char text[], size_t byteLength, |
| 1730 const SkScalar pos[], int scalarsPerPosition, | 2201 const SkScalar pos[], int scalarsPerPosition, |
| 1731 const SkPoint& offset, const SkPaint& paint) const { | 2202 const SkPoint& offset, const SkPaint& paint) const { |
| 1732 SkASSERT(byteLength == 0 || text != nullptr); | 2203 SkASSERT(byteLength == 0 || text != nullptr); |
| 1733 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | 2204 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
| 1734 | 2205 |
| 1735 SkDEBUGCODE(this->validate();) | 2206 SkDEBUGCODE(this->validate();) |
| 1736 | 2207 |
| 1737 // nothing to draw | 2208 // nothing to draw |
| 1738 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { | 2209 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1753 SkBlitter* blitter = nullptr; | 2224 SkBlitter* blitter = nullptr; |
| 1754 if (needsRasterTextBlit(*this)) { | 2225 if (needsRasterTextBlit(*this)) { |
| 1755 blitterChooser.choose(fDst, *fMatrix, paint); | 2226 blitterChooser.choose(fDst, *fMatrix, paint); |
| 1756 blitter = blitterChooser.get(); | 2227 blitter = blitterChooser.get(); |
| 1757 if (fRC->isAA()) { | 2228 if (fRC->isAA()) { |
| 1758 wrapper.init(*fRC, blitter); | 2229 wrapper.init(*fRC, blitter); |
| 1759 blitter = wrapper.getBlitter(); | 2230 blitter = wrapper.getBlitter(); |
| 1760 } | 2231 } |
| 1761 } | 2232 } |
| 1762 | 2233 |
| 1763 const char* stop = text + byteLength; | |
| 1764 SkTextAlignProc alignProc(paint.getTextAlign()); | |
| 1765 SkDraw1Glyph d1g; | 2234 SkDraw1Glyph d1g; |
| 1766 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); | 2235 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); |
| 1767 SkTextMapStateProc tmsProc(*fMatrix, offset, scalarsPerPosition); | |
| 1768 | 2236 |
|
mtklein
2015/11/04 17:54:12
There's something to be said for this existing cod
herb_g
2015/11/04 21:58:43
Acknowledged.
| |
| 1769 if (cache->isSubpixel()) { | 2237 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(*fMatrix); |
| 1770 // maybe we should skip the rounding if linearText is set | 2238 uint32_t mtype = fMatrix->getType(); |
| 1771 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix); | 2239 SkPaint::Align textAlignment = paint.getTextAlign(); |
| 1772 | 2240 if (scalarsPerPosition == 1 |
| 1773 SkFixed fxMask = ~0; | 2241 && textAlignment == SkPaint::kLeft_Align |
| 1774 SkFixed fyMask = ~0; | 2242 && axisAlignment == kX_SkAxisAlignment |
| 1775 if (kX_SkAxisAlignment == baseline) { | 2243 && cache->isSubpixel() |
| 1776 fyMask = 0; | 2244 && (mtype |
| 1777 d1g.fHalfSampleY = SK_ScalarHalf; | 2245 & (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask |
| 1778 } else if (kY_SkAxisAlignment == baseline) { | 2246 | SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) <= |
| 1779 fxMask = 0; | 2247 SkMatrix::kTranslate_Mas k) { |
| 1780 d1g.fHalfSampleX = SK_ScalarHalf; | 2248 SpecializedProcessPosText( |
| 1781 } | 2249 text, byteLength, offset, *fMatrix, pos, glyphCacheProc, cache, |
| 1782 | 2250 [&](const SkGlyph &glyph, SkPoint position, SkPoint rounding) { |
| 1783 if (SkPaint::kLeft_Align == paint.getTextAlign()) { | 2251 position += rounding; |
| 1784 while (text < stop) { | 2252 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 } | 2253 } |
| 1798 } else { | 2254 ); |
| 1799 while (text < stop) { | 2255 } else { |
| 1800 const char* currentText = text; | 2256 ProcessPosText( |
| 1801 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); | 2257 text, byteLength, offset, *fMatrix, pos, scalarsPerPosition, |
| 1802 | 2258 textAlignment, glyphCacheProc, cache, |
| 1803 if (metricGlyph.fWidth) { | 2259 [&](const SkGlyph &glyph, SkPoint position, SkPoint rounding) { |
| 1804 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) | 2260 position += rounding; |
| 1805 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) | 2261 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 } | 2262 } |
| 1827 } | 2263 ); |
| 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 } | 2264 } |
| 1866 } | 2265 } |
| 1867 | 2266 |
| 1868 #if defined _WIN32 && _MSC_VER >= 1300 | 2267 #if defined _WIN32 && _MSC_VER >= 1300 |
| 1869 #pragma warning ( pop ) | 2268 #pragma warning ( pop ) |
| 1870 #endif | 2269 #endif |
| 1871 | 2270 |
| 1872 /////////////////////////////////////////////////////////////////////////////// | 2271 /////////////////////////////////////////////////////////////////////////////// |
| 1873 | 2272 |
| 1874 static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) { | 2273 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); | 2657 mask->fImage = SkMask::AllocImage(size); |
| 2259 memset(mask->fImage, 0, mask->computeImageSize()); | 2658 memset(mask->fImage, 0, mask->computeImageSize()); |
| 2260 } | 2659 } |
| 2261 | 2660 |
| 2262 if (SkMask::kJustComputeBounds_CreateMode != mode) { | 2661 if (SkMask::kJustComputeBounds_CreateMode != mode) { |
| 2263 draw_into_mask(*mask, devPath, style); | 2662 draw_into_mask(*mask, devPath, style); |
| 2264 } | 2663 } |
| 2265 | 2664 |
| 2266 return true; | 2665 return true; |
| 2267 } | 2666 } |
| OLD | NEW |