| 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 | 7 |
| 8 #include "SkDraw.h" | 8 #include "SkDraw.h" |
| 9 #include "SkBlitter.h" | 9 #include "SkBlitter.h" |
| 10 #include "SkBounder.h" | 10 #include "SkBounder.h" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 #include "SkStroke.h" | 25 #include "SkStroke.h" |
| 26 #include "SkTemplatesPriv.h" | 26 #include "SkTemplatesPriv.h" |
| 27 #include "SkTLazy.h" | 27 #include "SkTLazy.h" |
| 28 #include "SkUtils.h" | 28 #include "SkUtils.h" |
| 29 | 29 |
| 30 #include "SkAutoKern.h" | 30 #include "SkAutoKern.h" |
| 31 #include "SkBitmapProcShader.h" | 31 #include "SkBitmapProcShader.h" |
| 32 #include "SkDrawProcs.h" | 32 #include "SkDrawProcs.h" |
| 33 #include "SkMatrixUtils.h" | 33 #include "SkMatrixUtils.h" |
| 34 | 34 |
| 35 bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) { | |
| 36 // we don't cache hairlines in the cache | |
| 37 if (SkPaint::kStroke_Style == paint.getStyle() && | |
| 38 0 == paint.getStrokeWidth()) { | |
| 39 return true; | |
| 40 } | |
| 41 | |
| 42 // we don't cache perspective | |
| 43 if (ctm.hasPerspective()) { | |
| 44 return true; | |
| 45 } | |
| 46 | |
| 47 SkMatrix textM; | |
| 48 return SkPaint::TooBigToUseCache(ctm, *paint.setTextMatrix(&textM)); | |
| 49 } | |
| 50 | |
| 51 //#define TRACE_BITMAP_DRAWS | 35 //#define TRACE_BITMAP_DRAWS |
| 52 | 36 |
| 53 #define kBlitterStorageLongCount (sizeof(SkBitmapProcShader) >> 2) | 37 #define kBlitterStorageLongCount (sizeof(SkBitmapProcShader) >> 2) |
| 54 | 38 |
| 55 /** Helper for allocating small blitters on the stack. | 39 /** Helper for allocating small blitters on the stack. |
| 56 */ | 40 */ |
| 57 class SkAutoBlitterChoose : SkNoncopyable { | 41 class SkAutoBlitterChoose : SkNoncopyable { |
| 58 public: | 42 public: |
| 59 SkAutoBlitterChoose() { | 43 SkAutoBlitterChoose() { |
| 60 fBlitter = NULL; | 44 fBlitter = NULL; |
| (...skipping 1390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1451 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | 1435 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); |
| 1452 | 1436 |
| 1453 x += autokern.adjust(glyph) + glyph.fAdvanceX; | 1437 x += autokern.adjust(glyph) + glyph.fAdvanceX; |
| 1454 y += glyph.fAdvanceY; | 1438 y += glyph.fAdvanceY; |
| 1455 } | 1439 } |
| 1456 stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y)); | 1440 stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y)); |
| 1457 | 1441 |
| 1458 SkASSERT(text == stop); | 1442 SkASSERT(text == stop); |
| 1459 } | 1443 } |
| 1460 | 1444 |
| 1445 bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) { |
| 1446 // hairline glyphs are fast enough so we don't need to cache them |
| 1447 if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth(
)) { |
| 1448 return true; |
| 1449 } |
| 1450 |
| 1451 // we don't cache perspective |
| 1452 if (ctm.hasPerspective()) { |
| 1453 return true; |
| 1454 } |
| 1455 |
| 1456 SkMatrix textM; |
| 1457 return SkPaint::TooBigToUseCache(ctm, *paint.setTextMatrix(&textM)); |
| 1458 } |
| 1459 |
| 1461 void SkDraw::drawText_asPaths(const char text[], size_t byteLength, | 1460 void SkDraw::drawText_asPaths(const char text[], size_t byteLength, |
| 1462 SkScalar x, SkScalar y, | 1461 SkScalar x, SkScalar y, |
| 1463 const SkPaint& paint) const { | 1462 const SkPaint& paint) const { |
| 1464 SkDEBUGCODE(this->validate();) | 1463 SkDEBUGCODE(this->validate();) |
| 1465 | 1464 |
| 1466 SkTextToPathIter iter(text, byteLength, paint, true); | 1465 SkTextToPathIter iter(text, byteLength, paint, true); |
| 1467 | 1466 |
| 1468 SkMatrix matrix; | 1467 SkMatrix matrix; |
| 1469 matrix.setScale(iter.getPathScale(), iter.getPathScale()); | 1468 matrix.setScale(iter.getPathScale(), iter.getPathScale()); |
| 1470 matrix.postTranslate(x, y); | 1469 matrix.postTranslate(x, y); |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1709 | 1708 |
| 1710 // SkScalarRec doesn't currently have a way of representing hairline stroke
and | 1709 // SkScalarRec doesn't currently have a way of representing hairline stroke
and |
| 1711 // will fill if its frame-width is 0. | 1710 // will fill if its frame-width is 0. |
| 1712 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { | 1711 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { |
| 1713 this->drawText_asPaths(text, byteLength, x, y, paint); | 1712 this->drawText_asPaths(text, byteLength, x, y, paint); |
| 1714 return; | 1713 return; |
| 1715 } | 1714 } |
| 1716 | 1715 |
| 1717 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); | 1716 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); |
| 1718 | 1717 |
| 1719 #if SK_DISTANCEFIELD_FONTS | |
| 1720 const SkMatrix* ctm = fMatrix; | |
| 1721 const SkPaint* paintRef = &paint; | |
| 1722 SkPaint paintCopy; | |
| 1723 uint32_t procFlags = fProcs ? fProcs->fFlags : 0; | |
| 1724 if (procFlags & SkDrawProcs::kUseScaledGlyphs_Flag) { | |
| 1725 paintCopy = paint; | |
| 1726 paintCopy.setTextSize(SkDrawProcs::kBaseDFFontSize); | |
| 1727 paintCopy.setLCDRenderText(false); | |
| 1728 paintRef = &paintCopy; | |
| 1729 } | |
| 1730 if (procFlags & SkDrawProcs::kSkipBakedGlyphTransform_Flag) { | |
| 1731 ctm = NULL; | |
| 1732 } | |
| 1733 SkAutoGlyphCache autoCache(*paintRef, &fDevice->fLeakyProperties, ctm); | |
| 1734 #else | |
| 1735 SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix); | 1718 SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix); |
| 1736 #endif | |
| 1737 SkGlyphCache* cache = autoCache.getCache(); | 1719 SkGlyphCache* cache = autoCache.getCache(); |
| 1738 | 1720 |
| 1739 // transform our starting point | 1721 // transform our starting point |
| 1740 #if SK_DISTANCEFIELD_FONTS | |
| 1741 if (!(procFlags & SkDrawProcs::kSkipBakedGlyphTransform_Flag)) | |
| 1742 #endif | |
| 1743 { | 1722 { |
| 1744 SkPoint loc; | 1723 SkPoint loc; |
| 1745 fMatrix->mapXY(x, y, &loc); | 1724 fMatrix->mapXY(x, y, &loc); |
| 1746 x = loc.fX; | 1725 x = loc.fX; |
| 1747 y = loc.fY; | 1726 y = loc.fY; |
| 1748 } | 1727 } |
| 1749 | 1728 |
| 1750 // need to measure first | 1729 // need to measure first |
| 1751 if (paint.getTextAlign() != SkPaint::kLeft_Align) { | 1730 if (paint.getTextAlign() != SkPaint::kLeft_Align) { |
| 1752 SkVector stop; | 1731 SkVector stop; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1791 d1g.fHalfSampleY = SK_FixedHalf; | 1770 d1g.fHalfSampleY = SK_FixedHalf; |
| 1792 } else if (kY_SkAxisAlignment == baseline) { | 1771 } else if (kY_SkAxisAlignment == baseline) { |
| 1793 fxMask = 0; | 1772 fxMask = 0; |
| 1794 d1g.fHalfSampleX = SK_FixedHalf; | 1773 d1g.fHalfSampleX = SK_FixedHalf; |
| 1795 } | 1774 } |
| 1796 } | 1775 } |
| 1797 | 1776 |
| 1798 SkFixed fx = SkScalarToFixed(x) + d1g.fHalfSampleX; | 1777 SkFixed fx = SkScalarToFixed(x) + d1g.fHalfSampleX; |
| 1799 SkFixed fy = SkScalarToFixed(y) + d1g.fHalfSampleY; | 1778 SkFixed fy = SkScalarToFixed(y) + d1g.fHalfSampleY; |
| 1800 | 1779 |
| 1801 #if SK_DISTANCEFIELD_FONTS | |
| 1802 SkFixed fixedScale; | |
| 1803 if (procFlags & SkDrawProcs::kUseScaledGlyphs_Flag) { | |
| 1804 fixedScale = SkScalarToFixed(paint.getTextSize()/(float)SkDrawProcs::kBa
seDFFontSize); | |
| 1805 } | |
| 1806 #endif | |
| 1807 while (text < stop) { | 1780 while (text < stop) { |
| 1808 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fy
Mask); | 1781 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fy
Mask); |
| 1809 | 1782 |
| 1810 #if SK_DISTANCEFIELD_FONTS | |
| 1811 if (procFlags & SkDrawProcs::kUseScaledGlyphs_Flag) { | |
| 1812 fx += SkFixedMul_portable(autokern.adjust(glyph), fixedScale); | |
| 1813 } else { | |
| 1814 fx += autokern.adjust(glyph); | |
| 1815 } | |
| 1816 #else | |
| 1817 fx += autokern.adjust(glyph); | 1783 fx += autokern.adjust(glyph); |
| 1818 #endif | |
| 1819 | 1784 |
| 1820 if (glyph.fWidth) { | 1785 if (glyph.fWidth) { |
| 1821 proc(d1g, fx, fy, glyph); | 1786 proc(d1g, fx, fy, glyph); |
| 1822 } | 1787 } |
| 1823 | 1788 |
| 1824 #if SK_DISTANCEFIELD_FONTS | |
| 1825 if (procFlags & SkDrawProcs::kUseScaledGlyphs_Flag) { | |
| 1826 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale); | |
| 1827 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale); | |
| 1828 } else { | |
| 1829 fx += glyph.fAdvanceX; | |
| 1830 fy += glyph.fAdvanceY; | |
| 1831 } | |
| 1832 #else | |
| 1833 fx += glyph.fAdvanceX; | 1789 fx += glyph.fAdvanceX; |
| 1834 fy += glyph.fAdvanceY; | 1790 fy += glyph.fAdvanceY; |
| 1835 #endif | |
| 1836 } | 1791 } |
| 1837 } | 1792 } |
| 1838 | 1793 |
| 1839 // last parameter is interpreted as SkFixed [x, y] | 1794 // last parameter is interpreted as SkFixed [x, y] |
| 1840 // return the fixed position, which may be rounded or not by the caller | 1795 // return the fixed position, which may be rounded or not by the caller |
| 1841 // e.g. subpixel doesn't round | 1796 // e.g. subpixel doesn't round |
| 1842 typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*); | 1797 typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*); |
| 1843 | 1798 |
| 1844 static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* ds
t) { | 1799 static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* ds
t) { |
| 1845 dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY)); | 1800 dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY)); |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2006 return; | 1961 return; |
| 2007 } | 1962 } |
| 2008 | 1963 |
| 2009 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { | 1964 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { |
| 2010 this->drawPosText_asPaths(text, byteLength, pos, constY, | 1965 this->drawPosText_asPaths(text, byteLength, pos, constY, |
| 2011 scalarsPerPosition, paint); | 1966 scalarsPerPosition, paint); |
| 2012 return; | 1967 return; |
| 2013 } | 1968 } |
| 2014 | 1969 |
| 2015 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); | 1970 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); |
| 2016 #if SK_DISTANCEFIELD_FONTS | |
| 2017 const SkMatrix* ctm = fMatrix; | |
| 2018 const SkPaint* paintRef = &paint; | |
| 2019 SkPaint paintCopy; | |
| 2020 uint32_t procFlags = fProcs ? fProcs->fFlags : 0; | |
| 2021 if (procFlags & SkDrawProcs::kUseScaledGlyphs_Flag) { | |
| 2022 paintCopy = paint; | |
| 2023 paintCopy.setTextSize(SkDrawProcs::kBaseDFFontSize); | |
| 2024 paintRef = &paintCopy; | |
| 2025 } | |
| 2026 if (procFlags & SkDrawProcs::kSkipBakedGlyphTransform_Flag) { | |
| 2027 ctm = &SkMatrix::I(); | |
| 2028 } | |
| 2029 SkAutoGlyphCache autoCache(*paintRef, &fDevice->fLeakyProperties, ctm); | |
| 2030 #else | |
| 2031 SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix); | 1971 SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix); |
| 2032 #endif | |
| 2033 SkGlyphCache* cache = autoCache.getCache(); | 1972 SkGlyphCache* cache = autoCache.getCache(); |
| 2034 | 1973 |
| 2035 SkAAClipBlitterWrapper wrapper; | 1974 SkAAClipBlitterWrapper wrapper; |
| 2036 SkAutoBlitterChoose blitterChooser; | 1975 SkAutoBlitterChoose blitterChooser; |
| 2037 SkBlitter* blitter = NULL; | 1976 SkBlitter* blitter = NULL; |
| 2038 if (needsRasterTextBlit(*this)) { | 1977 if (needsRasterTextBlit(*this)) { |
| 2039 blitterChooser.choose(*fBitmap, *fMatrix, paint); | 1978 blitterChooser.choose(*fBitmap, *fMatrix, paint); |
| 2040 blitter = blitterChooser.get(); | 1979 blitter = blitterChooser.get(); |
| 2041 if (fRC->isAA()) { | 1980 if (fRC->isAA()) { |
| 2042 wrapper.init(*fRC, blitter); | 1981 wrapper.init(*fRC, blitter); |
| 2043 blitter = wrapper.getBlitter(); | 1982 blitter = wrapper.getBlitter(); |
| 2044 } | 1983 } |
| 2045 } | 1984 } |
| 2046 | 1985 |
| 2047 const char* stop = text + byteLength; | 1986 const char* stop = text + byteLength; |
| 2048 AlignProc alignProc = pick_align_proc(paint.getTextAlign()); | 1987 AlignProc alignProc = pick_align_proc(paint.getTextAlign()); |
| 2049 SkDraw1Glyph d1g; | 1988 SkDraw1Glyph d1g; |
| 2050 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); | 1989 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); |
| 2051 #if SK_DISTANCEFIELD_FONTS | |
| 2052 TextMapState tms(*ctm, constY); | |
| 2053 #else | |
| 2054 TextMapState tms(*fMatrix, constY); | 1990 TextMapState tms(*fMatrix, constY); |
| 2055 #endif | |
| 2056 TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition); | 1991 TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition); |
| 2057 | 1992 |
| 2058 if (cache->isSubpixel()) { | 1993 if (cache->isSubpixel()) { |
| 2059 // maybe we should skip the rounding if linearText is set | 1994 // maybe we should skip the rounding if linearText is set |
| 2060 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix); | 1995 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix); |
| 2061 | 1996 |
| 2062 SkFixed fxMask = ~0; | 1997 SkFixed fxMask = ~0; |
| 2063 SkFixed fyMask = ~0; | 1998 SkFixed fyMask = ~0; |
| 2064 if (kX_SkAxisAlignment == baseline) { | 1999 if (kX_SkAxisAlignment == baseline) { |
| 2065 fyMask = 0; | 2000 fyMask = 0; |
| 2066 #ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX | 2001 #ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX |
| 2067 d1g.fHalfSampleY = SK_FixedHalf; | 2002 d1g.fHalfSampleY = SK_FixedHalf; |
| 2068 #endif | 2003 #endif |
| 2069 } else if (kY_SkAxisAlignment == baseline) { | 2004 } else if (kY_SkAxisAlignment == baseline) { |
| 2070 fxMask = 0; | 2005 fxMask = 0; |
| 2071 #ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX | 2006 #ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX |
| 2072 d1g.fHalfSampleX = SK_FixedHalf; | 2007 d1g.fHalfSampleX = SK_FixedHalf; |
| 2073 #endif | 2008 #endif |
| 2074 } | 2009 } |
| 2075 | 2010 |
| 2076 if (SkPaint::kLeft_Align == paint.getTextAlign()) { | 2011 if (SkPaint::kLeft_Align == paint.getTextAlign()) { |
| 2077 while (text < stop) { | 2012 while (text < stop) { |
| 2078 #if SK_DISTANCEFIELD_FONTS | |
| 2079 if (procFlags & SkDrawProcs::kSkipBakedGlyphTransform_Flag) { | |
| 2080 tms.fLoc.fX = *pos; | |
| 2081 tms.fLoc.fY = *(pos+1); | |
| 2082 } else { | |
| 2083 tmsProc(tms, pos); | |
| 2084 } | |
| 2085 #else | |
| 2086 tmsProc(tms, pos); | 2013 tmsProc(tms, pos); |
| 2087 #endif | |
| 2088 SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + d1g.fHalfSampleX; | 2014 SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + d1g.fHalfSampleX; |
| 2089 SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + d1g.fHalfSampleY; | 2015 SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + d1g.fHalfSampleY; |
| 2090 | 2016 |
| 2091 const SkGlyph& glyph = glyphCacheProc(cache, &text, | 2017 const SkGlyph& glyph = glyphCacheProc(cache, &text, |
| 2092 fx & fxMask, fy & fyMask); | 2018 fx & fxMask, fy & fyMask); |
| 2093 | 2019 |
| 2094 if (glyph.fWidth) { | 2020 if (glyph.fWidth) { |
| 2095 proc(d1g, fx, fy, glyph); | 2021 proc(d1g, fx, fy, glyph); |
| 2096 } | 2022 } |
| 2097 pos += scalarsPerPosition; | 2023 pos += scalarsPerPosition; |
| (...skipping 797 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2895 mask->fImage = SkMask::AllocImage(size); | 2821 mask->fImage = SkMask::AllocImage(size); |
| 2896 memset(mask->fImage, 0, mask->computeImageSize()); | 2822 memset(mask->fImage, 0, mask->computeImageSize()); |
| 2897 } | 2823 } |
| 2898 | 2824 |
| 2899 if (SkMask::kJustComputeBounds_CreateMode != mode) { | 2825 if (SkMask::kJustComputeBounds_CreateMode != mode) { |
| 2900 draw_into_mask(*mask, devPath, style); | 2826 draw_into_mask(*mask, devPath, style); |
| 2901 } | 2827 } |
| 2902 | 2828 |
| 2903 return true; | 2829 return true; |
| 2904 } | 2830 } |
| OLD | NEW |