1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "Paint.h"
18 #include "BlurDrawLooper.h"
19 
20 namespace android {
21 
Paint()22 Paint::Paint()
23         : SkPaint()
24         , mLetterSpacing(0)
25         , mWordSpacing(0)
26         , mFontFeatureSettings()
27         , mMinikinLocaleListId(0)
28         , mFamilyVariant(minikin::FamilyVariant::DEFAULT) {
29     // SkPaint::antialiasing defaults to false, but
30     // SkFont::edging defaults to kAntiAlias. To keep them
31     // insync, we manually set the font to kAilas.
32     mFont.setEdging(SkFont::Edging::kAlias);
33 }
34 
Paint(const Paint & paint)35 Paint::Paint(const Paint& paint)
36         : SkPaint(paint)
37         , mFont(paint.mFont)
38         , mLooper(paint.mLooper)
39         , mLetterSpacing(paint.mLetterSpacing)
40         , mWordSpacing(paint.mWordSpacing)
41         , mFontFeatureSettings(paint.mFontFeatureSettings)
42         , mMinikinLocaleListId(paint.mMinikinLocaleListId)
43         , mFamilyVariant(paint.mFamilyVariant)
44         , mHyphenEdit(paint.mHyphenEdit)
45         , mTypeface(paint.mTypeface)
46         , mAlign(paint.mAlign)
47         , mFilterBitmap(paint.mFilterBitmap)
48         , mStrikeThru(paint.mStrikeThru)
49         , mUnderline(paint.mUnderline)
50         , mDevKern(paint.mDevKern)
51         , mRunFlag(paint.mRunFlag) {}
52 
~Paint()53 Paint::~Paint() {}
54 
operator =(const Paint & other)55 Paint& Paint::operator=(const Paint& other) {
56     SkPaint::operator=(other);
57     mFont = other.mFont;
58     mLooper = other.mLooper;
59     mLetterSpacing = other.mLetterSpacing;
60     mWordSpacing = other.mWordSpacing;
61     mFontFeatureSettings = other.mFontFeatureSettings;
62     mMinikinLocaleListId = other.mMinikinLocaleListId;
63     mFamilyVariant = other.mFamilyVariant;
64     mHyphenEdit = other.mHyphenEdit;
65     mTypeface = other.mTypeface;
66     mAlign = other.mAlign;
67     mFilterBitmap = other.mFilterBitmap;
68     mStrikeThru = other.mStrikeThru;
69     mUnderline = other.mUnderline;
70     mDevKern = other.mDevKern;
71     mRunFlag = other.mRunFlag;
72     return *this;
73 }
74 
operator ==(const Paint & a,const Paint & b)75 bool operator==(const Paint& a, const Paint& b) {
76     return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b) && a.mFont == b.mFont &&
77            a.mLooper == b.mLooper && a.mLetterSpacing == b.mLetterSpacing &&
78            a.mWordSpacing == b.mWordSpacing && a.mFontFeatureSettings == b.mFontFeatureSettings &&
79            a.mMinikinLocaleListId == b.mMinikinLocaleListId &&
80            a.mFamilyVariant == b.mFamilyVariant && a.mHyphenEdit == b.mHyphenEdit &&
81            a.mTypeface == b.mTypeface && a.mAlign == b.mAlign &&
82            a.mFilterBitmap == b.mFilterBitmap && a.mStrikeThru == b.mStrikeThru &&
83            a.mUnderline == b.mUnderline && a.mDevKern == b.mDevKern && a.mRunFlag == b.mRunFlag;
84 }
85 
reset()86 void Paint::reset() {
87     SkPaint::reset();
88 
89     mFont = SkFont();
90     mFont.setEdging(SkFont::Edging::kAlias);
91     mLooper.reset();
92 
93     mFilterBitmap = false;
94     mStrikeThru = false;
95     mUnderline = false;
96     mDevKern = false;
97     mRunFlag = minikin::RunFlag::NONE;
98 }
99 
setLooper(sk_sp<BlurDrawLooper> looper)100 void Paint::setLooper(sk_sp<BlurDrawLooper> looper) {
101     mLooper = std::move(looper);
102 }
103 
setAntiAlias(bool aa)104 void Paint::setAntiAlias(bool aa) {
105     // Java does not support/understand subpixel(lcd) antialiasing
106     SkASSERT(mFont.getEdging() != SkFont::Edging::kSubpixelAntiAlias);
107     // JavaPaint antialiasing affects both the SkPaint and SkFont settings.
108     SkPaint::setAntiAlias(aa);
109     mFont.setEdging(aa ? SkFont::Edging::kAntiAlias : SkFont::Edging::kAlias);
110 }
111 
112 ////////////////// Java flags compatibility //////////////////
113 
114 /*  Flags are tricky. Java has its own idea of the "paint" flags, but they don't really
115     match up with skia anymore, so we have to do some shuffling in get/set flags()
116 
117 	3 flags apply to SkPaint (antialias, dither, filter -> enum)
118     5 flags (merged with antialias) are for SkFont
119     2 flags are for minikin::Paint (underline and strikethru)
120 */
121 
122 // flags relating to SkPaint
123 static const uint32_t sAntiAliasFlag    = 0x01;   // affects paint and font-edging
124 static const uint32_t sFilterBitmapFlag = 0x02;   // maps to enum
125 static const uint32_t sDitherFlag       = 0x04;
126 // flags relating to SkFont
127 static const uint32_t sFakeBoldFlag     = 0x020;
128 static const uint32_t sLinearMetrics    = 0x040;
129 static const uint32_t sSubpixelMetrics  = 0x080;
130 static const uint32_t sEmbeddedBitmaps  = 0x400;
131 static const uint32_t sForceAutoHinting = 0x800;
132 // flags related to minikin::Paint
133 static const uint32_t sUnderlineFlag    = 0x08;
134 static const uint32_t sStrikeThruFlag   = 0x10;
135 static const uint32_t sTextRunLeftEdge = 0x2000;
136 static const uint32_t sTextRunRightEdge = 0x4000;
137 // flags no longer supported on native side (but mirrored for compatibility)
138 static const uint32_t sDevKernFlag      = 0x100;
139 
paintToLegacyFlags(const SkPaint & paint)140 static uint32_t paintToLegacyFlags(const SkPaint& paint) {
141     uint32_t flags = 0;
142     flags |= -(int)paint.isAntiAlias() & sAntiAliasFlag;
143     flags |= -(int)paint.isDither()    & sDitherFlag;
144     return flags;
145 }
146 
fontToLegacyFlags(const SkFont & font)147 static uint32_t fontToLegacyFlags(const SkFont& font) {
148     uint32_t flags = 0;
149     flags |= -(int)font.isEmbolden()         & sFakeBoldFlag;
150     flags |= -(int)font.isLinearMetrics()    & sLinearMetrics;
151     flags |= -(int)font.isSubpixel()         & sSubpixelMetrics;
152     flags |= -(int)font.isEmbeddedBitmaps()  & sEmbeddedBitmaps;
153     flags |= -(int)font.isForceAutoHinting() & sForceAutoHinting;
154     return flags;
155 }
156 
applyLegacyFlagsToPaint(uint32_t flags,SkPaint * paint)157 static void applyLegacyFlagsToPaint(uint32_t flags, SkPaint* paint) {
158     paint->setAntiAlias((flags & sAntiAliasFlag) != 0);
159     paint->setDither   ((flags & sDitherFlag) != 0);
160 }
161 
applyLegacyFlagsToFont(uint32_t flags,SkFont * font)162 static void applyLegacyFlagsToFont(uint32_t flags, SkFont* font) {
163     font->setEmbolden        ((flags & sFakeBoldFlag) != 0);
164     font->setLinearMetrics   ((flags & sLinearMetrics) != 0);
165     font->setSubpixel        ((flags & sSubpixelMetrics) != 0);
166     font->setEmbeddedBitmaps ((flags & sEmbeddedBitmaps) != 0);
167     font->setForceAutoHinting((flags & sForceAutoHinting) != 0);
168 
169     if (flags & sAntiAliasFlag) {
170         font->setEdging(SkFont::Edging::kAntiAlias);
171     } else {
172         font->setEdging(SkFont::Edging::kAlias);
173     }
174 }
175 
GetSkPaintJavaFlags(const SkPaint & paint)176 uint32_t Paint::GetSkPaintJavaFlags(const SkPaint& paint) {
177     return paintToLegacyFlags(paint);
178 }
179 
SetSkPaintJavaFlags(SkPaint * paint,uint32_t flags)180 void Paint::SetSkPaintJavaFlags(SkPaint* paint, uint32_t flags) {
181     applyLegacyFlagsToPaint(flags, paint);
182 }
183 
getJavaFlags() const184 uint32_t Paint::getJavaFlags() const {
185     uint32_t flags = paintToLegacyFlags(*this) | fontToLegacyFlags(mFont);
186     flags |= -(int)mStrikeThru   & sStrikeThruFlag;
187     flags |= -(int)mUnderline    & sUnderlineFlag;
188     flags |= -(int)mDevKern      & sDevKernFlag;
189     flags |= -(int)mFilterBitmap & sFilterBitmapFlag;
190     if (mRunFlag & minikin::RunFlag::LEFT_EDGE) {
191         flags |= sTextRunLeftEdge;
192     }
193     if (mRunFlag & minikin::RunFlag::RIGHT_EDGE) {
194         flags |= sTextRunRightEdge;
195     }
196     return flags;
197 }
198 
setJavaFlags(uint32_t flags)199 void Paint::setJavaFlags(uint32_t flags) {
200     applyLegacyFlagsToPaint(flags, this);
201     applyLegacyFlagsToFont(flags, &mFont);
202     mStrikeThru   = (flags & sStrikeThruFlag) != 0;
203     mUnderline    = (flags & sUnderlineFlag) != 0;
204     mDevKern      = (flags & sDevKernFlag) != 0;
205     mFilterBitmap = (flags & sFilterBitmapFlag) != 0;
206 
207     std::underlying_type<minikin::RunFlag>::type rawFlag = minikin::RunFlag::NONE;
208     if (flags & sTextRunLeftEdge) {
209         rawFlag |= minikin::RunFlag::LEFT_EDGE;
210     }
211     if (flags & sTextRunRightEdge) {
212         rawFlag |= minikin::RunFlag::RIGHT_EDGE;
213     }
214     mRunFlag = static_cast<minikin::RunFlag>(rawFlag);
215 }
216 
217 }  // namespace android
218