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

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