Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: src/core/SkDraw.cpp

Issue 1420973005: Refactor glyph selection and positioning (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fix comment Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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.
1734 #if 0
1735 template <typename... Ts> union SameSizeAndAlignmentAs;
1736
1737 template <typename H>
1738 union SameSizeAndAlignmentAs<H> {
1739 SameSizeAndAlignmentAs () {}
1740 ~SameSizeAndAlignmentAs () {};
1741
1742 private:
1743 H unused;
1744 };
1745
1746 template <typename H, typename... Ts>
1747 union SameSizeAndAlignmentAs<H, Ts...> {
1748 SameSizeAndAlignmentAs () {}
1749 ~SameSizeAndAlignmentAs () {};
1750
1751 private:
1752 H unused;
1753 SameSizeAndAlignmentAs<Ts...> cont_unused;
1754 };
1755
1756 #else
1757
1758 template <typename... Ts> struct SizeOf;
bungeman-skia 2015/11/02 21:09:35 Seems like this should be called something like Ma
herb_g 2015/11/02 21:26:50 Done.
1759
1760 template <typename T> struct SizeOf<T> { static const size_t value = sizeof(T); };
bungeman-skia 2015/11/02 21:09:35 It seems like this would be cleaner if the base ca
herb_g 2015/11/02 21:26:49 Done.
1761
1762 template <typename H, typename... Ts> struct SizeOf<H, Ts...> {
1763 static const size_t value =
1764 sizeof(H) >= SizeOf<Ts...>::value ? sizeof(H) : SizeOf<Ts...>::value;
1765 };
1766
1767 template <typename... Ts> struct SameSizeAndAlignmentAs {
1768 private:
1769 SkAlignedSStorage<SizeOf<Ts...>::value> unused;
1770 };
1771
1772 #endif
1773
1774 //////////////////////////////////////////////////////////////////////////////// ///////////////////
1775 // Basically UntaggedVariant is a pile of memory that can hold one of the Ts. It provides a way
bungeman-skia 2015/11/02 21:09:34 Remove 'Basically'
herb_g 2015/11/02 21:26:50 Done.
1776 // to initialize that memory in a typesafe way.
1777 template <typename... Ts>
1778 class UntaggedVariant {
1779 public:
1780 UntaggedVariant() {}
1781 ~UntaggedVariant() {}
1782 UntaggedVariant(const UntaggedVariant&) = delete;
1783 UntaggedVariant& operator=(const UntaggedVariant&) = delete;
1784 UntaggedVariant(UntaggedVariant&&) = delete;
1785 UntaggedVariant& operator=(UntaggedVariant&&) = delete;
1786 template <typename Variant, typename... Args>
1787 void Init(Args&&... args) {
1788 SkASSERT(sizeof(Variant) <= sizeof(fSpace));
1789 #ifndef SK_BUILD_FOR_WIN32
1790 SkASSERT(alignof(Variant) <= alignof(SameSizeAndAlignmentAs<Ts...>));
1791 #endif
1792 new (&fSpace) Variant(skstd::forward<Args>(args)...);
1793 }
1794
1795 private:
1796 SameSizeAndAlignmentAs<Ts...> fSpace;
1797 };
1798
1799 //////////////////////////////////////////////////////////////////////////////// ////////////////////
1800 // PolymorphicVariant holds supclasses of Base without slicing. Ts must be supcl asses of Base.
bungeman-skia 2015/11/02 21:09:34 Is this supposed to be super classes or subclasses
herb_g 2015/11/02 21:26:50 Done.
1801 template <typename Base, typename... Ts>
1802 class PolymorphicVariant {
1803 public:
1804 typedef UntaggedVariant<Ts...> Variants;
1805 template <typename Initializer>
1806 PolymorphicVariant(Initializer&& initializer) {
1807 skstd::forward<Initializer>(initializer)(&fVariants);
1808 }
1809 ~PolymorphicVariant() { get()->~Base(); }
1810 Base* get() const { return (Base*) &fVariants; }
1811 Base* operator->() const { return get(); }
1812 Base& operator*() const { return *get(); }
1813
1814 private:
1815 Variants fVariants;
1816 };
1817
1818
1819 class Noncopyable {
bungeman-skia 2015/11/02 21:09:34 Is there any reason why SkNoncopyable can't be use
herb_g 2015/11/02 21:26:50 Changed to SkNoncopyable. I was struggling with th
1820 public:
1821 Noncopyable() {}
1822 Noncopyable(const Noncopyable&) = delete;
1823 void operator=(const Noncopyable&) = delete;
1824 };
bungeman-skia 2015/11/02 21:09:35 Everything down to here is rather general and does
herb_g 2015/11/02 21:26:50 I hope to extract the code through ProcessPosText
1825
1826 //////////////////////////////////////////////////////////////////////////////// ////////////////////
1827 // PositionReaderInterface read a point from the pos vector.
1828 // * LinearPositions - assumes a common Y for many X values.
1829 // * ArbitraryPositions - a list of (X,Y) pairs.
1830 class PositionReaderInterface : Noncopyable {
1831 public:
1832 virtual ~PositionReaderInterface() { }
1833 virtual const SkPoint NextPoint() = 0;
1834 };
1835
1836 class LinearPositions final : public PositionReaderInterface {
1837 public:
1838 LinearPositions(const SkScalar* positions)
1839 : fPositions(positions) { }
1840
1841 LinearPositions(const LinearPositions&) = delete;
1842
1843 const SkPoint NextPoint() override {
1844 SkScalar x = *fPositions++;
1845 return {x, 0};
1846 }
1847 private:
1848 const SkScalar* fPositions;
1849 };
1850
1851 class ArbitraryPositions final : public PositionReaderInterface {
1852 public:
1853 ArbitraryPositions(const SkScalar* positions)
1854 : fPositions(positions) { }
1855 const SkPoint NextPoint() override {
1856 SkPoint to_return {fPositions[0], fPositions[1]};
1857 fPositions += 2;
1858 return to_return;
1859 }
1860
1861 private:
1862 const SkScalar* fPositions;
1863 };
1864
1865 typedef PolymorphicVariant<PositionReaderInterface, LinearPositions, ArbitraryPo sitions>
1866 PositionReader;
1867
1868 //////////////////////////////////////////////////////////////////////////////// ////////////////////
1869 // MapperInterface given a point map it through the matrix. There are several sh ortcut variants.
1870 // * TranslationMapper - assumes a translation only matrix.
1871 // * XScaleMapper - assumes an X scaling and a translation.
1872 // * GeneralMapper - Does all other matricies.
1873 class MapperInterface : Noncopyable {
1874 public:
1875 virtual ~MapperInterface() {}
1876 virtual SkPoint Map(SkPoint position) const = 0;
1877 };
1878
1879 class TranslationMapper final : public MapperInterface {
1880 public:
1881 TranslationMapper(const SkMatrix& matrix, const SkPoint origin)
1882 : fTranslate(matrix.mapXY(origin.fX, origin.fY)) { }
1883 SkPoint Map(SkPoint position) const override {
1884 return position + fTranslate;
1885 }
1886
1887 private:
1888 const SkPoint fTranslate;
1889 };
1890
1891 class XScaleMapper final : public MapperInterface {
1892 public:
1893 XScaleMapper(const SkMatrix& matrix, const SkPoint origin)
1894 : fTranslate(matrix.mapXY(origin.fX, origin.fY))
1895 , fXScale(matrix.getScaleX()) { }
1896 SkPoint Map(SkPoint position) const override {
1897 return {SkScalarMul(fXScale, position.fX) + fTranslate.fX, fTranslate.fY };
1898 }
1899
1900 private:
1901 const SkPoint fTranslate;
1902 const SkScalar fXScale;
1903 };
1904
1905 class GeneralMapper final : public MapperInterface {
1906 public:
1907 GeneralMapper(const SkMatrix& matrix, const SkPoint origin)
1908 : fOrigin(origin)
1909 , fMatrix(matrix)
1910 , fMapProc(matrix.getMapXYProc()) { }
1911 SkPoint Map(SkPoint position) const override {
1912 SkPoint result;
1913 fMapProc(fMatrix, position.fX + fOrigin.fX, position.fY + fOrigin.fY, &r esult);
1914 return result;
1915 }
1916
1917 private:
1918 const SkPoint fOrigin;
1919 const SkMatrix& fMatrix;
1920 const SkMatrix::MapXYProc fMapProc;
1921 };
1922
1923 typedef PolymorphicVariant<MapperInterface, TranslationMapper, XScaleMapper, Gen eralMapper> Mapper;
1924
1925 //////////////////////////////////////////////////////////////////////////////// ////////////////////
1926 // Text alignment handles shifting the glyph based on its width.
1927 template <SkPaint::Align textAlignment>
1928 static SkPoint text_alignment_adjustment(const SkGlyph& glyph) {
1929 switch (textAlignment) {
1930 case SkPaint::kLeft_Align:
1931 return {0.0f, 0.0f};
1932 break;
1933 case SkPaint::kCenter_Align:
1934 return {SkFixedToScalar(glyph.fAdvanceX >> 1),
1935 SkFixedToScalar(glyph.fAdvanceY >> 1)};
1936 break;
1937 case SkPaint::kRight_Align:
1938 return {SkFixedToScalar(glyph.fAdvanceX),
1939 SkFixedToScalar(glyph.fAdvanceY)};
1940 break;
1941 }
1942 // Even though the entire enum is covered above, MVSC doesn't think so. Make it happy.
1943 return {0.0f, 0.0f};
1944 }
1945
1946 //////////////////////////////////////////////////////////////////////////////// ////////////////////
1947 // Axis alignment are handled by NoAlignment, XAxisAlignment, and YAxisAlignment . They
1948 // handle aligning rounding to whole pixels of either the X axis or the Y axis. The XAlignment
1949 // and YAlignment functions produce a suitable position for the glyph cache to p roduce the
1950 // correct alignment. If a position is aligned with an axis a shortcut of 0 is u sed for the
1951 // sub-pixel position.
1952
1953 static const SkScalar kSubpixelRounding = SkFixedToScalar(SkGlyph::kSubpixelRoun d);
1954
1955 struct NoAlignment {
1956 static SkPoint Rounding() { return {kSubpixelRounding, kSubpixelRounding}; }
1957 static SkFixed XAlignment(SkScalar x) { return SkScalarToFixed(x + kSubpixel Rounding); }
1958 static SkFixed YAlignment(SkScalar y) { return SkScalarToFixed(y + kSubpixel Rounding); }
1959 };
1960
1961 struct XAxisAlignment {
1962 static SkPoint Rounding() { return {SkFixedToScalar(SkGlyph::kSubpixelRound) , SK_ScalarHalf}; }
1963 static SkFixed XAlignment(SkScalar x) { return SkScalarToFixed(x + kSubpixel Rounding); }
1964 static SkFixed YAlignment(SkScalar y) { return 0; }
1965 };
1966
1967 struct YAxisAlignment {
1968 static SkPoint Rounding() { return {SK_ScalarHalf, kSubpixelRounding}; }
1969 static SkFixed XAlignment(SkScalar x) { return 0; }
1970 static SkFixed YAlignment(SkScalar y) { return SkScalarToFixed(y + kSubpixel Rounding); }
1971 };
1972
1973 //////////////////////////////////////////////////////////////////////////////// ////////////////////
1974 // GlyphFindAndPlaceInterface given the text and position finds the correct glyp h and does glyph
1975 // specific position adjustment. The FindAndPositionGlyph method takes text and position and calls
1976 // processOneGlyph with the correct glyph, final position and rounding terms. Th e final position
1977 // is not rounded yet and is the responsibility of processOneGlyph.
1978 template <typename GlyphProcessor>
1979 class GlyphFindAndPlaceInterface : Noncopyable {
1980 public:
1981 struct Result {
1982 const SkGlyph* fGlyph;
1983 Sk48Dot16 fX;
1984 Sk48Dot16 fY;
1985 };
1986 virtual ~GlyphFindAndPlaceInterface() { };
1987 // This should be a pure virtual, but older versions of clang have a bug tha t causes a
1988 // compile error.
1989 virtual void FindAndPositionGlyph(const char **text, SkPoint position,
1990 GlyphProcessor&& processOneGlyph) {};
1991 };
1992
1993 //////////////////////////////////////////////////////////////////////////////// ////////////////////
1994 // GlyphFindAndPlaceForSubpixel handles finding and placing glyphs when sub-pixe l positioning is
1995 // requested. After it has found a placed the glyph it calls the templated funct ion
1996 // GlyphProcessor in order to actually perform an action.
1997 template <typename GlyphProcessor, SkPaint::Align textAlignment, typename axisAl ignment>
1998 class GlyphFindAndPlaceForSubpixel final : public GlyphFindAndPlaceInterface<Gly phProcessor> {
1999 public:
2000 GlyphFindAndPlaceForSubpixel(SkGlyphCache* cache, SkDrawCacheProc glyphCache Proc)
2001 : fCache(cache)
2002 , fGlyphCacheProc(glyphCacheProc) {
2003 }
2004 void FindAndPositionGlyph(const char** text, SkPoint position,
2005 GlyphProcessor&& processOneGlyph) override {
2006 SkPoint finalPosition = position;
2007 if (textAlignment != SkPaint::kLeft_Align) {
2008 // Get the width of an un-sub-pixel positioned glyph for calculating the alignment.
2009 // This is not needed for kLeftAlign because its adjustment is alway s {0, 0}.
2010 const char* tempText = *text;
2011 const SkGlyph& metricGlyph = fGlyphCacheProc(fCache, &tempText, 0, 0 );
2012
2013 if (metricGlyph.fWidth <= 0) {
2014 return;
2015 }
2016
2017 // Adjust the final position by the alignment adjustment.
2018 finalPosition -= text_alignment_adjustment<textAlignment>(metricGlyp h);
2019 }
2020
2021 // Find the glyph.
2022 const SkGlyph& renderGlyph = fGlyphCacheProc(
2023 fCache, text,
2024 axisAlignment::XAlignment(finalPosition.fX),
2025 axisAlignment::YAlignment(finalPosition.fY));
2026
2027 // If the glyph has no width (no pixels) then don't bother processing it .
2028 if (renderGlyph.fWidth > 0) {
2029 processOneGlyph(renderGlyph, finalPosition, axisAlignment::Rounding( ));
2030 }
2031 }
2032
2033 private:
2034 SkGlyphCache* const fCache;
2035 SkDrawCacheProc fGlyphCacheProc;
2036 };
2037
2038 //////////////////////////////////////////////////////////////////////////////// ////////////////////
2039 // GlyphFindAndPlaceForFullPixel handles finding and placing glyphs when no sub- pixel positioning
2040 // is requested.
2041 template <typename GlyphProcessor, SkPaint::Align textAlignment>
2042 class GlyphFindAndPlaceForFullPixel final : public GlyphFindAndPlaceInterface<Gl yphProcessor> {
2043 public:
2044 GlyphFindAndPlaceForFullPixel(SkGlyphCache* cache, SkDrawCacheProc glyphCach eProc)
2045 : fCache(cache)
2046 , fGlyphCacheProc(glyphCacheProc) { }
2047 void FindAndPositionGlyph(const char** text, SkPoint position,
2048 GlyphProcessor&& processOneGlyph) override {
2049 SkPoint finalPosition = position;
2050 const SkGlyph& glyph = fGlyphCacheProc(fCache, text, 0, 0);
2051 if (glyph.fWidth <= 0) {
2052 return;
2053 }
2054 finalPosition -= text_alignment_adjustment<textAlignment>(glyph);
2055 processOneGlyph(glyph, finalPosition, {SK_ScalarHalf, SK_ScalarHalf});
2056 }
2057
2058 private:
2059 SkGlyphCache* const fCache;
2060 SkDrawCacheProc fGlyphCacheProc;
2061 };
2062
2063 //////////////////////////////////////////////////////////////////////////////// ////////////////////
2064 // GlyphFindAndPlace is a large variant that encapsulates the multiple types of finding and
2065 // placing a glyph. There are three factors that go into the different factors.
2066 // * Is sub-pixel positioned - a boolean that says whether to use sub-pixel posi tioning.
2067 // * Text alignment - indicates if the glyph should be placed to the right, cent ered or left of a
2068 // given position.
2069 // * Axis alignment - indicates if the glyphs final sub-pixel position should be rounded to a
2070 // whole pixel if the glyph is aligned with an axis. This is only used for sub -pixel positioning
2071 // and allows the baseline to look crisp.
2072 template <typename GlyphProcessor>
2073 using GlyphFindAndPlace =
2074 PolymorphicVariant<
2075 GlyphFindAndPlaceInterface<GlyphProcessor>,
2076 // Subpixel
2077 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kLeft_Align, No Alignment >,
2078 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kLeft_Align, XA xisAlignment>,
2079 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kLeft_Align, YA xisAlignment>,
2080 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kCenter_Align, No Alignment >,
2081 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kCenter_Align, XA xisAlignment>,
2082 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kCenter_Align, YA xisAlignment>,
2083 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kRight_Align, No Alignment >,
2084 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kRight_Align, XA xisAlignment>,
2085 GlyphFindAndPlaceForSubpixel< GlyphProcessor, SkPaint::kRight_Align, YA xisAlignment>,
2086 // Full pixel
2087 GlyphFindAndPlaceForFullPixel<GlyphProcessor, SkPaint::kLeft_Align >,
2088 GlyphFindAndPlaceForFullPixel<GlyphProcessor, SkPaint::kCenter_Align>,
2089 GlyphFindAndPlaceForFullPixel<GlyphProcessor, SkPaint::kRight_Align >
2090 >;
2091
2092 //////////////////////////////////////////////////////////////////////////////// ////////////////////
2093 // init_subpixel is a helper function for initializing all the variants of
2094 // GlyphFindAndPlaceForSubpixel.
2095 template <typename GlyphProcessor, SkPaint::Align textAlignment>
2096 static void init_subpixel(
2097 typename GlyphFindAndPlace<GlyphProcessor>::Variants* to_init,
2098 SkAxisAlignment axisAlignment,
2099 SkGlyphCache* cache,
2100 SkDrawCacheProc glyphCacheProc) {
2101 switch (axisAlignment) {
2102 case kX_SkAxisAlignment:
2103 to_init->template Init<GlyphFindAndPlaceForSubpixel<
2104 GlyphProcessor, textAlignment, XAxisAlignment>>(
2105 cache, glyphCacheProc);
2106 break; case kNone_SkAxisAlignment:
bungeman-skia 2015/11/02 21:09:34 I think this case needs to go on the next line.
herb_g 2015/11/02 21:26:50 Done.
2107 to_init->template Init<GlyphFindAndPlaceForSubpixel<
2108 GlyphProcessor, textAlignment, NoAlignment>>(
2109 cache, glyphCacheProc);
2110 break;
2111 case kY_SkAxisAlignment:
2112 to_init->template Init<GlyphFindAndPlaceForSubpixel<
2113 GlyphProcessor, textAlignment, YAxisAlignment>>(
2114 cache, glyphCacheProc);
2115 break;
2116 }
2117 }
2118
2119 //////////////////////////////////////////////////////////////////////////////// ////////////////////
2120 // SpecializedProcessPosText is a version of ProcessPosText that de-virtualizes the different
2121 // components used. This allows greater inlining freedom to the compiler. Curren tly, there is
2122 // only one variant that is used: sub-pixel position, left-aligned, x-axis-align ed, translation,
2123 // and one scalar per position entry.
2124 template <typename GlyphProcessor>
2125 static void SpecializedProcessPosText(const char *const text, size_t byteLength,
2126 const SkPoint &offset, const SkMatrix &mat rix,
2127 const SkScalar *const pos, SkDrawCacheProc &glyphCacheProc,
2128 SkGlyphCache *cache, GlyphProcessor &&proc essOneGlyph) {
2129 typedef GlyphFindAndPlaceForSubpixel<
2130 GlyphProcessor, SkPaint::kLeft_Align, XAxisAlignment> Positioner;
2131 LinearPositions positions{pos};
2132 TranslationMapper mapper{matrix, offset};
2133 Positioner positioner{cache, glyphCacheProc};
2134 const char* cursor = text;
2135 const char* stop = text + byteLength;
2136 while (cursor < stop) {
2137 SkPoint mappedPoint = mapper.TranslationMapper::Map(positions.LinearPosi tions::NextPoint());
2138 positioner.Positioner::FindAndPositionGlyph(
2139 &cursor, mappedPoint, skstd::forward<GlyphProcessor>(processOneGlyph ));
2140 }
2141 }
2142
2143 //////////////////////////////////////////////////////////////////////////////// ////////////////////
2144 // ProcessPosText handles all cases for finding and positioning glyphs. It has a very large
2145 // multiplicity.
2146 // * Sub-pixel positioning (2) - use sub-pixel positioning.
2147 // * Text alignment (3) - text alignment with respect to the glyph's width.
2148 // * Matrix type (3) - special cases for translation and X-coordinate scaling.
2149 // * Components per position (2) - the positions vector can have a common Y with different Xs, or
2150 // XY-pairs.
2151 // * Axis Alignment (for sub-pixel positioning) (3) - when using sub-pixel posit ioning, round to
2152 // a whole coordinate instead of using sub-pixel positioning.
2153 // The number of variations is 108 for sub-pixel and 36 for full-pixel.
2154 // This routine handles all of them using inline polymorphic variable (no heap a llocation).
2155 template <typename GlyphProcessor>
2156 static void ProcessPosText(const char text[], size_t byteLength,
2157 const SkPoint& offset, const SkMatrix& matrix,
2158 const SkScalar pos[], int scalarsPerPosition,
2159 SkPaint::Align textAlignment, SkDrawCacheProc& glyph CacheProc,
2160 SkGlyphCache* cache, GlyphProcessor&& processOneGlyp h) {
2161
2162 PositionReader positionReader {
2163 [&](PositionReader::Variants* to_init) {
2164 if (2 == scalarsPerPosition) {
2165 to_init->Init<ArbitraryPositions>(pos);
2166 } else {
2167 to_init->Init<LinearPositions>(pos);
2168 }
2169 }
2170 };
2171
2172 Mapper mapper {
2173 [&] (Mapper::Variants* to_init) {
2174 uint32_t mtype = matrix.getType();
2175 if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)
2176 || scalarsPerPosition == 2) {
2177 to_init->Init<GeneralMapper>(matrix, offset);
2178 } else if (mtype & SkMatrix::kScale_Mask) {
2179 to_init->Init<XScaleMapper>(matrix, offset);
2180 } else {
2181 to_init->Init<TranslationMapper>(matrix, offset);
2182 }
2183 }
2184 };
2185
2186 GlyphFindAndPlace<GlyphProcessor> findAndPosition{
2187 [&](typename GlyphFindAndPlace<GlyphProcessor>::Variants* to_init) {
2188 if (cache->isSubpixel()) {
2189 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(m atrix);
2190 switch (textAlignment) {
2191 case SkPaint::kLeft_Align:
2192 init_subpixel<GlyphProcessor, SkPaint::kLeft_Align>(to_i nit,
bungeman-skia 2015/11/02 21:09:35 All the parameters should just go on the next line
herb_g 2015/11/02 21:26:50 Done.
2193 axisA lignment, cache,
2194 glyphCacheProc);
2195 break;
2196 case SkPaint::kCenter_Align:
2197 init_subpixel<GlyphProcessor, SkPaint::kCenter_Align>(to _init,
2198 axi sAlignment, cache,
2199 glyphCacheProc);
2200 break;
2201 case SkPaint::kRight_Align:
2202 init_subpixel<GlyphProcessor, SkPaint::kRight_Align>(to_ init,
2203 axis Alignment, cache,
2204 glyphCacheProc);
2205 break;
2206 }
2207 } else {
2208 switch (textAlignment) {
2209 case SkPaint::kLeft_Align:
2210 to_init->template Init<GlyphFindAndPlaceForFullPixel<Gly phProcessor,
2211 SkPaint::kLeft_Align>>(
2212 cache, glyphCacheProc);
2213 break;
2214 case SkPaint::kCenter_Align:
2215 to_init->template Init<GlyphFindAndPlaceForFullPixel<Gly phProcessor,
2216 SkPaint::kCenter_Align>>(
2217 cache, glyphCacheProc);
2218 break;
2219 case SkPaint::kRight_Align:
2220 to_init->template Init<GlyphFindAndPlaceForFullPixel<Gly phProcessor,
2221 SkPaint::kRight_Align>>(
2222 cache, glyphCacheProc);
2223 break;
2224 }
2225 }
2226 }
2227 };
2228
2229 const char* stop = text + byteLength;
2230 while (text < stop) {
2231 SkPoint mappedPoint = mapper->Map(positionReader->NextPoint());
2232 findAndPosition->FindAndPositionGlyph(
2233 &text, mappedPoint, skstd::forward<GlyphProcessor>(processOneGlyph)) ;
2234 }
2235 }
2236
1729 void SkDraw::drawPosText(const char text[], size_t byteLength, 2237 void SkDraw::drawPosText(const char text[], size_t byteLength,
1730 const SkScalar pos[], int scalarsPerPosition, 2238 const SkScalar pos[], int scalarsPerPosition,
1731 const SkPoint& offset, const SkPaint& paint) const { 2239 const SkPoint& offset, const SkPaint& paint) const {
1732 SkASSERT(byteLength == 0 || text != nullptr); 2240 SkASSERT(byteLength == 0 || text != nullptr);
1733 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 2241 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1734 2242
1735 SkDEBUGCODE(this->validate();) 2243 SkDEBUGCODE(this->validate();)
1736 2244
1737 // nothing to draw 2245 // nothing to draw
1738 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { 2246 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
(...skipping 14 matching lines...) Expand all
1753 SkBlitter* blitter = nullptr; 2261 SkBlitter* blitter = nullptr;
1754 if (needsRasterTextBlit(*this)) { 2262 if (needsRasterTextBlit(*this)) {
1755 blitterChooser.choose(fDst, *fMatrix, paint); 2263 blitterChooser.choose(fDst, *fMatrix, paint);
1756 blitter = blitterChooser.get(); 2264 blitter = blitterChooser.get();
1757 if (fRC->isAA()) { 2265 if (fRC->isAA()) {
1758 wrapper.init(*fRC, blitter); 2266 wrapper.init(*fRC, blitter);
1759 blitter = wrapper.getBlitter(); 2267 blitter = wrapper.getBlitter();
1760 } 2268 }
1761 } 2269 }
1762 2270
1763 const char* stop = text + byteLength;
1764 SkTextAlignProc alignProc(paint.getTextAlign());
1765 SkDraw1Glyph d1g; 2271 SkDraw1Glyph d1g;
1766 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); 2272 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint);
1767 SkTextMapStateProc tmsProc(*fMatrix, offset, scalarsPerPosition);
1768 2273
1769 if (cache->isSubpixel()) { 2274 SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(*fMatrix);
1770 // maybe we should skip the rounding if linearText is set 2275 uint32_t mtype = fMatrix->getType();
1771 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix); 2276 SkPaint::Align textAlignment = paint.getTextAlign();
1772 2277 if (scalarsPerPosition == 1
1773 SkFixed fxMask = ~0; 2278 && textAlignment == SkPaint::kLeft_Align
1774 SkFixed fyMask = ~0; 2279 && axisAlignment == kX_SkAxisAlignment
1775 if (kX_SkAxisAlignment == baseline) { 2280 && cache->isSubpixel()
1776 fyMask = 0; 2281 && (mtype
1777 d1g.fHalfSampleY = SK_ScalarHalf; 2282 & (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask
1778 } else if (kY_SkAxisAlignment == baseline) { 2283 | SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) <=
1779 fxMask = 0; 2284 SkMatrix::kTranslate_Mas k) {
1780 d1g.fHalfSampleX = SK_ScalarHalf; 2285 SpecializedProcessPosText(
1781 } 2286 text, byteLength, offset, *fMatrix, pos, glyphCacheProc, cache,
1782 2287 [&](const SkGlyph &glyph, SkPoint position, SkPoint rounding) {
1783 if (SkPaint::kLeft_Align == paint.getTextAlign()) { 2288 position += rounding;
1784 while (text < stop) { 2289 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 } 2290 }
1798 } else { 2291 );
1799 while (text < stop) { 2292 } else {
1800 const char* currentText = text; 2293 ProcessPosText(
1801 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); 2294 text, byteLength, offset, *fMatrix, pos, scalarsPerPosition,
1802 2295 textAlignment, glyphCacheProc, cache,
1803 if (metricGlyph.fWidth) { 2296 [&](const SkGlyph &glyph, SkPoint position, SkPoint rounding) {
1804 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) 2297 position += rounding;
1805 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) 2298 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, &currentText,
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 } 2299 }
1827 } 2300 );
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 } 2301 }
1866 } 2302 }
1867 2303
1868 #if defined _WIN32 && _MSC_VER >= 1300 2304 #if defined _WIN32 && _MSC_VER >= 1300
1869 #pragma warning ( pop ) 2305 #pragma warning ( pop )
1870 #endif 2306 #endif
1871 2307
1872 /////////////////////////////////////////////////////////////////////////////// 2308 ///////////////////////////////////////////////////////////////////////////////
1873 2309
1874 static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) { 2310 static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) {
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after
2258 mask->fImage = SkMask::AllocImage(size); 2694 mask->fImage = SkMask::AllocImage(size);
2259 memset(mask->fImage, 0, mask->computeImageSize()); 2695 memset(mask->fImage, 0, mask->computeImageSize());
2260 } 2696 }
2261 2697
2262 if (SkMask::kJustComputeBounds_CreateMode != mode) { 2698 if (SkMask::kJustComputeBounds_CreateMode != mode) {
2263 draw_into_mask(*mask, devPath, style); 2699 draw_into_mask(*mask, devPath, style);
2264 } 2700 }
2265 2701
2266 return true; 2702 return true;
2267 } 2703 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698