• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libs/android_runtime/android/graphics/Paint.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 #define LOG_TAG "Paint"
19 
20 #include <utils/Log.h>
21 
22 #include "jni.h"
23 #include "GraphicsJNI.h"
24 #include "core_jni_helpers.h"
25 #include <nativehelper/ScopedStringChars.h>
26 #include <nativehelper/ScopedUtfChars.h>
27 #include <nativehelper/ScopedPrimitiveArray.h>
28 
29 #include "SkBlurDrawLooper.h"
30 #include "SkColorFilter.h"
31 #include "SkMaskFilter.h"
32 #include "SkPath.h"
33 #include "SkPathEffect.h"
34 #include "SkShader.h"
35 #include "SkBlendMode.h"
36 #include "unicode/uloc.h"
37 #include "unicode/ushape.h"
38 #include "utils/Blur.h"
39 
40 #include <hwui/MinikinSkia.h>
41 #include <hwui/MinikinUtils.h>
42 #include <hwui/Paint.h>
43 #include <hwui/Typeface.h>
44 #include <minikin/GraphemeBreak.h>
45 #include <minikin/LocaleList.h>
46 #include <minikin/Measurement.h>
47 #include <unicode/utf16.h>
48 
49 #include <cassert>
50 #include <cstring>
51 #include <memory>
52 #include <vector>
53 
54 namespace android {
55 
56 struct JMetricsID {
57     jfieldID    top;
58     jfieldID    ascent;
59     jfieldID    descent;
60     jfieldID    bottom;
61     jfieldID    leading;
62 };
63 
64 static jclass   gFontMetrics_class;
65 static JMetricsID gFontMetrics_fieldID;
66 
67 static jclass   gFontMetricsInt_class;
68 static JMetricsID gFontMetricsInt_fieldID;
69 
defaultSettingsForAndroid(Paint * paint)70 static void defaultSettingsForAndroid(Paint* paint) {
71     // GlyphID encoding is required because we are using Harfbuzz shaping
72     paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
73 }
74 
75 namespace PaintGlue {
76     enum MoveOpt {
77         AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT
78     };
79 
deletePaint(Paint * paint)80     static void deletePaint(Paint* paint) {
81         delete paint;
82     }
83 
getNativeFinalizer(JNIEnv *,jobject)84     static jlong getNativeFinalizer(JNIEnv*, jobject) {
85         return static_cast<jlong>(reinterpret_cast<uintptr_t>(&deletePaint));
86     }
87 
init(JNIEnv * env,jobject)88     static jlong init(JNIEnv* env, jobject) {
89         static_assert(1 <<  0 == SkPaint::kAntiAlias_Flag,             "paint_flags_mismatch");
90         static_assert(1 <<  2 == SkPaint::kDither_Flag,                "paint_flags_mismatch");
91         static_assert(1 <<  3 == SkPaint::kUnderlineText_ReserveFlag,  "paint_flags_mismatch");
92         static_assert(1 <<  4 == SkPaint::kStrikeThruText_ReserveFlag, "paint_flags_mismatch");
93         static_assert(1 <<  5 == SkPaint::kFakeBoldText_Flag,          "paint_flags_mismatch");
94         static_assert(1 <<  6 == SkPaint::kLinearText_Flag,            "paint_flags_mismatch");
95         static_assert(1 <<  7 == SkPaint::kSubpixelText_Flag,          "paint_flags_mismatch");
96         static_assert(1 <<  8 == SkPaint::kDevKernText_Flag,           "paint_flags_mismatch");
97         static_assert(1 << 10 == SkPaint::kEmbeddedBitmapText_Flag,    "paint_flags_mismatch");
98 
99         Paint* obj = new Paint();
100         defaultSettingsForAndroid(obj);
101         return reinterpret_cast<jlong>(obj);
102     }
103 
initWithPaint(JNIEnv * env,jobject clazz,jlong paintHandle)104     static jlong initWithPaint(JNIEnv* env, jobject clazz, jlong paintHandle) {
105         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
106         Paint* obj = new Paint(*paint);
107         return reinterpret_cast<jlong>(obj);
108     }
109 
breakText(JNIEnv * env,const Paint & paint,const Typeface * typeface,const jchar text[],int count,float maxWidth,jint bidiFlags,jfloatArray jmeasured,const bool forwardScan)110     static int breakText(JNIEnv* env, const Paint& paint, const Typeface* typeface,
111             const jchar text[], int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
112             const bool forwardScan) {
113         size_t measuredCount = 0;
114         float measured = 0;
115 
116         std::unique_ptr<float[]> advancesArray(new float[count]);
117         MinikinUtils::measureText(&paint, static_cast<minikin::Bidi>(bidiFlags), typeface, text,
118                 0, count, count, advancesArray.get());
119 
120         for (int i = 0; i < count; i++) {
121             // traverse in the given direction
122             int index = forwardScan ? i : (count - i - 1);
123             float width = advancesArray[index];
124             if (measured + width > maxWidth) {
125                 break;
126             }
127             // properly handle clusters when scanning backwards
128             if (forwardScan || width != 0.0f) {
129                 measuredCount = i + 1;
130             }
131             measured += width;
132         }
133 
134         if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
135             AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
136             jfloat* array = autoMeasured.ptr();
137             array[0] = measured;
138         }
139         return measuredCount;
140     }
141 
breakTextC(JNIEnv * env,jobject clazz,jlong paintHandle,jcharArray jtext,jint index,jint count,jfloat maxWidth,jint bidiFlags,jfloatArray jmeasuredWidth)142     static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray jtext,
143             jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
144         NPE_CHECK_RETURN_ZERO(env, jtext);
145 
146         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
147         const Typeface* typeface = paint->getAndroidTypeface();
148 
149         bool forwardTextDirection;
150         if (count < 0) {
151             forwardTextDirection = false;
152             count = -count;
153         }
154         else {
155             forwardTextDirection = true;
156         }
157 
158         if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
159             doThrowAIOOBE(env);
160             return 0;
161         }
162 
163         const jchar* text = env->GetCharArrayElements(jtext, nullptr);
164         count = breakText(env, *paint, typeface, text + index, count, maxWidth,
165                           bidiFlags, jmeasuredWidth, forwardTextDirection);
166         env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
167                                       JNI_ABORT);
168         return count;
169     }
170 
breakTextS(JNIEnv * env,jobject clazz,jlong paintHandle,jstring jtext,jboolean forwards,jfloat maxWidth,jint bidiFlags,jfloatArray jmeasuredWidth)171     static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jstring jtext,
172             jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
173         NPE_CHECK_RETURN_ZERO(env, jtext);
174 
175         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
176         const Typeface* typeface = paint->getAndroidTypeface();
177 
178         int count = env->GetStringLength(jtext);
179         const jchar* text = env->GetStringChars(jtext, nullptr);
180         count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, forwards);
181         env->ReleaseStringChars(jtext, text);
182         return count;
183     }
184 
doTextAdvances(JNIEnv * env,Paint * paint,const Typeface * typeface,const jchar * text,jint start,jint count,jint contextCount,jint bidiFlags,jfloatArray advances,jint advancesIndex)185     static jfloat doTextAdvances(JNIEnv *env, Paint *paint, const Typeface* typeface,
186             const jchar *text, jint start, jint count, jint contextCount, jint bidiFlags,
187             jfloatArray advances, jint advancesIndex) {
188         NPE_CHECK_RETURN_ZERO(env, text);
189 
190         if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
191             doThrowAIOOBE(env);
192             return 0;
193         }
194         if (count == 0) {
195             return 0;
196         }
197         if (advances) {
198             size_t advancesLength = env->GetArrayLength(advances);
199             if ((size_t)(count  + advancesIndex) > advancesLength) {
200                 doThrowAIOOBE(env);
201                 return 0;
202             }
203         }
204         std::unique_ptr<jfloat[]> advancesArray;
205         if (advances) {
206             advancesArray.reset(new jfloat[count]);
207         }
208         const float advance = MinikinUtils::measureText(paint,
209                 static_cast<minikin::Bidi>(bidiFlags), typeface, text, start, count, contextCount,
210                 advancesArray.get());
211         if (advances) {
212             env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray.get());
213         }
214         return advance;
215     }
216 
getTextAdvances___CIIIII_FI(JNIEnv * env,jobject clazz,jlong paintHandle,jcharArray text,jint index,jint count,jint contextIndex,jint contextCount,jint bidiFlags,jfloatArray advances,jint advancesIndex)217     static jfloat getTextAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
218             jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
219             jint bidiFlags, jfloatArray advances, jint advancesIndex) {
220         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
221         const Typeface* typeface = paint->getAndroidTypeface();
222         jchar* textArray = env->GetCharArrayElements(text, nullptr);
223         jfloat result = doTextAdvances(env, paint, typeface, textArray + contextIndex,
224                 index - contextIndex, count, contextCount, bidiFlags, advances, advancesIndex);
225         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
226         return result;
227     }
228 
getTextAdvances__StringIIIII_FI(JNIEnv * env,jobject clazz,jlong paintHandle,jstring text,jint start,jint end,jint contextStart,jint contextEnd,jint bidiFlags,jfloatArray advances,jint advancesIndex)229     static jfloat getTextAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
230             jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint bidiFlags,
231             jfloatArray advances, jint advancesIndex) {
232         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
233         const Typeface* typeface = paint->getAndroidTypeface();
234         const jchar* textArray = env->GetStringChars(text, nullptr);
235         jfloat result = doTextAdvances(env, paint, typeface, textArray + contextStart,
236                 start - contextStart, end - start, contextEnd - contextStart, bidiFlags,
237                 advances, advancesIndex);
238         env->ReleaseStringChars(text, textArray);
239         return result;
240     }
241 
doTextRunCursor(JNIEnv * env,Paint * paint,const Typeface * typeface,const jchar * text,jint start,jint count,jint dir,jint offset,jint opt)242     static jint doTextRunCursor(JNIEnv *env, Paint* paint, const Typeface* typeface,
243             const jchar *text, jint start, jint count, jint dir, jint offset, jint opt) {
244         minikin::GraphemeBreak::MoveOpt moveOpt = minikin::GraphemeBreak::MoveOpt(opt);
245         minikin::Bidi bidiFlags = dir == 1 ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
246         std::unique_ptr<float[]> advancesArray(new float[count]);
247         MinikinUtils::measureText(paint, bidiFlags, typeface, text, start, count, start + count,
248                 advancesArray.get());
249         size_t result = minikin::GraphemeBreak::getTextRunCursor(advancesArray.get(), text,
250                 start, count, offset, moveOpt);
251         return static_cast<jint>(result);
252     }
253 
getTextRunCursor___C(JNIEnv * env,jobject clazz,jlong paintHandle,jcharArray text,jint contextStart,jint contextCount,jint dir,jint offset,jint cursorOpt)254     static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text,
255             jint contextStart, jint contextCount, jint dir, jint offset, jint cursorOpt) {
256         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
257         const Typeface* typeface = paint->getAndroidTypeface();
258         jchar* textArray = env->GetCharArrayElements(text, nullptr);
259         jint result = doTextRunCursor(env, paint, typeface, textArray,
260                 contextStart, contextCount, dir, offset, cursorOpt);
261         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
262         return result;
263     }
264 
getTextRunCursor__String(JNIEnv * env,jobject clazz,jlong paintHandle,jstring text,jint contextStart,jint contextEnd,jint dir,jint offset,jint cursorOpt)265     static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle,
266             jstring text, jint contextStart, jint contextEnd, jint dir, jint offset,
267             jint cursorOpt) {
268         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
269         const Typeface* typeface = paint->getAndroidTypeface();
270         const jchar* textArray = env->GetStringChars(text, nullptr);
271         jint result = doTextRunCursor(env, paint, typeface, textArray,
272                 contextStart, contextEnd - contextStart, dir, offset, cursorOpt);
273         env->ReleaseStringChars(text, textArray);
274         return result;
275     }
276 
277     class GetTextFunctor {
278     public:
GetTextFunctor(const minikin::Layout & layout,SkPath * path,jfloat x,jfloat y,Paint * paint,uint16_t * glyphs,SkPoint * pos)279         GetTextFunctor(const minikin::Layout& layout, SkPath* path, jfloat x, jfloat y,
280                     Paint* paint, uint16_t* glyphs, SkPoint* pos)
281                 : layout(layout), path(path), x(x), y(y), paint(paint), glyphs(glyphs), pos(pos) {
282         }
283 
operator ()(size_t start,size_t end)284         void operator()(size_t start, size_t end) {
285             for (size_t i = start; i < end; i++) {
286                 glyphs[i] = layout.getGlyphId(i);
287                 pos[i].fX = x + layout.getX(i);
288                 pos[i].fY = y + layout.getY(i);
289             }
290             if (start == 0) {
291                 paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, path);
292             } else {
293                 paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, &tmpPath);
294                 path->addPath(tmpPath);
295             }
296         }
297     private:
298         const minikin::Layout& layout;
299         SkPath* path;
300         jfloat x;
301         jfloat y;
302         Paint* paint;
303         uint16_t* glyphs;
304         SkPoint* pos;
305         SkPath tmpPath;
306     };
307 
getTextPath(JNIEnv * env,Paint * paint,const Typeface * typeface,const jchar * text,jint count,jint bidiFlags,jfloat x,jfloat y,SkPath * path)308     static void getTextPath(JNIEnv* env, Paint* paint, const Typeface* typeface, const jchar* text,
309             jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
310         minikin::Layout layout = MinikinUtils::doLayout(
311                 paint, static_cast<minikin::Bidi>(bidiFlags), typeface, text, 0, count, count,
312                 nullptr);
313         size_t nGlyphs = layout.nGlyphs();
314         uint16_t* glyphs = new uint16_t[nGlyphs];
315         SkPoint* pos = new SkPoint[nGlyphs];
316 
317         x += MinikinUtils::xOffsetForTextAlign(paint, layout);
318         Paint::Align align = paint->getTextAlign();
319         paint->setTextAlign(Paint::kLeft_Align);
320         paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
321         GetTextFunctor f(layout, path, x, y, paint, glyphs, pos);
322         MinikinUtils::forFontRun(layout, paint, f);
323         paint->setTextAlign(align);
324         delete[] glyphs;
325         delete[] pos;
326     }
327 
getTextPath___C(JNIEnv * env,jobject clazz,jlong paintHandle,jint bidiFlags,jcharArray text,jint index,jint count,jfloat x,jfloat y,jlong pathHandle)328     static void getTextPath___C(JNIEnv* env, jobject clazz, jlong paintHandle, jint bidiFlags,
329             jcharArray text, jint index, jint count, jfloat x, jfloat y, jlong pathHandle) {
330         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
331         const Typeface* typeface = paint->getAndroidTypeface();
332         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
333         const jchar* textArray = env->GetCharArrayElements(text, nullptr);
334         getTextPath(env, paint, typeface, textArray + index, count, bidiFlags, x, y, path);
335         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
336     }
337 
getTextPath__String(JNIEnv * env,jobject clazz,jlong paintHandle,jint bidiFlags,jstring text,jint start,jint end,jfloat x,jfloat y,jlong pathHandle)338     static void getTextPath__String(JNIEnv* env, jobject clazz, jlong paintHandle, jint bidiFlags,
339             jstring text, jint start, jint end, jfloat x, jfloat y, jlong pathHandle) {
340         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
341         const Typeface* typeface = paint->getAndroidTypeface();
342         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
343         const jchar* textArray = env->GetStringChars(text, nullptr);
344         getTextPath(env, paint, typeface, textArray + start, end - start, bidiFlags, x, y, path);
345         env->ReleaseStringChars(text, textArray);
346     }
347 
doTextBounds(JNIEnv * env,const jchar * text,int count,jobject bounds,const Paint & paint,const Typeface * typeface,jint bidiFlags)348     static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds,
349             const Paint& paint, const Typeface* typeface, jint bidiFlags) {
350         SkRect  r;
351         SkIRect ir;
352 
353         minikin::Layout layout = MinikinUtils::doLayout(&paint,
354                 static_cast<minikin::Bidi>(bidiFlags), typeface, text, 0, count, count, nullptr);
355         minikin::MinikinRect rect;
356         layout.getBounds(&rect);
357         r.fLeft = rect.mLeft;
358         r.fTop = rect.mTop;
359         r.fRight = rect.mRight;
360         r.fBottom = rect.mBottom;
361         r.roundOut(&ir);
362         GraphicsJNI::irect_to_jrect(ir, env, bounds);
363     }
364 
getStringBounds(JNIEnv * env,jobject,jlong paintHandle,jstring text,jint start,jint end,jint bidiFlags,jobject bounds)365     static void getStringBounds(JNIEnv* env, jobject, jlong paintHandle, jstring text, jint start,
366             jint end, jint bidiFlags, jobject bounds) {
367         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
368         const Typeface* typeface = paint->getAndroidTypeface();
369         const jchar* textArray = env->GetStringChars(text, nullptr);
370         doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags);
371         env->ReleaseStringChars(text, textArray);
372     }
373 
getCharArrayBounds(JNIEnv * env,jobject,jlong paintHandle,jcharArray text,jint index,jint count,jint bidiFlags,jobject bounds)374     static void getCharArrayBounds(JNIEnv* env, jobject, jlong paintHandle, jcharArray text,
375             jint index, jint count, jint bidiFlags, jobject bounds) {
376         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
377         const Typeface* typeface = paint->getAndroidTypeface();
378         const jchar* textArray = env->GetCharArrayElements(text, nullptr);
379         doTextBounds(env, textArray + index, count, bounds, *paint, typeface, bidiFlags);
380         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
381                                       JNI_ABORT);
382     }
383 
384     // Returns true if the given string is exact one pair of regional indicators.
isFlag(const jchar * str,size_t length)385     static bool isFlag(const jchar* str, size_t length) {
386         const jchar RI_LEAD_SURROGATE = 0xD83C;
387         const jchar RI_TRAIL_SURROGATE_MIN = 0xDDE6;
388         const jchar RI_TRAIL_SURROGATE_MAX = 0xDDFF;
389 
390         if (length != 4) {
391             return false;
392         }
393         if (str[0] != RI_LEAD_SURROGATE || str[2] != RI_LEAD_SURROGATE) {
394             return false;
395         }
396         return RI_TRAIL_SURROGATE_MIN <= str[1] && str[1] <= RI_TRAIL_SURROGATE_MAX &&
397             RI_TRAIL_SURROGATE_MIN <= str[3] && str[3] <= RI_TRAIL_SURROGATE_MAX;
398     }
399 
layoutContainsNotdef(const minikin::Layout & layout)400     static jboolean layoutContainsNotdef(const minikin::Layout& layout) {
401         for (size_t i = 0; i < layout.nGlyphs(); i++) {
402             if (layout.getGlyphId(i) == 0) {
403                 return true;
404             }
405         }
406         return false;
407     }
408 
409     // Don't count glyphs that are the recommended "space" glyph and are zero width.
410     // This logic makes assumptions about HarfBuzz layout, but does correctly handle
411     // cases where ligatures form and zero width space glyphs are left in as
412     // placeholders.
countNonSpaceGlyphs(const minikin::Layout & layout)413     static size_t countNonSpaceGlyphs(const minikin::Layout& layout) {
414         size_t count = 0;
415         static unsigned int kSpaceGlyphId = 3;
416         for (size_t i = 0; i < layout.nGlyphs(); i++) {
417             if (layout.getGlyphId(i) != kSpaceGlyphId || layout.getCharAdvance(i) != 0.0) {
418                 count++;
419             }
420         }
421         return count;
422     }
423 
hasGlyph(JNIEnv * env,jclass,jlong paintHandle,jint bidiFlags,jstring string)424     static jboolean hasGlyph(JNIEnv *env, jclass, jlong paintHandle, jint bidiFlags,
425             jstring string) {
426         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
427         const Typeface* typeface = paint->getAndroidTypeface();
428         ScopedStringChars str(env, string);
429 
430         /* Start by rejecting unsupported base code point and variation selector pairs. */
431         size_t nChars = 0;
432         const uint32_t kStartOfString = 0xFFFFFFFF;
433         uint32_t prevCp = kStartOfString;
434         for (size_t i = 0; i < str.size(); i++) {
435             jchar cu = str[i];
436             uint32_t cp = cu;
437             if (U16_IS_TRAIL(cu)) {
438                 // invalid UTF-16, unpaired trailing surrogate
439                 return false;
440             } else if (U16_IS_LEAD(cu)) {
441                 if (i + 1 == str.size()) {
442                     // invalid UTF-16, unpaired leading surrogate at end of string
443                     return false;
444                 }
445                 i++;
446                 jchar cu2 = str[i];
447                 if (!U16_IS_TRAIL(cu2)) {
448                     // invalid UTF-16, unpaired leading surrogate
449                     return false;
450                 }
451                 cp = U16_GET_SUPPLEMENTARY(cu, cu2);
452             }
453 
454             if (prevCp != kStartOfString &&
455                 ((0xFE00 <= cp && cp <= 0xFE0F) || (0xE0100 <= cp && cp <= 0xE01EF))) {
456                 bool hasVS = MinikinUtils::hasVariationSelector(typeface, prevCp, cp);
457                 if (!hasVS) {
458                     // No font has a glyph for the code point and variation selector pair.
459                     return false;
460                 } else if (nChars == 1 && i + 1 == str.size()) {
461                     // The string is just a codepoint and a VS, we have an authoritative answer
462                     return true;
463                 }
464             }
465             nChars++;
466             prevCp = cp;
467         }
468         minikin::Layout layout = MinikinUtils::doLayout(paint,
469                 static_cast<minikin::Bidi>(bidiFlags), typeface, str.get(), 0, str.size(),
470                 str.size(), nullptr);
471         size_t nGlyphs = countNonSpaceGlyphs(layout);
472         if (nGlyphs != 1 && nChars > 1) {
473             // multiple-character input, and was not a ligature
474             // TODO: handle ZWJ/ZWNJ characters specially so we can detect certain ligatures
475             // in joining scripts, such as Arabic and Mongolian.
476             return false;
477         }
478 
479         if (nGlyphs == 0 || layoutContainsNotdef(layout)) {
480             return false;  // The collection doesn't have a glyph.
481         }
482 
483         if (nChars == 2 && isFlag(str.get(), str.size())) {
484             // Some font may have a special glyph for unsupported regional indicator pairs.
485             // To return false for this case, need to compare the glyph id with the one of ZZ
486             // since ZZ is reserved for unknown or invalid territory.
487             // U+1F1FF (REGIONAL INDICATOR SYMBOL LETTER Z) is \uD83C\uDDFF in UTF16.
488             static const jchar ZZ_FLAG_STR[] = { 0xD83C, 0xDDFF, 0xD83C, 0xDDFF };
489             minikin::Layout zzLayout = MinikinUtils::doLayout(paint,
490                     static_cast<minikin::Bidi>(bidiFlags), typeface, ZZ_FLAG_STR, 0, 4, 4,
491                     nullptr);
492             if (zzLayout.nGlyphs() != 1 || layoutContainsNotdef(zzLayout)) {
493                 // The font collection doesn't have a glyph for unknown flag. Just return true.
494                 return true;
495             }
496             return zzLayout.getGlyphId(0) != layout.getGlyphId(0);
497         }
498         return true;
499     }
500 
doRunAdvance(const Paint * paint,const Typeface * typeface,const jchar buf[],jint start,jint count,jint bufSize,jboolean isRtl,jint offset)501     static jfloat doRunAdvance(const Paint* paint, const Typeface* typeface, const jchar buf[],
502             jint start, jint count, jint bufSize, jboolean isRtl, jint offset) {
503         minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
504         if (offset == start + count) {
505             return MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count,
506                     bufSize, nullptr);
507         }
508         std::unique_ptr<float[]> advancesArray(new float[count]);
509         MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize,
510                 advancesArray.get());
511         return minikin::getRunAdvance(advancesArray.get(), buf, start, count, offset);
512     }
513 
getRunAdvance___CIIIIZI_F(JNIEnv * env,jclass,jlong paintHandle,jcharArray text,jint start,jint end,jint contextStart,jint contextEnd,jboolean isRtl,jint offset)514     static jfloat getRunAdvance___CIIIIZI_F(JNIEnv *env, jclass, jlong paintHandle, jcharArray text,
515             jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl, jint offset) {
516         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
517         const Typeface* typeface = paint->getAndroidTypeface();
518         ScopedCharArrayRO textArray(env, text);
519         jfloat result = doRunAdvance(paint, typeface, textArray.get() + contextStart,
520                 start - contextStart, end - start, contextEnd - contextStart, isRtl,
521                 offset - contextStart);
522         return result;
523     }
524 
doOffsetForAdvance(const Paint * paint,const Typeface * typeface,const jchar buf[],jint start,jint count,jint bufSize,jboolean isRtl,jfloat advance)525     static jint doOffsetForAdvance(const Paint* paint, const Typeface* typeface, const jchar buf[],
526             jint start, jint count, jint bufSize, jboolean isRtl, jfloat advance) {
527         minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
528         std::unique_ptr<float[]> advancesArray(new float[count]);
529         MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize,
530                 advancesArray.get());
531         return minikin::getOffsetForAdvance(advancesArray.get(), buf, start, count, advance);
532     }
533 
getOffsetForAdvance___CIIIIZF_I(JNIEnv * env,jclass,jlong paintHandle,jcharArray text,jint start,jint end,jint contextStart,jint contextEnd,jboolean isRtl,jfloat advance)534     static jint getOffsetForAdvance___CIIIIZF_I(JNIEnv *env, jclass, jlong paintHandle,
535             jcharArray text, jint start, jint end, jint contextStart, jint contextEnd,
536             jboolean isRtl, jfloat advance) {
537         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
538         const Typeface* typeface = paint->getAndroidTypeface();
539         ScopedCharArrayRO textArray(env, text);
540         jint result = doOffsetForAdvance(paint, typeface, textArray.get() + contextStart,
541                 start - contextStart, end - start, contextEnd - contextStart, isRtl, advance);
542         result += contextStart;
543         return result;
544     }
545 
546     // ------------------ @FastNative ---------------------------
547 
setTextLocales(JNIEnv * env,jobject clazz,jlong objHandle,jstring locales)548     static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
549         Paint* obj = reinterpret_cast<Paint*>(objHandle);
550         ScopedUtfChars localesChars(env, locales);
551         jint minikinLocaleListId = minikin::registerLocaleList(localesChars.c_str());
552         obj->setMinikinLocaleListId(minikinLocaleListId);
553         return minikinLocaleListId;
554     }
555 
setFontFeatureSettings(JNIEnv * env,jobject clazz,jlong paintHandle,jstring settings)556     static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
557         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
558         if (!settings) {
559             paint->setFontFeatureSettings(std::string());
560         } else {
561             ScopedUtfChars settingsChars(env, settings);
562             paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
563         }
564     }
565 
getMetricsInternal(jlong paintHandle,Paint::FontMetrics * metrics)566     static SkScalar getMetricsInternal(jlong paintHandle, Paint::FontMetrics *metrics) {
567         const int kElegantTop = 2500;
568         const int kElegantBottom = -1000;
569         const int kElegantAscent = 1900;
570         const int kElegantDescent = -500;
571         const int kElegantLeading = 0;
572         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
573         const Typeface* typeface = paint->getAndroidTypeface();
574         typeface = Typeface::resolveDefault(typeface);
575         minikin::FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
576         float saveSkewX = paint->getTextSkewX();
577         bool savefakeBold = paint->isFakeBoldText();
578         MinikinFontSkia::populateSkPaint(paint, baseFont.font->typeface().get(), baseFont.fakery);
579         SkScalar spacing = paint->getFontMetrics(metrics);
580         // The populateSkPaint call may have changed fake bold / text skew
581         // because we want to measure with those effects applied, so now
582         // restore the original settings.
583         paint->setTextSkewX(saveSkewX);
584         paint->setFakeBoldText(savefakeBold);
585         if (paint->getFamilyVariant() == minikin::FontFamily::Variant::ELEGANT) {
586             SkScalar size = paint->getTextSize();
587             metrics->fTop = -size * kElegantTop / 2048;
588             metrics->fBottom = -size * kElegantBottom / 2048;
589             metrics->fAscent = -size * kElegantAscent / 2048;
590             metrics->fDescent = -size * kElegantDescent / 2048;
591             metrics->fLeading = size * kElegantLeading / 2048;
592             spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
593         }
594         return spacing;
595     }
596 
getFontMetrics(JNIEnv * env,jobject,jlong paintHandle,jobject metricsObj)597     static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj) {
598         Paint::FontMetrics metrics;
599         SkScalar spacing = getMetricsInternal(paintHandle, &metrics);
600 
601         if (metricsObj) {
602             SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
603             env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
604             env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
605             env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
606             env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
607             env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
608         }
609         return SkScalarToFloat(spacing);
610     }
611 
getFontMetricsInt(JNIEnv * env,jobject,jlong paintHandle,jobject metricsObj)612     static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj) {
613         Paint::FontMetrics metrics;
614 
615         getMetricsInternal(paintHandle, &metrics);
616         int ascent = SkScalarRoundToInt(metrics.fAscent);
617         int descent = SkScalarRoundToInt(metrics.fDescent);
618         int leading = SkScalarRoundToInt(metrics.fLeading);
619 
620         if (metricsObj) {
621             SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
622             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
623             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
624             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
625             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
626             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
627         }
628         return descent - ascent + leading;
629     }
630 
631 
632     // ------------------ @CriticalNative ---------------------------
633 
reset(jlong objHandle)634     static void reset(jlong objHandle) {
635         Paint* obj = reinterpret_cast<Paint*>(objHandle);
636         obj->reset();
637         defaultSettingsForAndroid(obj);
638     }
639 
assign(jlong dstPaintHandle,jlong srcPaintHandle)640     static void assign(jlong dstPaintHandle, jlong srcPaintHandle) {
641         Paint* dst = reinterpret_cast<Paint*>(dstPaintHandle);
642         const Paint* src = reinterpret_cast<Paint*>(srcPaintHandle);
643         *dst = *src;
644     }
645 
646     // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
647     static const uint32_t sFilterBitmapFlag = 0x02;
648 
getFlags(jlong paintHandle)649     static jint getFlags(jlong paintHandle) {
650         Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
651         uint32_t result = nativePaint->getFlags();
652         result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
653         if (nativePaint->getFilterQuality() != kNone_SkFilterQuality) {
654             result |= sFilterBitmapFlag;
655         }
656         return static_cast<jint>(result);
657     }
658 
setFlags(jlong paintHandle,jint flags)659     static void setFlags(jlong paintHandle, jint flags) {
660         Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
661         // Instead of modifying 0x02, change the filter level.
662         nativePaint->setFilterQuality(flags & sFilterBitmapFlag
663                 ? kLow_SkFilterQuality
664                 : kNone_SkFilterQuality);
665         // Don't pass through filter flag, which is no longer stored in paint's flags.
666         flags &= ~sFilterBitmapFlag;
667         // Use the existing value for 0x02.
668         const uint32_t existing0x02Flag = nativePaint->getFlags() & sFilterBitmapFlag;
669         flags |= existing0x02Flag;
670         nativePaint->setFlags(flags);
671     }
672 
getHinting(jlong paintHandle)673     static jint getHinting(jlong paintHandle) {
674         return reinterpret_cast<Paint*>(paintHandle)->getHinting()
675                 == Paint::kNo_Hinting ? 0 : 1;
676     }
677 
setHinting(jlong paintHandle,jint mode)678     static void setHinting(jlong paintHandle, jint mode) {
679         reinterpret_cast<Paint*>(paintHandle)->setHinting(
680                 mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
681     }
682 
setAntiAlias(jlong paintHandle,jboolean aa)683     static void setAntiAlias(jlong paintHandle, jboolean aa) {
684         reinterpret_cast<Paint*>(paintHandle)->setAntiAlias(aa);
685     }
686 
setLinearText(jlong paintHandle,jboolean linearText)687     static void setLinearText(jlong paintHandle, jboolean linearText) {
688         reinterpret_cast<Paint*>(paintHandle)->setLinearText(linearText);
689     }
690 
setSubpixelText(jlong paintHandle,jboolean subpixelText)691     static void setSubpixelText(jlong paintHandle, jboolean subpixelText) {
692         reinterpret_cast<Paint*>(paintHandle)->setSubpixelText(subpixelText);
693     }
694 
setUnderlineText(jlong paintHandle,jboolean underlineText)695     static void setUnderlineText(jlong paintHandle, jboolean underlineText) {
696         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
697         uint32_t flags = paint->getFlags();
698         if (underlineText) {
699             flags |= Paint::kUnderlineText_ReserveFlag;
700         } else {
701             flags &= ~Paint::kUnderlineText_ReserveFlag;
702         }
703         paint->setFlags(flags);
704     }
705 
setStrikeThruText(jlong paintHandle,jboolean strikeThruText)706     static void setStrikeThruText(jlong paintHandle, jboolean strikeThruText) {
707         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
708         uint32_t flags = paint->getFlags();
709         if (strikeThruText) {
710             flags |= Paint::kStrikeThruText_ReserveFlag;
711         } else {
712             flags &= ~Paint::kStrikeThruText_ReserveFlag;
713         }
714         paint->setFlags(flags);
715     }
716 
setFakeBoldText(jlong paintHandle,jboolean fakeBoldText)717     static void setFakeBoldText(jlong paintHandle, jboolean fakeBoldText) {
718         reinterpret_cast<Paint*>(paintHandle)->setFakeBoldText(fakeBoldText);
719     }
720 
setFilterBitmap(jlong paintHandle,jboolean filterBitmap)721     static void setFilterBitmap(jlong paintHandle, jboolean filterBitmap) {
722         reinterpret_cast<Paint*>(paintHandle)->setFilterQuality(
723                 filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality);
724     }
725 
setDither(jlong paintHandle,jboolean dither)726     static void setDither(jlong paintHandle, jboolean dither) {
727         reinterpret_cast<Paint*>(paintHandle)->setDither(dither);
728     }
729 
getStyle(jlong objHandle)730     static jint getStyle(jlong objHandle) {
731         Paint* obj = reinterpret_cast<Paint*>(objHandle);
732         return static_cast<jint>(obj->getStyle());
733     }
734 
setStyle(jlong objHandle,jint styleHandle)735     static void setStyle(jlong objHandle, jint styleHandle) {
736         Paint* obj = reinterpret_cast<Paint*>(objHandle);
737         Paint::Style style = static_cast<Paint::Style>(styleHandle);
738         obj->setStyle(style);
739     }
740 
getColor(jlong paintHandle)741     static jint getColor(jlong paintHandle) {
742         int color;
743         color = reinterpret_cast<Paint*>(paintHandle)->getColor();
744         return static_cast<jint>(color);
745     }
746 
getAlpha(jlong paintHandle)747     static jint getAlpha(jlong paintHandle) {
748         int alpha;
749         alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha();
750         return static_cast<jint>(alpha);
751     }
752 
setColor(jlong paintHandle,jint color)753     static void setColor(jlong paintHandle, jint color) {
754         reinterpret_cast<Paint*>(paintHandle)->setColor(color);
755     }
756 
setAlpha(jlong paintHandle,jint a)757     static void setAlpha(jlong paintHandle, jint a) {
758         reinterpret_cast<Paint*>(paintHandle)->setAlpha(a);
759     }
760 
getStrokeWidth(jlong paintHandle)761     static jfloat getStrokeWidth(jlong paintHandle) {
762         return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeWidth());
763     }
764 
setStrokeWidth(jlong paintHandle,jfloat width)765     static void setStrokeWidth(jlong paintHandle, jfloat width) {
766         reinterpret_cast<Paint*>(paintHandle)->setStrokeWidth(width);
767     }
768 
getStrokeMiter(jlong paintHandle)769     static jfloat getStrokeMiter(jlong paintHandle) {
770         return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeMiter());
771     }
772 
setStrokeMiter(jlong paintHandle,jfloat miter)773     static void setStrokeMiter(jlong paintHandle, jfloat miter) {
774         reinterpret_cast<Paint*>(paintHandle)->setStrokeMiter(miter);
775     }
776 
getStrokeCap(jlong objHandle)777     static jint getStrokeCap(jlong objHandle) {
778         Paint* obj = reinterpret_cast<Paint*>(objHandle);
779         return static_cast<jint>(obj->getStrokeCap());
780     }
781 
setStrokeCap(jlong objHandle,jint capHandle)782     static void setStrokeCap(jlong objHandle, jint capHandle) {
783         Paint* obj = reinterpret_cast<Paint*>(objHandle);
784         Paint::Cap cap = static_cast<Paint::Cap>(capHandle);
785         obj->setStrokeCap(cap);
786     }
787 
getStrokeJoin(jlong objHandle)788     static jint getStrokeJoin(jlong objHandle) {
789         Paint* obj = reinterpret_cast<Paint*>(objHandle);
790         return static_cast<jint>(obj->getStrokeJoin());
791     }
792 
setStrokeJoin(jlong objHandle,jint joinHandle)793     static void setStrokeJoin(jlong objHandle, jint joinHandle) {
794         Paint* obj = reinterpret_cast<Paint*>(objHandle);
795         Paint::Join join = (Paint::Join) joinHandle;
796         obj->setStrokeJoin(join);
797     }
798 
getFillPath(jlong objHandle,jlong srcHandle,jlong dstHandle)799     static jboolean getFillPath(jlong objHandle, jlong srcHandle, jlong dstHandle) {
800         Paint* obj = reinterpret_cast<Paint*>(objHandle);
801         SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
802         SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
803         return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
804     }
805 
setShader(jlong objHandle,jlong shaderHandle)806     static jlong setShader(jlong objHandle, jlong shaderHandle) {
807         Paint* obj = reinterpret_cast<Paint*>(objHandle);
808         SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
809         obj->setShader(sk_ref_sp(shader));
810         return reinterpret_cast<jlong>(obj->getShader());
811     }
812 
setColorFilter(jlong objHandle,jlong filterHandle)813     static jlong setColorFilter(jlong objHandle, jlong filterHandle) {
814         Paint* obj = reinterpret_cast<Paint *>(objHandle);
815         SkColorFilter* filter  = reinterpret_cast<SkColorFilter *>(filterHandle);
816         obj->setColorFilter(sk_ref_sp(filter));
817         return reinterpret_cast<jlong>(obj->getColorFilter());
818     }
819 
setXfermode(jlong paintHandle,jint xfermodeHandle)820     static void setXfermode(jlong paintHandle, jint xfermodeHandle) {
821         // validate that the Java enum values match our expectations
822         static_assert(0 == static_cast<int>(SkBlendMode::kClear), "xfermode_mismatch");
823         static_assert(1 == static_cast<int>(SkBlendMode::kSrc), "xfermode_mismatch");
824         static_assert(2 == static_cast<int>(SkBlendMode::kDst), "xfermode_mismatch");
825         static_assert(3 == static_cast<int>(SkBlendMode::kSrcOver), "xfermode_mismatch");
826         static_assert(4 == static_cast<int>(SkBlendMode::kDstOver), "xfermode_mismatch");
827         static_assert(5 == static_cast<int>(SkBlendMode::kSrcIn), "xfermode_mismatch");
828         static_assert(6 == static_cast<int>(SkBlendMode::kDstIn), "xfermode_mismatch");
829         static_assert(7 == static_cast<int>(SkBlendMode::kSrcOut), "xfermode_mismatch");
830         static_assert(8 == static_cast<int>(SkBlendMode::kDstOut), "xfermode_mismatch");
831         static_assert(9 == static_cast<int>(SkBlendMode::kSrcATop), "xfermode_mismatch");
832         static_assert(10 == static_cast<int>(SkBlendMode::kDstATop), "xfermode_mismatch");
833         static_assert(11 == static_cast<int>(SkBlendMode::kXor), "xfermode_mismatch");
834         static_assert(16 == static_cast<int>(SkBlendMode::kDarken), "xfermode_mismatch");
835         static_assert(17 == static_cast<int>(SkBlendMode::kLighten), "xfermode_mismatch");
836         static_assert(13 == static_cast<int>(SkBlendMode::kModulate), "xfermode_mismatch");
837         static_assert(14 == static_cast<int>(SkBlendMode::kScreen), "xfermode_mismatch");
838         static_assert(12 == static_cast<int>(SkBlendMode::kPlus), "xfermode_mismatch");
839         static_assert(15 == static_cast<int>(SkBlendMode::kOverlay), "xfermode_mismatch");
840 
841         SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
842         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
843         paint->setBlendMode(mode);
844     }
845 
setPathEffect(jlong objHandle,jlong effectHandle)846     static jlong setPathEffect(jlong objHandle, jlong effectHandle) {
847         Paint* obj = reinterpret_cast<Paint*>(objHandle);
848         SkPathEffect* effect  = reinterpret_cast<SkPathEffect*>(effectHandle);
849         obj->setPathEffect(sk_ref_sp(effect));
850         return reinterpret_cast<jlong>(obj->getPathEffect());
851     }
852 
setMaskFilter(jlong objHandle,jlong maskfilterHandle)853     static jlong setMaskFilter(jlong objHandle, jlong maskfilterHandle) {
854         Paint* obj = reinterpret_cast<Paint*>(objHandle);
855         SkMaskFilter* maskfilter  = reinterpret_cast<SkMaskFilter*>(maskfilterHandle);
856         obj->setMaskFilter(sk_ref_sp(maskfilter));
857         return reinterpret_cast<jlong>(obj->getMaskFilter());
858     }
859 
setTypeface(jlong objHandle,jlong typefaceHandle)860     static void setTypeface(jlong objHandle, jlong typefaceHandle) {
861         Paint* paint = reinterpret_cast<Paint*>(objHandle);
862         paint->setAndroidTypeface(reinterpret_cast<Typeface*>(typefaceHandle));
863     }
864 
getTextAlign(jlong objHandle)865     static jint getTextAlign(jlong objHandle) {
866         Paint* obj = reinterpret_cast<Paint*>(objHandle);
867         return static_cast<jint>(obj->getTextAlign());
868     }
869 
setTextAlign(jlong objHandle,jint alignHandle)870     static void setTextAlign(jlong objHandle, jint alignHandle) {
871         Paint* obj = reinterpret_cast<Paint*>(objHandle);
872         Paint::Align align = static_cast<Paint::Align>(alignHandle);
873         obj->setTextAlign(align);
874     }
875 
setTextLocalesByMinikinLocaleListId(jlong objHandle,jint minikinLocaleListId)876     static void setTextLocalesByMinikinLocaleListId(jlong objHandle,
877             jint minikinLocaleListId) {
878         Paint* obj = reinterpret_cast<Paint*>(objHandle);
879         obj->setMinikinLocaleListId(minikinLocaleListId);
880     }
881 
isElegantTextHeight(jlong paintHandle)882     static jboolean isElegantTextHeight(jlong paintHandle) {
883         Paint* obj = reinterpret_cast<Paint*>(paintHandle);
884         return obj->getFamilyVariant() == minikin::FontFamily::Variant::ELEGANT;
885     }
886 
setElegantTextHeight(jlong paintHandle,jboolean aa)887     static void setElegantTextHeight(jlong paintHandle, jboolean aa) {
888         Paint* obj = reinterpret_cast<Paint*>(paintHandle);
889         obj->setFamilyVariant(
890                 aa ? minikin::FontFamily::Variant::ELEGANT : minikin::FontFamily::Variant::DEFAULT);
891     }
892 
getTextSize(jlong paintHandle)893     static jfloat getTextSize(jlong paintHandle) {
894         return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSize());
895     }
896 
setTextSize(jlong paintHandle,jfloat textSize)897     static void setTextSize(jlong paintHandle, jfloat textSize) {
898         reinterpret_cast<Paint*>(paintHandle)->setTextSize(textSize);
899     }
900 
getTextScaleX(jlong paintHandle)901     static jfloat getTextScaleX(jlong paintHandle) {
902         return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextScaleX());
903     }
904 
setTextScaleX(jlong paintHandle,jfloat scaleX)905     static void setTextScaleX(jlong paintHandle, jfloat scaleX) {
906         reinterpret_cast<Paint*>(paintHandle)->setTextScaleX(scaleX);
907     }
908 
getTextSkewX(jlong paintHandle)909     static jfloat getTextSkewX(jlong paintHandle) {
910         return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSkewX());
911     }
912 
setTextSkewX(jlong paintHandle,jfloat skewX)913     static void setTextSkewX(jlong paintHandle, jfloat skewX) {
914         reinterpret_cast<Paint*>(paintHandle)->setTextSkewX(skewX);
915     }
916 
getLetterSpacing(jlong paintHandle)917     static jfloat getLetterSpacing(jlong paintHandle) {
918         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
919         return paint->getLetterSpacing();
920     }
921 
setLetterSpacing(jlong paintHandle,jfloat letterSpacing)922     static void setLetterSpacing(jlong paintHandle, jfloat letterSpacing) {
923         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
924         paint->setLetterSpacing(letterSpacing);
925     }
926 
getWordSpacing(jlong paintHandle)927     static jfloat getWordSpacing(jlong paintHandle) {
928         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
929         return paint->getWordSpacing();
930     }
931 
setWordSpacing(jlong paintHandle,jfloat wordSpacing)932     static void setWordSpacing(jlong paintHandle, jfloat wordSpacing) {
933         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
934         paint->setWordSpacing(wordSpacing);
935     }
936 
getHyphenEdit(jlong paintHandle,jint hyphen)937     static jint getHyphenEdit(jlong paintHandle, jint hyphen) {
938         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
939         return paint->getHyphenEdit();
940     }
941 
setHyphenEdit(jlong paintHandle,jint hyphen)942     static void setHyphenEdit(jlong paintHandle, jint hyphen) {
943         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
944         paint->setHyphenEdit((uint32_t)hyphen);
945     }
946 
ascent(jlong paintHandle)947     static jfloat ascent(jlong paintHandle) {
948         Paint::FontMetrics metrics;
949         getMetricsInternal(paintHandle, &metrics);
950         return SkScalarToFloat(metrics.fAscent);
951     }
952 
descent(jlong paintHandle)953     static jfloat descent(jlong paintHandle) {
954         Paint::FontMetrics metrics;
955         getMetricsInternal(paintHandle, &metrics);
956         return SkScalarToFloat(metrics.fDescent);
957     }
958 
getUnderlinePosition(jlong paintHandle)959     static jfloat getUnderlinePosition(jlong paintHandle) {
960         Paint::FontMetrics metrics;
961         getMetricsInternal(paintHandle, &metrics);
962         SkScalar position;
963         if (metrics.hasUnderlinePosition(&position)) {
964             return SkScalarToFloat(position);
965         } else {
966             const SkScalar textSize = reinterpret_cast<Paint*>(paintHandle)->getTextSize();
967             return SkScalarToFloat(Paint::kStdUnderline_Top * textSize);
968         }
969     }
970 
getUnderlineThickness(jlong paintHandle)971     static jfloat getUnderlineThickness(jlong paintHandle) {
972         Paint::FontMetrics metrics;
973         getMetricsInternal(paintHandle, &metrics);
974         SkScalar thickness;
975         if (metrics.hasUnderlineThickness(&thickness)) {
976             return SkScalarToFloat(thickness);
977         } else {
978             const SkScalar textSize = reinterpret_cast<Paint*>(paintHandle)->getTextSize();
979             return SkScalarToFloat(Paint::kStdUnderline_Thickness * textSize);
980         }
981     }
982 
getStrikeThruPosition(jlong paintHandle)983     static jfloat getStrikeThruPosition(jlong paintHandle) {
984         const SkScalar textSize = reinterpret_cast<Paint*>(paintHandle)->getTextSize();
985         return SkScalarToFloat(Paint::kStdStrikeThru_Top * textSize);
986     }
987 
getStrikeThruThickness(jlong paintHandle)988     static jfloat getStrikeThruThickness(jlong paintHandle) {
989         const SkScalar textSize = reinterpret_cast<Paint*>(paintHandle)->getTextSize();
990         return SkScalarToFloat(Paint::kStdStrikeThru_Thickness * textSize);
991     }
992 
setShadowLayer(jlong paintHandle,jfloat radius,jfloat dx,jfloat dy,jint color)993     static void setShadowLayer(jlong paintHandle, jfloat radius,
994                                jfloat dx, jfloat dy, jint color) {
995         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
996         if (radius <= 0) {
997             paint->setLooper(nullptr);
998         }
999         else {
1000             SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
1001             paint->setLooper(SkBlurDrawLooper::Make((SkColor)color, sigma, dx, dy));
1002         }
1003     }
1004 
hasShadowLayer(jlong paintHandle)1005     static jboolean hasShadowLayer(jlong paintHandle) {
1006         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
1007         return paint->getLooper() && paint->getLooper()->asABlurShadow(nullptr);
1008     }
1009 
equalsForTextMeasurement(jlong lPaint,jlong rPaint)1010     static jboolean equalsForTextMeasurement(jlong lPaint, jlong rPaint) {
1011         if (lPaint == rPaint) {
1012             return true;
1013         }
1014         Paint* leftPaint = reinterpret_cast<Paint*>(lPaint);
1015         Paint* rightPaint = reinterpret_cast<Paint*>(rPaint);
1016 
1017         const Typeface* leftTypeface = Typeface::resolveDefault(leftPaint->getAndroidTypeface());
1018         const Typeface* rightTypeface = Typeface::resolveDefault(rightPaint->getAndroidTypeface());
1019         minikin::MinikinPaint leftMinikinPaint
1020                 = MinikinUtils::prepareMinikinPaint(leftPaint, leftTypeface);
1021         minikin::MinikinPaint rightMinikinPaint
1022                 = MinikinUtils::prepareMinikinPaint(rightPaint, rightTypeface);
1023 
1024         return leftMinikinPaint == rightMinikinPaint;
1025     }
1026 
1027 }; // namespace PaintGlue
1028 
1029 static const JNINativeMethod methods[] = {
1030     {"nGetNativeFinalizer", "()J", (void*) PaintGlue::getNativeFinalizer},
1031     {"nInit","()J", (void*) PaintGlue::init},
1032     {"nInitWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
1033     {"nBreakText","(J[CIIFI[F)I", (void*) PaintGlue::breakTextC},
1034     {"nBreakText","(JLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
1035     {"nGetTextAdvances","(J[CIIIII[FI)F",
1036             (void*) PaintGlue::getTextAdvances___CIIIII_FI},
1037     {"nGetTextAdvances","(JLjava/lang/String;IIIII[FI)F",
1038             (void*) PaintGlue::getTextAdvances__StringIIIII_FI},
1039 
1040     {"nGetTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C},
1041     {"nGetTextRunCursor", "(JLjava/lang/String;IIIII)I",
1042             (void*) PaintGlue::getTextRunCursor__String},
1043     {"nGetTextPath", "(JI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C},
1044     {"nGetTextPath", "(JILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String},
1045     {"nGetStringBounds", "(JLjava/lang/String;IIILandroid/graphics/Rect;)V",
1046             (void*) PaintGlue::getStringBounds },
1047     {"nGetCharArrayBounds", "(J[CIIILandroid/graphics/Rect;)V",
1048             (void*) PaintGlue::getCharArrayBounds },
1049     {"nHasGlyph", "(JILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph },
1050     {"nGetRunAdvance", "(J[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F},
1051     {"nGetOffsetForAdvance", "(J[CIIIIZF)I",
1052             (void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I},
1053 
1054     // --------------- @FastNative ----------------------
1055 
1056     {"nSetTextLocales","(JLjava/lang/String;)I", (void*) PaintGlue::setTextLocales},
1057     {"nSetFontFeatureSettings","(JLjava/lang/String;)V",
1058                 (void*) PaintGlue::setFontFeatureSettings},
1059     {"nGetFontMetrics", "(JLandroid/graphics/Paint$FontMetrics;)F",
1060                 (void*)PaintGlue::getFontMetrics},
1061     {"nGetFontMetricsInt", "(JLandroid/graphics/Paint$FontMetricsInt;)I",
1062             (void*)PaintGlue::getFontMetricsInt},
1063 
1064     // --------------- @CriticalNative ------------------
1065 
1066     {"nReset","(J)V", (void*) PaintGlue::reset},
1067     {"nSet","(JJ)V", (void*) PaintGlue::assign},
1068     {"nGetFlags","(J)I", (void*) PaintGlue::getFlags},
1069     {"nSetFlags","(JI)V", (void*) PaintGlue::setFlags},
1070     {"nGetHinting","(J)I", (void*) PaintGlue::getHinting},
1071     {"nSetHinting","(JI)V", (void*) PaintGlue::setHinting},
1072     {"nSetAntiAlias","(JZ)V", (void*) PaintGlue::setAntiAlias},
1073     {"nSetSubpixelText","(JZ)V", (void*) PaintGlue::setSubpixelText},
1074     {"nSetLinearText","(JZ)V", (void*) PaintGlue::setLinearText},
1075     {"nSetUnderlineText","(JZ)V", (void*) PaintGlue::setUnderlineText},
1076     {"nSetStrikeThruText","(JZ)V", (void*) PaintGlue::setStrikeThruText},
1077     {"nSetFakeBoldText","(JZ)V", (void*) PaintGlue::setFakeBoldText},
1078     {"nSetFilterBitmap","(JZ)V", (void*) PaintGlue::setFilterBitmap},
1079     {"nSetDither","(JZ)V", (void*) PaintGlue::setDither},
1080     {"nGetStyle","(J)I", (void*) PaintGlue::getStyle},
1081     {"nSetStyle","(JI)V", (void*) PaintGlue::setStyle},
1082     {"nGetColor","(J)I", (void*) PaintGlue::getColor},
1083     {"nSetColor","(JI)V", (void*) PaintGlue::setColor},
1084     {"nGetAlpha","(J)I", (void*) PaintGlue::getAlpha},
1085     {"nSetAlpha","(JI)V", (void*) PaintGlue::setAlpha},
1086     {"nGetStrokeWidth","(J)F", (void*) PaintGlue::getStrokeWidth},
1087     {"nSetStrokeWidth","(JF)V", (void*) PaintGlue::setStrokeWidth},
1088     {"nGetStrokeMiter","(J)F", (void*) PaintGlue::getStrokeMiter},
1089     {"nSetStrokeMiter","(JF)V", (void*) PaintGlue::setStrokeMiter},
1090     {"nGetStrokeCap","(J)I", (void*) PaintGlue::getStrokeCap},
1091     {"nSetStrokeCap","(JI)V", (void*) PaintGlue::setStrokeCap},
1092     {"nGetStrokeJoin","(J)I", (void*) PaintGlue::getStrokeJoin},
1093     {"nSetStrokeJoin","(JI)V", (void*) PaintGlue::setStrokeJoin},
1094     {"nGetFillPath","(JJJ)Z", (void*) PaintGlue::getFillPath},
1095     {"nSetShader","(JJ)J", (void*) PaintGlue::setShader},
1096     {"nSetColorFilter","(JJ)J", (void*) PaintGlue::setColorFilter},
1097     {"nSetXfermode","(JI)V", (void*) PaintGlue::setXfermode},
1098     {"nSetPathEffect","(JJ)J", (void*) PaintGlue::setPathEffect},
1099     {"nSetMaskFilter","(JJ)J", (void*) PaintGlue::setMaskFilter},
1100     {"nSetTypeface","(JJ)V", (void*) PaintGlue::setTypeface},
1101     {"nGetTextAlign","(J)I", (void*) PaintGlue::getTextAlign},
1102     {"nSetTextAlign","(JI)V", (void*) PaintGlue::setTextAlign},
1103     {"nSetTextLocalesByMinikinLocaleListId","(JI)V",
1104             (void*) PaintGlue::setTextLocalesByMinikinLocaleListId},
1105     {"nIsElegantTextHeight","(J)Z", (void*) PaintGlue::isElegantTextHeight},
1106     {"nSetElegantTextHeight","(JZ)V", (void*) PaintGlue::setElegantTextHeight},
1107     {"nGetTextSize","(J)F", (void*) PaintGlue::getTextSize},
1108     {"nSetTextSize","(JF)V", (void*) PaintGlue::setTextSize},
1109     {"nGetTextScaleX","(J)F", (void*) PaintGlue::getTextScaleX},
1110     {"nSetTextScaleX","(JF)V", (void*) PaintGlue::setTextScaleX},
1111     {"nGetTextSkewX","(J)F", (void*) PaintGlue::getTextSkewX},
1112     {"nSetTextSkewX","(JF)V", (void*) PaintGlue::setTextSkewX},
1113     {"nGetLetterSpacing","(J)F", (void*) PaintGlue::getLetterSpacing},
1114     {"nSetLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing},
1115     {"nGetWordSpacing","(J)F", (void*) PaintGlue::getWordSpacing},
1116     {"nSetWordSpacing","(JF)V", (void*) PaintGlue::setWordSpacing},
1117     {"nGetHyphenEdit", "(J)I", (void*) PaintGlue::getHyphenEdit},
1118     {"nSetHyphenEdit", "(JI)V", (void*) PaintGlue::setHyphenEdit},
1119     {"nAscent","(J)F", (void*) PaintGlue::ascent},
1120     {"nDescent","(J)F", (void*) PaintGlue::descent},
1121     {"nGetUnderlinePosition","(J)F", (void*) PaintGlue::getUnderlinePosition},
1122     {"nGetUnderlineThickness","(J)F", (void*) PaintGlue::getUnderlineThickness},
1123     {"nGetStrikeThruPosition","(J)F", (void*) PaintGlue::getStrikeThruPosition},
1124     {"nGetStrikeThruThickness","(J)F", (void*) PaintGlue::getStrikeThruThickness},
1125     {"nSetShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer},
1126     {"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer},
1127     {"nEqualsForTextMeasurement", "(JJ)Z", (void*)PaintGlue::equalsForTextMeasurement},
1128 };
1129 
register_android_graphics_Paint(JNIEnv * env)1130 int register_android_graphics_Paint(JNIEnv* env) {
1131     gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics");
1132     gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class);
1133 
1134     gFontMetrics_fieldID.top = GetFieldIDOrDie(env, gFontMetrics_class, "top", "F");
1135     gFontMetrics_fieldID.ascent = GetFieldIDOrDie(env, gFontMetrics_class, "ascent", "F");
1136     gFontMetrics_fieldID.descent = GetFieldIDOrDie(env, gFontMetrics_class, "descent", "F");
1137     gFontMetrics_fieldID.bottom = GetFieldIDOrDie(env, gFontMetrics_class, "bottom", "F");
1138     gFontMetrics_fieldID.leading = GetFieldIDOrDie(env, gFontMetrics_class, "leading", "F");
1139 
1140     gFontMetricsInt_class = FindClassOrDie(env, "android/graphics/Paint$FontMetricsInt");
1141     gFontMetricsInt_class = MakeGlobalRefOrDie(env, gFontMetricsInt_class);
1142 
1143     gFontMetricsInt_fieldID.top = GetFieldIDOrDie(env, gFontMetricsInt_class, "top", "I");
1144     gFontMetricsInt_fieldID.ascent = GetFieldIDOrDie(env, gFontMetricsInt_class, "ascent", "I");
1145     gFontMetricsInt_fieldID.descent = GetFieldIDOrDie(env, gFontMetricsInt_class, "descent", "I");
1146     gFontMetricsInt_fieldID.bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I");
1147     gFontMetricsInt_fieldID.leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I");
1148 
1149     return RegisterMethodsOrDie(env, "android/graphics/Paint", methods, NELEM(methods));
1150 }
1151 
1152 }
1153