• 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 <android_runtime/AndroidRuntime.h>
25 #include <ScopedUtfChars.h>
26 
27 #include "SkBlurDrawLooper.h"
28 #include "SkColorFilter.h"
29 #include "SkMaskFilter.h"
30 #include "SkRasterizer.h"
31 #include "SkShader.h"
32 #include "SkTypeface.h"
33 #include "SkXfermode.h"
34 #include "unicode/uloc.h"
35 #include "unicode/ushape.h"
36 #include "utils/Blur.h"
37 
38 #include <minikin/GraphemeBreak.h>
39 #include "MinikinSkia.h"
40 #include "MinikinUtils.h"
41 #include "Paint.h"
42 #include "TypefaceImpl.h"
43 
44 // temporary for debugging
45 #include <Caches.h>
46 #include <utils/Log.h>
47 
48 namespace android {
49 
50 struct JMetricsID {
51     jfieldID    top;
52     jfieldID    ascent;
53     jfieldID    descent;
54     jfieldID    bottom;
55     jfieldID    leading;
56 };
57 
58 static jclass   gFontMetrics_class;
59 static JMetricsID gFontMetrics_fieldID;
60 
61 static jclass   gFontMetricsInt_class;
62 static JMetricsID gFontMetricsInt_fieldID;
63 
defaultSettingsForAndroid(Paint * paint)64 static void defaultSettingsForAndroid(Paint* paint) {
65     // GlyphID encoding is required because we are using Harfbuzz shaping
66     paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
67 }
68 
69 class PaintGlue {
70 public:
71     enum MoveOpt {
72         AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT
73     };
74 
finalizer(JNIEnv * env,jobject clazz,jlong objHandle)75     static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
76         Paint* obj = reinterpret_cast<Paint*>(objHandle);
77         delete obj;
78     }
79 
init(JNIEnv * env,jobject clazz)80     static jlong init(JNIEnv* env, jobject clazz) {
81         Paint* obj = new Paint();
82         defaultSettingsForAndroid(obj);
83         return reinterpret_cast<jlong>(obj);
84     }
85 
initWithPaint(JNIEnv * env,jobject clazz,jlong paintHandle)86     static jlong initWithPaint(JNIEnv* env, jobject clazz, jlong paintHandle) {
87         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
88         Paint* obj = new Paint(*paint);
89         return reinterpret_cast<jlong>(obj);
90     }
91 
reset(JNIEnv * env,jobject clazz,jlong objHandle)92     static void reset(JNIEnv* env, jobject clazz, jlong objHandle) {
93         Paint* obj = reinterpret_cast<Paint*>(objHandle);
94         obj->reset();
95         defaultSettingsForAndroid(obj);
96     }
97 
assign(JNIEnv * env,jobject clazz,jlong dstPaintHandle,jlong srcPaintHandle)98     static void assign(JNIEnv* env, jobject clazz, jlong dstPaintHandle, jlong srcPaintHandle) {
99         Paint* dst = reinterpret_cast<Paint*>(dstPaintHandle);
100         const Paint* src = reinterpret_cast<Paint*>(srcPaintHandle);
101         *dst = *src;
102     }
103 
104     // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
105     static const uint32_t sFilterBitmapFlag = 0x02;
106 
getFlags(JNIEnv * env,jobject paint)107     static jint getFlags(JNIEnv* env, jobject paint) {
108         NPE_CHECK_RETURN_ZERO(env, paint);
109         Paint* nativePaint = GraphicsJNI::getNativePaint(env, paint);
110         uint32_t result = nativePaint->getFlags();
111         result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
112         if (nativePaint->getFilterLevel() != Paint::kNone_FilterLevel) {
113             result |= sFilterBitmapFlag;
114         }
115         return static_cast<jint>(result);
116     }
117 
setFlags(JNIEnv * env,jobject paint,jint flags)118     static void setFlags(JNIEnv* env, jobject paint, jint flags) {
119         NPE_CHECK_RETURN_VOID(env, paint);
120         Paint* nativePaint = GraphicsJNI::getNativePaint(env, paint);
121         // Instead of modifying 0x02, change the filter level.
122         nativePaint->setFilterLevel(flags & sFilterBitmapFlag
123                 ? Paint::kLow_FilterLevel
124                 : Paint::kNone_FilterLevel);
125         // Don't pass through filter flag, which is no longer stored in paint's flags.
126         flags &= ~sFilterBitmapFlag;
127         // Use the existing value for 0x02.
128         const uint32_t existing0x02Flag = nativePaint->getFlags() & sFilterBitmapFlag;
129         flags |= existing0x02Flag;
130         nativePaint->setFlags(flags);
131     }
132 
getHinting(JNIEnv * env,jobject paint)133     static jint getHinting(JNIEnv* env, jobject paint) {
134         NPE_CHECK_RETURN_ZERO(env, paint);
135         return GraphicsJNI::getNativePaint(env, paint)->getHinting()
136                 == Paint::kNo_Hinting ? 0 : 1;
137     }
138 
setHinting(JNIEnv * env,jobject paint,jint mode)139     static void setHinting(JNIEnv* env, jobject paint, jint mode) {
140         NPE_CHECK_RETURN_VOID(env, paint);
141         GraphicsJNI::getNativePaint(env, paint)->setHinting(
142                 mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
143     }
144 
setAntiAlias(JNIEnv * env,jobject paint,jboolean aa)145     static void setAntiAlias(JNIEnv* env, jobject paint, jboolean aa) {
146         NPE_CHECK_RETURN_VOID(env, paint);
147         GraphicsJNI::getNativePaint(env, paint)->setAntiAlias(aa);
148     }
149 
setLinearText(JNIEnv * env,jobject paint,jboolean linearText)150     static void setLinearText(JNIEnv* env, jobject paint, jboolean linearText) {
151         NPE_CHECK_RETURN_VOID(env, paint);
152         GraphicsJNI::getNativePaint(env, paint)->setLinearText(linearText);
153     }
154 
setSubpixelText(JNIEnv * env,jobject paint,jboolean subpixelText)155     static void setSubpixelText(JNIEnv* env, jobject paint, jboolean subpixelText) {
156         NPE_CHECK_RETURN_VOID(env, paint);
157         GraphicsJNI::getNativePaint(env, paint)->setSubpixelText(subpixelText);
158     }
159 
setUnderlineText(JNIEnv * env,jobject paint,jboolean underlineText)160     static void setUnderlineText(JNIEnv* env, jobject paint, jboolean underlineText) {
161         NPE_CHECK_RETURN_VOID(env, paint);
162         GraphicsJNI::getNativePaint(env, paint)->setUnderlineText(underlineText);
163     }
164 
setStrikeThruText(JNIEnv * env,jobject paint,jboolean strikeThruText)165     static void setStrikeThruText(JNIEnv* env, jobject paint, jboolean strikeThruText) {
166         NPE_CHECK_RETURN_VOID(env, paint);
167         GraphicsJNI::getNativePaint(env, paint)->setStrikeThruText(strikeThruText);
168     }
169 
setFakeBoldText(JNIEnv * env,jobject paint,jboolean fakeBoldText)170     static void setFakeBoldText(JNIEnv* env, jobject paint, jboolean fakeBoldText) {
171         NPE_CHECK_RETURN_VOID(env, paint);
172         GraphicsJNI::getNativePaint(env, paint)->setFakeBoldText(fakeBoldText);
173     }
174 
setFilterBitmap(JNIEnv * env,jobject paint,jboolean filterBitmap)175     static void setFilterBitmap(JNIEnv* env, jobject paint, jboolean filterBitmap) {
176         NPE_CHECK_RETURN_VOID(env, paint);
177         GraphicsJNI::getNativePaint(env, paint)->setFilterLevel(
178                 filterBitmap ? Paint::kLow_FilterLevel : Paint::kNone_FilterLevel);
179     }
180 
setDither(JNIEnv * env,jobject paint,jboolean dither)181     static void setDither(JNIEnv* env, jobject paint, jboolean dither) {
182         NPE_CHECK_RETURN_VOID(env, paint);
183         GraphicsJNI::getNativePaint(env, paint)->setDither(dither);
184     }
185 
getStyle(JNIEnv * env,jobject clazz,jlong objHandle)186     static jint getStyle(JNIEnv* env, jobject clazz,jlong objHandle) {
187         Paint* obj = reinterpret_cast<Paint*>(objHandle);
188         return static_cast<jint>(obj->getStyle());
189     }
190 
setStyle(JNIEnv * env,jobject clazz,jlong objHandle,jint styleHandle)191     static void setStyle(JNIEnv* env, jobject clazz, jlong objHandle, jint styleHandle) {
192         Paint* obj = reinterpret_cast<Paint*>(objHandle);
193         Paint::Style style = static_cast<Paint::Style>(styleHandle);
194         obj->setStyle(style);
195     }
196 
getColor(JNIEnv * env,jobject paint)197     static jint getColor(JNIEnv* env, jobject paint) {
198         NPE_CHECK_RETURN_ZERO(env, paint);
199         int color;
200         color = GraphicsJNI::getNativePaint(env, paint)->getColor();
201         return static_cast<jint>(color);
202     }
203 
getAlpha(JNIEnv * env,jobject paint)204     static jint getAlpha(JNIEnv* env, jobject paint) {
205         NPE_CHECK_RETURN_ZERO(env, paint);
206         int alpha;
207         alpha = GraphicsJNI::getNativePaint(env, paint)->getAlpha();
208         return static_cast<jint>(alpha);
209     }
210 
setColor(JNIEnv * env,jobject paint,jint color)211     static void setColor(JNIEnv* env, jobject paint, jint color) {
212         NPE_CHECK_RETURN_VOID(env, paint);
213         GraphicsJNI::getNativePaint(env, paint)->setColor(color);
214     }
215 
setAlpha(JNIEnv * env,jobject paint,jint a)216     static void setAlpha(JNIEnv* env, jobject paint, jint a) {
217         NPE_CHECK_RETURN_VOID(env, paint);
218         GraphicsJNI::getNativePaint(env, paint)->setAlpha(a);
219     }
220 
getStrokeWidth(JNIEnv * env,jobject paint)221     static jfloat getStrokeWidth(JNIEnv* env, jobject paint) {
222         NPE_CHECK_RETURN_ZERO(env, paint);
223         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeWidth());
224     }
225 
setStrokeWidth(JNIEnv * env,jobject paint,jfloat width)226     static void setStrokeWidth(JNIEnv* env, jobject paint, jfloat width) {
227         NPE_CHECK_RETURN_VOID(env, paint);
228         GraphicsJNI::getNativePaint(env, paint)->setStrokeWidth(width);
229     }
230 
getStrokeMiter(JNIEnv * env,jobject paint)231     static jfloat getStrokeMiter(JNIEnv* env, jobject paint) {
232         NPE_CHECK_RETURN_ZERO(env, paint);
233         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeMiter());
234     }
235 
setStrokeMiter(JNIEnv * env,jobject paint,jfloat miter)236     static void setStrokeMiter(JNIEnv* env, jobject paint, jfloat miter) {
237         NPE_CHECK_RETURN_VOID(env, paint);
238         GraphicsJNI::getNativePaint(env, paint)->setStrokeMiter(miter);
239     }
240 
getStrokeCap(JNIEnv * env,jobject clazz,jlong objHandle)241     static jint getStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle) {
242         Paint* obj = reinterpret_cast<Paint*>(objHandle);
243         return static_cast<jint>(obj->getStrokeCap());
244     }
245 
setStrokeCap(JNIEnv * env,jobject clazz,jlong objHandle,jint capHandle)246     static void setStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle, jint capHandle) {
247         Paint* obj = reinterpret_cast<Paint*>(objHandle);
248         Paint::Cap cap = static_cast<Paint::Cap>(capHandle);
249         obj->setStrokeCap(cap);
250     }
251 
getStrokeJoin(JNIEnv * env,jobject clazz,jlong objHandle)252     static jint getStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle) {
253         Paint* obj = reinterpret_cast<Paint*>(objHandle);
254         return static_cast<jint>(obj->getStrokeJoin());
255     }
256 
setStrokeJoin(JNIEnv * env,jobject clazz,jlong objHandle,jint joinHandle)257     static void setStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle, jint joinHandle) {
258         Paint* obj = reinterpret_cast<Paint*>(objHandle);
259         Paint::Join join = (Paint::Join) joinHandle;
260         obj->setStrokeJoin(join);
261     }
262 
getFillPath(JNIEnv * env,jobject clazz,jlong objHandle,jlong srcHandle,jlong dstHandle)263     static jboolean getFillPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong dstHandle) {
264         Paint* obj = reinterpret_cast<Paint*>(objHandle);
265         SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
266         SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
267         return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
268     }
269 
setShader(JNIEnv * env,jobject clazz,jlong objHandle,jlong shaderHandle)270     static jlong setShader(JNIEnv* env, jobject clazz, jlong objHandle, jlong shaderHandle) {
271         Paint* obj = reinterpret_cast<Paint*>(objHandle);
272         SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
273         return reinterpret_cast<jlong>(obj->setShader(shader));
274     }
275 
setColorFilter(JNIEnv * env,jobject clazz,jlong objHandle,jlong filterHandle)276     static jlong setColorFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong filterHandle) {
277         Paint* obj = reinterpret_cast<Paint *>(objHandle);
278         SkColorFilter* filter  = reinterpret_cast<SkColorFilter *>(filterHandle);
279         return reinterpret_cast<jlong>(obj->setColorFilter(filter));
280     }
281 
setXfermode(JNIEnv * env,jobject clazz,jlong objHandle,jlong xfermodeHandle)282     static jlong setXfermode(JNIEnv* env, jobject clazz, jlong objHandle, jlong xfermodeHandle) {
283         Paint* obj = reinterpret_cast<Paint*>(objHandle);
284         SkXfermode* xfermode = reinterpret_cast<SkXfermode*>(xfermodeHandle);
285         return reinterpret_cast<jlong>(obj->setXfermode(xfermode));
286     }
287 
setPathEffect(JNIEnv * env,jobject clazz,jlong objHandle,jlong effectHandle)288     static jlong setPathEffect(JNIEnv* env, jobject clazz, jlong objHandle, jlong effectHandle) {
289         Paint* obj = reinterpret_cast<Paint*>(objHandle);
290         SkPathEffect* effect  = reinterpret_cast<SkPathEffect*>(effectHandle);
291         return reinterpret_cast<jlong>(obj->setPathEffect(effect));
292     }
293 
setMaskFilter(JNIEnv * env,jobject clazz,jlong objHandle,jlong maskfilterHandle)294     static jlong setMaskFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong maskfilterHandle) {
295         Paint* obj = reinterpret_cast<Paint*>(objHandle);
296         SkMaskFilter* maskfilter  = reinterpret_cast<SkMaskFilter*>(maskfilterHandle);
297         return reinterpret_cast<jlong>(obj->setMaskFilter(maskfilter));
298     }
299 
setTypeface(JNIEnv * env,jobject clazz,jlong objHandle,jlong typefaceHandle)300     static jlong setTypeface(JNIEnv* env, jobject clazz, jlong objHandle, jlong typefaceHandle) {
301         // TODO: in Paint refactoring, set typeface on android Paint, not Paint
302         return NULL;
303     }
304 
setRasterizer(JNIEnv * env,jobject clazz,jlong objHandle,jlong rasterizerHandle)305     static jlong setRasterizer(JNIEnv* env, jobject clazz, jlong objHandle, jlong rasterizerHandle) {
306         Paint* obj = reinterpret_cast<Paint*>(objHandle);
307         SkAutoTUnref<SkRasterizer> rasterizer(GraphicsJNI::refNativeRasterizer(rasterizerHandle));
308         return reinterpret_cast<jlong>(obj->setRasterizer(rasterizer));
309     }
310 
getTextAlign(JNIEnv * env,jobject clazz,jlong objHandle)311     static jint getTextAlign(JNIEnv* env, jobject clazz, jlong objHandle) {
312         Paint* obj = reinterpret_cast<Paint*>(objHandle);
313         return static_cast<jint>(obj->getTextAlign());
314     }
315 
setTextAlign(JNIEnv * env,jobject clazz,jlong objHandle,jint alignHandle)316     static void setTextAlign(JNIEnv* env, jobject clazz, jlong objHandle, jint alignHandle) {
317         Paint* obj = reinterpret_cast<Paint*>(objHandle);
318         Paint::Align align = static_cast<Paint::Align>(alignHandle);
319         obj->setTextAlign(align);
320     }
321 
322     // generate bcp47 identifier for the supplied locale
toLanguageTag(char * output,size_t outSize,const char * locale)323     static void toLanguageTag(char* output, size_t outSize,
324             const char* locale) {
325         if (output == NULL || outSize <= 0) {
326             return;
327         }
328         if (locale == NULL) {
329             output[0] = '\0';
330             return;
331         }
332         char canonicalChars[ULOC_FULLNAME_CAPACITY];
333         UErrorCode uErr = U_ZERO_ERROR;
334         uloc_canonicalize(locale, canonicalChars, ULOC_FULLNAME_CAPACITY,
335                 &uErr);
336         if (U_SUCCESS(uErr)) {
337             char likelyChars[ULOC_FULLNAME_CAPACITY];
338             uErr = U_ZERO_ERROR;
339             uloc_addLikelySubtags(canonicalChars, likelyChars,
340                     ULOC_FULLNAME_CAPACITY, &uErr);
341             if (U_SUCCESS(uErr)) {
342                 uErr = U_ZERO_ERROR;
343                 uloc_toLanguageTag(likelyChars, output, outSize, FALSE, &uErr);
344                 if (U_SUCCESS(uErr)) {
345                     return;
346                 } else {
347                     ALOGD("uloc_toLanguageTag(\"%s\") failed: %s", likelyChars,
348                             u_errorName(uErr));
349                 }
350             } else {
351                 ALOGD("uloc_addLikelySubtags(\"%s\") failed: %s",
352                         canonicalChars, u_errorName(uErr));
353             }
354         } else {
355             ALOGD("uloc_canonicalize(\"%s\") failed: %s", locale,
356                     u_errorName(uErr));
357         }
358         // unable to build a proper language identifier
359         output[0] = '\0';
360     }
361 
setTextLocale(JNIEnv * env,jobject clazz,jlong objHandle,jstring locale)362     static void setTextLocale(JNIEnv* env, jobject clazz, jlong objHandle, jstring locale) {
363         Paint* obj = reinterpret_cast<Paint*>(objHandle);
364         ScopedUtfChars localeChars(env, locale);
365         char langTag[ULOC_FULLNAME_CAPACITY];
366         toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, localeChars.c_str());
367 
368         obj->setTextLocale(langTag);
369     }
370 
isElegantTextHeight(JNIEnv * env,jobject paint)371     static jboolean isElegantTextHeight(JNIEnv* env, jobject paint) {
372         NPE_CHECK_RETURN_ZERO(env, paint);
373         Paint* obj = GraphicsJNI::getNativePaint(env, paint);
374         return obj->getFontVariant() == VARIANT_ELEGANT;
375     }
376 
setElegantTextHeight(JNIEnv * env,jobject paint,jboolean aa)377     static void setElegantTextHeight(JNIEnv* env, jobject paint, jboolean aa) {
378         NPE_CHECK_RETURN_VOID(env, paint);
379         Paint* obj = GraphicsJNI::getNativePaint(env, paint);
380         obj->setFontVariant(aa ? VARIANT_ELEGANT : VARIANT_DEFAULT);
381     }
382 
getTextSize(JNIEnv * env,jobject paint)383     static jfloat getTextSize(JNIEnv* env, jobject paint) {
384         NPE_CHECK_RETURN_ZERO(env, paint);
385         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSize());
386     }
387 
setTextSize(JNIEnv * env,jobject paint,jfloat textSize)388     static void setTextSize(JNIEnv* env, jobject paint, jfloat textSize) {
389         NPE_CHECK_RETURN_VOID(env, paint);
390         GraphicsJNI::getNativePaint(env, paint)->setTextSize(textSize);
391     }
392 
getTextScaleX(JNIEnv * env,jobject paint)393     static jfloat getTextScaleX(JNIEnv* env, jobject paint) {
394         NPE_CHECK_RETURN_ZERO(env, paint);
395         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextScaleX());
396     }
397 
setTextScaleX(JNIEnv * env,jobject paint,jfloat scaleX)398     static void setTextScaleX(JNIEnv* env, jobject paint, jfloat scaleX) {
399         NPE_CHECK_RETURN_VOID(env, paint);
400         GraphicsJNI::getNativePaint(env, paint)->setTextScaleX(scaleX);
401     }
402 
getTextSkewX(JNIEnv * env,jobject paint)403     static jfloat getTextSkewX(JNIEnv* env, jobject paint) {
404         NPE_CHECK_RETURN_ZERO(env, paint);
405         return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSkewX());
406     }
407 
setTextSkewX(JNIEnv * env,jobject paint,jfloat skewX)408     static void setTextSkewX(JNIEnv* env, jobject paint, jfloat skewX) {
409         NPE_CHECK_RETURN_VOID(env, paint);
410         GraphicsJNI::getNativePaint(env, paint)->setTextSkewX(skewX);
411     }
412 
getLetterSpacing(JNIEnv * env,jobject clazz,jlong paintHandle)413     static jfloat getLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle) {
414         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
415         return paint->getLetterSpacing();
416     }
417 
setLetterSpacing(JNIEnv * env,jobject clazz,jlong paintHandle,jfloat letterSpacing)418     static void setLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat letterSpacing) {
419         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
420         paint->setLetterSpacing(letterSpacing);
421     }
422 
setFontFeatureSettings(JNIEnv * env,jobject clazz,jlong paintHandle,jstring settings)423     static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
424         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
425         if (!settings) {
426             paint->setFontFeatureSettings(std::string());
427         } else {
428             ScopedUtfChars settingsChars(env, settings);
429             paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
430         }
431     }
432 
getMetricsInternal(JNIEnv * env,jobject jpaint,Paint::FontMetrics * metrics)433     static SkScalar getMetricsInternal(JNIEnv* env, jobject jpaint, Paint::FontMetrics *metrics) {
434         const int kElegantTop = 2500;
435         const int kElegantBottom = -1000;
436         const int kElegantAscent = 1900;
437         const int kElegantDescent = -500;
438         const int kElegantLeading = 0;
439         Paint* paint = GraphicsJNI::getNativePaint(env, jpaint);
440         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
441         typeface = TypefaceImpl_resolveDefault(typeface);
442         FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
443         float saveSkewX = paint->getTextSkewX();
444         bool savefakeBold = paint->isFakeBoldText();
445         MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
446         SkScalar spacing = paint->getFontMetrics(metrics);
447         // The populateSkPaint call may have changed fake bold / text skew
448         // because we want to measure with those effects applied, so now
449         // restore the original settings.
450         paint->setTextSkewX(saveSkewX);
451         paint->setFakeBoldText(savefakeBold);
452         if (paint->getFontVariant() == VARIANT_ELEGANT) {
453             SkScalar size = paint->getTextSize();
454             metrics->fTop = -size * kElegantTop / 2048;
455             metrics->fBottom = -size * kElegantBottom / 2048;
456             metrics->fAscent = -size * kElegantAscent / 2048;
457             metrics->fDescent = -size * kElegantDescent / 2048;
458             metrics->fLeading = size * kElegantLeading / 2048;
459             spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
460         }
461         return spacing;
462     }
463 
ascent(JNIEnv * env,jobject paint)464     static jfloat ascent(JNIEnv* env, jobject paint) {
465         NPE_CHECK_RETURN_ZERO(env, paint);
466         Paint::FontMetrics metrics;
467         getMetricsInternal(env, paint, &metrics);
468         return SkScalarToFloat(metrics.fAscent);
469     }
470 
descent(JNIEnv * env,jobject paint)471     static jfloat descent(JNIEnv* env, jobject paint) {
472         NPE_CHECK_RETURN_ZERO(env, paint);
473         Paint::FontMetrics metrics;
474         getMetricsInternal(env, paint, &metrics);
475         return SkScalarToFloat(metrics.fDescent);
476     }
477 
getFontMetrics(JNIEnv * env,jobject paint,jobject metricsObj)478     static jfloat getFontMetrics(JNIEnv* env, jobject paint, jobject metricsObj) {
479         NPE_CHECK_RETURN_ZERO(env, paint);
480         Paint::FontMetrics metrics;
481         SkScalar spacing = getMetricsInternal(env, paint, &metrics);
482 
483         if (metricsObj) {
484             SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
485             env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
486             env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
487             env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
488             env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
489             env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
490         }
491         return SkScalarToFloat(spacing);
492     }
493 
getFontMetricsInt(JNIEnv * env,jobject paint,jobject metricsObj)494     static jint getFontMetricsInt(JNIEnv* env, jobject paint, jobject metricsObj) {
495         NPE_CHECK_RETURN_ZERO(env, paint);
496         Paint::FontMetrics metrics;
497 
498         getMetricsInternal(env, paint, &metrics);
499         int ascent = SkScalarRoundToInt(metrics.fAscent);
500         int descent = SkScalarRoundToInt(metrics.fDescent);
501         int leading = SkScalarRoundToInt(metrics.fLeading);
502 
503         if (metricsObj) {
504             SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
505             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
506             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
507             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
508             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
509             env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
510         }
511         return descent - ascent + leading;
512     }
513 
measureText_CIII(JNIEnv * env,jobject jpaint,jcharArray text,jint index,jint count,jint bidiFlags)514     static jfloat measureText_CIII(JNIEnv* env, jobject jpaint, jcharArray text, jint index, jint count,
515             jint bidiFlags) {
516         NPE_CHECK_RETURN_ZERO(env, jpaint);
517         NPE_CHECK_RETURN_ZERO(env, text);
518 
519         size_t textLength = env->GetArrayLength(text);
520         if ((index | count) < 0 || (size_t)(index + count) > textLength) {
521             doThrowAIOOBE(env);
522             return 0;
523         }
524         if (count == 0) {
525             return 0;
526         }
527 
528         Paint* paint = GraphicsJNI::getNativePaint(env, jpaint);
529         const jchar* textArray = env->GetCharArrayElements(text, NULL);
530         jfloat result = 0;
531 
532         Layout layout;
533         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
534         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, index, count, textLength);
535         result = layout.getAdvance();
536         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
537         return result;
538     }
539 
measureText_StringIII(JNIEnv * env,jobject jpaint,jstring text,jint start,jint end,jint bidiFlags)540     static jfloat measureText_StringIII(JNIEnv* env, jobject jpaint, jstring text, jint start, jint end,
541             jint bidiFlags) {
542         NPE_CHECK_RETURN_ZERO(env, jpaint);
543         NPE_CHECK_RETURN_ZERO(env, text);
544 
545         size_t textLength = env->GetStringLength(text);
546         int count = end - start;
547         if ((start | count) < 0 || (size_t)end > textLength) {
548             doThrowAIOOBE(env);
549             return 0;
550         }
551         if (count == 0) {
552             return 0;
553         }
554 
555         const jchar* textArray = env->GetStringChars(text, NULL);
556         Paint* paint = GraphicsJNI::getNativePaint(env, jpaint);
557         jfloat width = 0;
558 
559         Layout layout;
560         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
561         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, start, count, textLength);
562         width = layout.getAdvance();
563 
564         env->ReleaseStringChars(text, textArray);
565         return width;
566     }
567 
measureText_StringI(JNIEnv * env,jobject jpaint,jstring text,jint bidiFlags)568     static jfloat measureText_StringI(JNIEnv* env, jobject jpaint, jstring text, jint bidiFlags) {
569         NPE_CHECK_RETURN_ZERO(env, jpaint);
570         NPE_CHECK_RETURN_ZERO(env, text);
571 
572         size_t textLength = env->GetStringLength(text);
573         if (textLength == 0) {
574             return 0;
575         }
576 
577         const jchar* textArray = env->GetStringChars(text, NULL);
578         Paint* paint = GraphicsJNI::getNativePaint(env, jpaint);
579         jfloat width = 0;
580 
581         Layout layout;
582         TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
583         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, 0, textLength, textLength);
584         width = layout.getAdvance();
585 
586         env->ReleaseStringChars(text, textArray);
587         return width;
588     }
589 
dotextwidths(JNIEnv * env,Paint * paint,TypefaceImpl * typeface,const jchar text[],int count,jfloatArray widths,jint bidiFlags)590     static int dotextwidths(JNIEnv* env, Paint* paint, TypefaceImpl* typeface, const jchar text[], int count,
591             jfloatArray widths, jint bidiFlags) {
592         NPE_CHECK_RETURN_ZERO(env, paint);
593         NPE_CHECK_RETURN_ZERO(env, text);
594 
595         if (count < 0 || !widths) {
596             doThrowAIOOBE(env);
597             return 0;
598         }
599         if (count == 0) {
600             return 0;
601         }
602         size_t widthsLength = env->GetArrayLength(widths);
603         if ((size_t)count > widthsLength) {
604             doThrowAIOOBE(env);
605             return 0;
606         }
607 
608         AutoJavaFloatArray autoWidths(env, widths, count);
609         jfloat* widthsArray = autoWidths.ptr();
610 
611         Layout layout;
612         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
613         layout.getAdvances(widthsArray);
614 
615         return count;
616     }
617 
getTextWidths___CIII_F(JNIEnv * env,jobject clazz,jlong paintHandle,jlong typefaceHandle,jcharArray text,jint index,jint count,jint bidiFlags,jfloatArray widths)618     static jint getTextWidths___CIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray text,
619             jint index, jint count, jint bidiFlags, jfloatArray widths) {
620         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
621         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
622         const jchar* textArray = env->GetCharArrayElements(text, NULL);
623         count = dotextwidths(env, paint, typeface, textArray + index, count, widths, bidiFlags);
624         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
625                                       JNI_ABORT);
626         return count;
627     }
628 
getTextWidths__StringIII_F(JNIEnv * env,jobject clazz,jlong paintHandle,jlong typefaceHandle,jstring text,jint start,jint end,jint bidiFlags,jfloatArray widths)629     static jint getTextWidths__StringIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring text,
630             jint start, jint end, jint bidiFlags, jfloatArray widths) {
631         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
632         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
633         const jchar* textArray = env->GetStringChars(text, NULL);
634         int count = dotextwidths(env, paint, typeface, textArray + start, end - start, widths, bidiFlags);
635         env->ReleaseStringChars(text, textArray);
636         return count;
637     }
638 
doTextRunAdvances(JNIEnv * env,Paint * paint,TypefaceImpl * typeface,const jchar * text,jint start,jint count,jint contextCount,jboolean isRtl,jfloatArray advances,jint advancesIndex)639     static jfloat doTextRunAdvances(JNIEnv *env, Paint *paint, TypefaceImpl* typeface, const jchar *text,
640                                     jint start, jint count, jint contextCount, jboolean isRtl,
641                                     jfloatArray advances, jint advancesIndex) {
642         NPE_CHECK_RETURN_ZERO(env, paint);
643         NPE_CHECK_RETURN_ZERO(env, text);
644 
645         if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
646             doThrowAIOOBE(env);
647             return 0;
648         }
649         if (count == 0) {
650             return 0;
651         }
652         if (advances) {
653             size_t advancesLength = env->GetArrayLength(advances);
654             if ((size_t)count > advancesLength) {
655                 doThrowAIOOBE(env);
656                 return 0;
657             }
658         }
659         jfloat* advancesArray = new jfloat[count];
660         jfloat totalAdvance = 0;
661 
662         int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
663 
664         Layout layout;
665         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count, contextCount);
666         layout.getAdvances(advancesArray);
667         totalAdvance = layout.getAdvance();
668 
669         if (advances != NULL) {
670             env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
671         }
672         delete [] advancesArray;
673         return totalAdvance;
674     }
675 
getTextRunAdvances___CIIIIZ_FI(JNIEnv * env,jobject clazz,jlong paintHandle,jlong typefaceHandle,jcharArray text,jint index,jint count,jint contextIndex,jint contextCount,jboolean isRtl,jfloatArray advances,jint advancesIndex)676     static jfloat getTextRunAdvances___CIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
677             jlong typefaceHandle,
678             jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
679             jboolean isRtl, jfloatArray advances, jint advancesIndex) {
680         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
681         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
682         jchar* textArray = env->GetCharArrayElements(text, NULL);
683         jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextIndex,
684                 index - contextIndex, count, contextCount, isRtl, advances, advancesIndex);
685         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
686         return result;
687     }
688 
getTextRunAdvances__StringIIIIZ_FI(JNIEnv * env,jobject clazz,jlong paintHandle,jlong typefaceHandle,jstring text,jint start,jint end,jint contextStart,jint contextEnd,jboolean isRtl,jfloatArray advances,jint advancesIndex)689     static jfloat getTextRunAdvances__StringIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
690             jlong typefaceHandle,
691             jstring text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl,
692             jfloatArray advances, jint advancesIndex) {
693         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
694         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
695         const jchar* textArray = env->GetStringChars(text, NULL);
696         jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextStart,
697                 start - contextStart, end - start, contextEnd - contextStart, isRtl,
698                 advances, advancesIndex);
699         env->ReleaseStringChars(text, textArray);
700         return result;
701     }
702 
doTextRunCursor(JNIEnv * env,Paint * paint,const jchar * text,jint start,jint count,jint flags,jint offset,jint opt)703     static jint doTextRunCursor(JNIEnv *env, Paint* paint, const jchar *text, jint start,
704             jint count, jint flags, jint offset, jint opt) {
705         GraphemeBreak::MoveOpt moveOpt = GraphemeBreak::MoveOpt(opt);
706         size_t result = GraphemeBreak::getTextRunCursor(text, start, count, offset, moveOpt);
707         return static_cast<jint>(result);
708     }
709 
getTextRunCursor___C(JNIEnv * env,jobject clazz,jlong paintHandle,jcharArray text,jint contextStart,jint contextCount,jint dir,jint offset,jint cursorOpt)710     static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text,
711             jint contextStart, jint contextCount, jint dir, jint offset, jint cursorOpt) {
712         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
713         jchar* textArray = env->GetCharArrayElements(text, NULL);
714         jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, dir,
715                 offset, cursorOpt);
716         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
717         return result;
718     }
719 
getTextRunCursor__String(JNIEnv * env,jobject clazz,jlong paintHandle,jstring text,jint contextStart,jint contextEnd,jint dir,jint offset,jint cursorOpt)720     static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text,
721             jint contextStart, jint contextEnd, jint dir, jint offset, jint cursorOpt) {
722         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
723         const jchar* textArray = env->GetStringChars(text, NULL);
724         jint result = doTextRunCursor(env, paint, textArray, contextStart,
725                 contextEnd - contextStart, dir, offset, cursorOpt);
726         env->ReleaseStringChars(text, textArray);
727         return result;
728     }
729 
730     class GetTextFunctor {
731     public:
GetTextFunctor(const Layout & layout,SkPath * path,jfloat x,jfloat y,Paint * paint,uint16_t * glyphs,SkPoint * pos)732         GetTextFunctor(const Layout& layout, SkPath* path, jfloat x, jfloat y, Paint* paint,
733                     uint16_t* glyphs, SkPoint* pos)
734                 : layout(layout), path(path), x(x), y(y), paint(paint), glyphs(glyphs), pos(pos) {
735         }
736 
operator ()(size_t start,size_t end)737         void operator()(size_t start, size_t end) {
738             for (size_t i = start; i < end; i++) {
739                 glyphs[i] = layout.getGlyphId(i);
740                 pos[i].fX = x + layout.getX(i);
741                 pos[i].fY = y + layout.getY(i);
742             }
743             if (start == 0) {
744                 paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, path);
745             } else {
746                 paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, &tmpPath);
747                 path->addPath(tmpPath);
748             }
749         }
750     private:
751         const Layout& layout;
752         SkPath* path;
753         jfloat x;
754         jfloat y;
755         Paint* paint;
756         uint16_t* glyphs;
757         SkPoint* pos;
758         SkPath tmpPath;
759     };
760 
getTextPath(JNIEnv * env,Paint * paint,TypefaceImpl * typeface,const jchar * text,jint count,jint bidiFlags,jfloat x,jfloat y,SkPath * path)761     static void getTextPath(JNIEnv* env, Paint* paint, TypefaceImpl* typeface, const jchar* text,
762             jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
763         Layout layout;
764         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
765         size_t nGlyphs = layout.nGlyphs();
766         uint16_t* glyphs = new uint16_t[nGlyphs];
767         SkPoint* pos = new SkPoint[nGlyphs];
768 
769         x += MinikinUtils::xOffsetForTextAlign(paint, layout);
770         Paint::Align align = paint->getTextAlign();
771         paint->setTextAlign(Paint::kLeft_Align);
772         paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
773         GetTextFunctor f(layout, path, x, y, paint, glyphs, pos);
774         MinikinUtils::forFontRun(layout, paint, f);
775         paint->setTextAlign(align);
776         delete[] glyphs;
777         delete[] pos;
778     }
779 
getTextPath___C(JNIEnv * env,jobject clazz,jlong paintHandle,jlong typefaceHandle,jint bidiFlags,jcharArray text,jint index,jint count,jfloat x,jfloat y,jlong pathHandle)780     static void getTextPath___C(JNIEnv* env, jobject clazz, jlong paintHandle,
781             jlong typefaceHandle, jint bidiFlags,
782             jcharArray text, jint index, jint count, jfloat x, jfloat y, jlong pathHandle) {
783         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
784         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
785         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
786         const jchar* textArray = env->GetCharArrayElements(text, NULL);
787         getTextPath(env, paint, typeface, textArray + index, count, bidiFlags, x, y, path);
788         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
789     }
790 
getTextPath__String(JNIEnv * env,jobject clazz,jlong paintHandle,jlong typefaceHandle,jint bidiFlags,jstring text,jint start,jint end,jfloat x,jfloat y,jlong pathHandle)791     static void getTextPath__String(JNIEnv* env, jobject clazz, jlong paintHandle,
792             jlong typefaceHandle, jint bidiFlags,
793             jstring text, jint start, jint end, jfloat x, jfloat y, jlong pathHandle) {
794         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
795         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
796         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
797         const jchar* textArray = env->GetStringChars(text, NULL);
798         getTextPath(env, paint, typeface, textArray + start, end - start, bidiFlags, x, y, path);
799         env->ReleaseStringChars(text, textArray);
800     }
801 
setShadowLayer(JNIEnv * env,jobject clazz,jlong paintHandle,jfloat radius,jfloat dx,jfloat dy,jint color)802     static void setShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius,
803                                jfloat dx, jfloat dy, jint color) {
804         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
805         if (radius <= 0) {
806             paint->setLooper(NULL);
807         }
808         else {
809             SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
810             paint->setLooper(SkBlurDrawLooper::Create((SkColor)color, sigma, dx, dy))->unref();
811         }
812     }
813 
hasShadowLayer(JNIEnv * env,jobject clazz,jlong paintHandle)814     static jboolean hasShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle) {
815         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
816         return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
817     }
818 
breakText(JNIEnv * env,const Paint & paint,TypefaceImpl * typeface,const jchar text[],int count,float maxWidth,jint bidiFlags,jfloatArray jmeasured,Paint::TextBufferDirection textBufferDirection)819     static int breakText(JNIEnv* env, const Paint& paint, TypefaceImpl* typeface, const jchar text[],
820                          int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
821                          Paint::TextBufferDirection textBufferDirection) {
822         size_t measuredCount = 0;
823         float measured = 0;
824 
825         Layout layout;
826         MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
827         float* advances = new float[count];
828         layout.getAdvances(advances);
829         const bool forwardScan = (textBufferDirection == Paint::kForward_TextBufferDirection);
830         for (int i = 0; i < count; i++) {
831             // traverse in the given direction
832             int index = forwardScan ? i : (count - i - 1);
833             float width = advances[index];
834             if (measured + width > maxWidth) {
835                 break;
836             }
837             // properly handle clusters when scanning backwards
838             if (forwardScan || width != 0.0f) {
839                 measuredCount = i + 1;
840             }
841             measured += width;
842         }
843         delete[] advances;
844 
845         if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
846             AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
847             jfloat* array = autoMeasured.ptr();
848             array[0] = measured;
849         }
850         return measuredCount;
851     }
852 
breakTextC(JNIEnv * env,jobject clazz,jlong paintHandle,jlong typefaceHandle,jcharArray jtext,jint index,jint count,jfloat maxWidth,jint bidiFlags,jfloatArray jmeasuredWidth)853     static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray jtext,
854             jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
855         NPE_CHECK_RETURN_ZERO(env, jtext);
856 
857         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
858         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
859 
860         Paint::TextBufferDirection tbd;
861         if (count < 0) {
862             tbd = Paint::kBackward_TextBufferDirection;
863             count = -count;
864         }
865         else {
866             tbd = Paint::kForward_TextBufferDirection;
867         }
868 
869         if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
870             doThrowAIOOBE(env);
871             return 0;
872         }
873 
874         const jchar* text = env->GetCharArrayElements(jtext, NULL);
875         count = breakText(env, *paint, typeface, text + index, count, maxWidth,
876                           bidiFlags, jmeasuredWidth, tbd);
877         env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
878                                       JNI_ABORT);
879         return count;
880     }
881 
breakTextS(JNIEnv * env,jobject clazz,jlong paintHandle,jlong typefaceHandle,jstring jtext,jboolean forwards,jfloat maxWidth,jint bidiFlags,jfloatArray jmeasuredWidth)882     static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
883                 jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
884         NPE_CHECK_RETURN_ZERO(env, jtext);
885 
886         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
887         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
888 
889         Paint::TextBufferDirection tbd = forwards ?
890                                         Paint::kForward_TextBufferDirection :
891                                         Paint::kBackward_TextBufferDirection;
892 
893         int count = env->GetStringLength(jtext);
894         const jchar* text = env->GetStringChars(jtext, NULL);
895         count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd);
896         env->ReleaseStringChars(jtext, text);
897         return count;
898     }
899 
doTextBounds(JNIEnv * env,const jchar * text,int count,jobject bounds,const Paint & paint,TypefaceImpl * typeface,jint bidiFlags)900     static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds,
901             const Paint& paint, TypefaceImpl* typeface, jint bidiFlags) {
902         SkRect  r;
903         SkIRect ir;
904 
905         Layout layout;
906         MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
907         MinikinRect rect;
908         layout.getBounds(&rect);
909         r.fLeft = rect.mLeft;
910         r.fTop = rect.mTop;
911         r.fRight = rect.mRight;
912         r.fBottom = rect.mBottom;
913         r.roundOut(&ir);
914         GraphicsJNI::irect_to_jrect(ir, env, bounds);
915     }
916 
getStringBounds(JNIEnv * env,jobject,jlong paintHandle,jlong typefaceHandle,jstring text,jint start,jint end,jint bidiFlags,jobject bounds)917     static void getStringBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
918                                 jstring text, jint start, jint end, jint bidiFlags, jobject bounds) {
919         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);;
920         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
921         const jchar* textArray = env->GetStringChars(text, NULL);
922         doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags);
923         env->ReleaseStringChars(text, textArray);
924     }
925 
getCharArrayBounds(JNIEnv * env,jobject,jlong paintHandle,jlong typefaceHandle,jcharArray text,jint index,jint count,jint bidiFlags,jobject bounds)926     static void getCharArrayBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
927                         jcharArray text, jint index, jint count, jint bidiFlags, jobject bounds) {
928         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
929         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
930         const jchar* textArray = env->GetCharArrayElements(text, NULL);
931         doTextBounds(env, textArray + index, count, bounds, *paint, typeface, bidiFlags);
932         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
933                                       JNI_ABORT);
934     }
935 
936 };
937 
938 static JNINativeMethod methods[] = {
939     {"finalizer", "(J)V", (void*) PaintGlue::finalizer},
940     {"native_init","()J", (void*) PaintGlue::init},
941     {"native_initWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
942 
943     {"native_reset","!(J)V", (void*) PaintGlue::reset},
944     {"native_set","!(JJ)V", (void*) PaintGlue::assign},
945     {"getFlags","!()I", (void*) PaintGlue::getFlags},
946     {"setFlags","!(I)V", (void*) PaintGlue::setFlags},
947     {"getHinting","!()I", (void*) PaintGlue::getHinting},
948     {"setHinting","!(I)V", (void*) PaintGlue::setHinting},
949     {"setAntiAlias","!(Z)V", (void*) PaintGlue::setAntiAlias},
950     {"setSubpixelText","!(Z)V", (void*) PaintGlue::setSubpixelText},
951     {"setLinearText","!(Z)V", (void*) PaintGlue::setLinearText},
952     {"setUnderlineText","!(Z)V", (void*) PaintGlue::setUnderlineText},
953     {"setStrikeThruText","!(Z)V", (void*) PaintGlue::setStrikeThruText},
954     {"setFakeBoldText","!(Z)V", (void*) PaintGlue::setFakeBoldText},
955     {"setFilterBitmap","!(Z)V", (void*) PaintGlue::setFilterBitmap},
956     {"setDither","!(Z)V", (void*) PaintGlue::setDither},
957     {"native_getStyle","!(J)I", (void*) PaintGlue::getStyle},
958     {"native_setStyle","!(JI)V", (void*) PaintGlue::setStyle},
959     {"getColor","!()I", (void*) PaintGlue::getColor},
960     {"setColor","!(I)V", (void*) PaintGlue::setColor},
961     {"getAlpha","!()I", (void*) PaintGlue::getAlpha},
962     {"setAlpha","!(I)V", (void*) PaintGlue::setAlpha},
963     {"getStrokeWidth","!()F", (void*) PaintGlue::getStrokeWidth},
964     {"setStrokeWidth","!(F)V", (void*) PaintGlue::setStrokeWidth},
965     {"getStrokeMiter","!()F", (void*) PaintGlue::getStrokeMiter},
966     {"setStrokeMiter","!(F)V", (void*) PaintGlue::setStrokeMiter},
967     {"native_getStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap},
968     {"native_setStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap},
969     {"native_getStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin},
970     {"native_setStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin},
971     {"native_getFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath},
972     {"native_setShader","!(JJ)J", (void*) PaintGlue::setShader},
973     {"native_setColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter},
974     {"native_setXfermode","!(JJ)J", (void*) PaintGlue::setXfermode},
975     {"native_setPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect},
976     {"native_setMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter},
977     {"native_setTypeface","!(JJ)J", (void*) PaintGlue::setTypeface},
978     {"native_setRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer},
979     {"native_getTextAlign","!(J)I", (void*) PaintGlue::getTextAlign},
980     {"native_setTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign},
981     {"native_setTextLocale","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale},
982     {"isElegantTextHeight","!()Z", (void*) PaintGlue::isElegantTextHeight},
983     {"setElegantTextHeight","!(Z)V", (void*) PaintGlue::setElegantTextHeight},
984     {"getTextSize","!()F", (void*) PaintGlue::getTextSize},
985     {"setTextSize","!(F)V", (void*) PaintGlue::setTextSize},
986     {"getTextScaleX","!()F", (void*) PaintGlue::getTextScaleX},
987     {"setTextScaleX","!(F)V", (void*) PaintGlue::setTextScaleX},
988     {"getTextSkewX","!()F", (void*) PaintGlue::getTextSkewX},
989     {"setTextSkewX","!(F)V", (void*) PaintGlue::setTextSkewX},
990     {"native_getLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing},
991     {"native_setLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing},
992     {"native_setFontFeatureSettings","(JLjava/lang/String;)V", (void*) PaintGlue::setFontFeatureSettings},
993     {"ascent","!()F", (void*) PaintGlue::ascent},
994     {"descent","!()F", (void*) PaintGlue::descent},
995 
996     {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)PaintGlue::getFontMetrics},
997     {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)PaintGlue::getFontMetricsInt},
998     {"native_measureText","([CIII)F", (void*) PaintGlue::measureText_CIII},
999     {"native_measureText","(Ljava/lang/String;I)F", (void*) PaintGlue::measureText_StringI},
1000     {"native_measureText","(Ljava/lang/String;III)F", (void*) PaintGlue::measureText_StringIII},
1001     {"native_breakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC},
1002     {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
1003     {"native_getTextWidths","(JJ[CIII[F)I", (void*) PaintGlue::getTextWidths___CIII_F},
1004     {"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) PaintGlue::getTextWidths__StringIII_F},
1005     {"native_getTextRunAdvances","(JJ[CIIIIZ[FI)F",
1006         (void*) PaintGlue::getTextRunAdvances___CIIIIZ_FI},
1007     {"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F",
1008         (void*) PaintGlue::getTextRunAdvances__StringIIIIZ_FI},
1009 
1010     {"native_getTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C},
1011     {"native_getTextRunCursor", "(JLjava/lang/String;IIIII)I",
1012         (void*) PaintGlue::getTextRunCursor__String},
1013     {"native_getTextPath","(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C},
1014     {"native_getTextPath","(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String},
1015     {"nativeGetStringBounds", "(JJLjava/lang/String;IIILandroid/graphics/Rect;)V",
1016                                         (void*) PaintGlue::getStringBounds },
1017     {"nativeGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V",
1018                                     (void*) PaintGlue::getCharArrayBounds },
1019 
1020     {"native_setShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer},
1021     {"native_hasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
1022 };
1023 
req_fieldID(jfieldID id)1024 static jfieldID req_fieldID(jfieldID id) {
1025     SkASSERT(id);
1026     return id;
1027 }
1028 
register_android_graphics_Paint(JNIEnv * env)1029 int register_android_graphics_Paint(JNIEnv* env) {
1030     gFontMetrics_class = env->FindClass("android/graphics/Paint$FontMetrics");
1031     SkASSERT(gFontMetrics_class);
1032     gFontMetrics_class = (jclass)env->NewGlobalRef(gFontMetrics_class);
1033 
1034     gFontMetrics_fieldID.top = req_fieldID(env->GetFieldID(gFontMetrics_class, "top", "F"));
1035     gFontMetrics_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetrics_class, "ascent", "F"));
1036     gFontMetrics_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetrics_class, "descent", "F"));
1037     gFontMetrics_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetrics_class, "bottom", "F"));
1038     gFontMetrics_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetrics_class, "leading", "F"));
1039 
1040     gFontMetricsInt_class = env->FindClass("android/graphics/Paint$FontMetricsInt");
1041     SkASSERT(gFontMetricsInt_class);
1042     gFontMetricsInt_class = (jclass)env->NewGlobalRef(gFontMetricsInt_class);
1043 
1044     gFontMetricsInt_fieldID.top = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "top", "I"));
1045     gFontMetricsInt_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "ascent", "I"));
1046     gFontMetricsInt_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "descent", "I"));
1047     gFontMetricsInt_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "bottom", "I"));
1048     gFontMetricsInt_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "leading", "I"));
1049 
1050     int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Paint", methods,
1051         sizeof(methods) / sizeof(methods[0]));
1052     return result;
1053 }
1054 
1055 }
1056