Paint.cpp revision 775873a66a946fae2b0535abb51df9817bd1b20c
14aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy/* libs/android_runtime/android/graphics/Paint.cpp
24aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy**
34aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy** Copyright 2006, The Android Open Source Project
44aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy**
54aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy** Licensed under the Apache License, Version 2.0 (the "License");
64aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy** you may not use this file except in compliance with the License.
74aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy** You may obtain a copy of the License at
84aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy**
94aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy**     http://www.apache.org/licenses/LICENSE-2.0
104aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy**
114aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy** Unless required by applicable law or agreed to in writing, software
124aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy** distributed under the License is distributed on an "AS IS" BASIS,
134aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy** See the License for the specific language governing permissions and
154aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy** limitations under the License.
164aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy*/
174aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy
184aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy#define LOG_TAG "Paint"
19d5a85fb63d91a9297e8d9a11016f3b3ed60dfbabRomain Guy
20c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <utils/Log.h>
219c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase
226554943a1dd6854c0f4976900956e556767b49e1Romain Guy#include "jni.h"
236554943a1dd6854c0f4976900956e556767b49e1Romain Guy#include "GraphicsJNI.h"
24a35778c799e8073a42b9e22191bde9d838327ab7John Reck#include "core_jni_helpers.h"
25c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik#include <ScopedStringChars.h>
269c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase#include <ScopedUtfChars.h>
272af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
284aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy#include "SkBlurDrawLooper.h"
29113e0824d6bddf4376240681f9cf6a2deded9498John Reck#include "SkColorFilter.h"
3013631f3da855f200a151e7837ed9f6b079622b58Romain Guy#include "SkMaskFilter.h"
314aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy#include "SkPath.h"
324aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy#include "SkRasterizer.h"
334aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy#include "SkShader.h"
34cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik#include "SkTypeface.h"
35984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson#include "SkXfermode.h"
36088c514cb13f3b8f8683588c2f398f18df1547c9John Reck#include "unicode/uloc.h"
378afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik#include "unicode/ushape.h"
38cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik#include "utils/Blur.h"
39cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik
408afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik#include <minikin/GraphemeBreak.h>
41cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik#include <minikin/Measurement.h>
42cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik#include <unicode/utf16.h>
434aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy#include "MinikinSkia.h"
444aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy#include "MinikinUtils.h"
454aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy#include "Paint.h"
4644fd8d24f761f82d21e9b00932648a1b6bf91449John Reck#include "TypefaceImpl.h"
4744fd8d24f761f82d21e9b00932648a1b6bf91449John Reck
484aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy#include <cassert>
494aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy#include <cstring>
5044fd8d24f761f82d21e9b00932648a1b6bf91449John Reck#include <memory>
5144fd8d24f761f82d21e9b00932648a1b6bf91449John Reck#include <vector>
5244fd8d24f761f82d21e9b00932648a1b6bf91449John Reck
53d34dd71800d9a1077e58c3b7f2511c46848da417Chet Haasenamespace android {
5444fd8d24f761f82d21e9b00932648a1b6bf91449John Reck
5543ccf4663c822ddd435b7683cc05221f6169c6c3Romain Guystruct JMetricsID {
56735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy    jfieldID    top;
572fc941e4650d618ff6e122f28b616d9032ffa134Romain Guy    jfieldID    ascent;
5844fd8d24f761f82d21e9b00932648a1b6bf91449John Reck    jfieldID    descent;
5944fd8d24f761f82d21e9b00932648a1b6bf91449John Reck    jfieldID    bottom;
6044fd8d24f761f82d21e9b00932648a1b6bf91449John Reck    jfieldID    leading;
615977baa1fa24125c148a72699b53e62abaf08960Chet Haase};
625977baa1fa24125c148a72699b53e62abaf08960Chet Haase
63107843de4507b3511006cb9c77b8d0364374385aTom Hudsonstatic jclass   gFontMetrics_class;
647d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guystatic JMetricsID gFontMetrics_fieldID;
6544fd8d24f761f82d21e9b00932648a1b6bf91449John Reck
6644fd8d24f761f82d21e9b00932648a1b6bf91449John Reckstatic jclass   gFontMetricsInt_class;
6744fd8d24f761f82d21e9b00932648a1b6bf91449John Reckstatic JMetricsID gFontMetricsInt_fieldID;
6844fd8d24f761f82d21e9b00932648a1b6bf91449John Reck
6944fd8d24f761f82d21e9b00932648a1b6bf91449John Reckstatic void defaultSettingsForAndroid(Paint* paint) {
70984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    // GlyphID encoding is required because we are using Harfbuzz shaping
7145e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy    paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
728afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik}
73984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
7427454a42de8b3c54cdd3b2b2a12446c2c10c8cb9Romain Guynamespace PaintGlue {
7527454a42de8b3c54cdd3b2b2a12446c2c10c8cb9Romain Guy    enum MoveOpt {
7627454a42de8b3c54cdd3b2b2a12446c2c10c8cb9Romain Guy        AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT
77107843de4507b3511006cb9c77b8d0364374385aTom Hudson    };
788afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik
798afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik    static void deletePaint(Paint* paint) {
80107843de4507b3511006cb9c77b8d0364374385aTom Hudson        delete paint;
81b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    }
82b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy
83daf98e941e140e8739458126640183b9f296a2abChet Haase    static jlong getNativeFinalizer(JNIEnv*, jobject) {
84daf98e941e140e8739458126640183b9f296a2abChet Haase        return static_cast<jlong>(reinterpret_cast<uintptr_t>(&deletePaint));
85daf98e941e140e8739458126640183b9f296a2abChet Haase    }
862b1847ea60650a9f68372abe860415f18b55081dRomain Guy
874aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy    static jlong init(JNIEnv* env, jobject) {
884aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        static_assert(1 <<  0 == SkPaint::kAntiAlias_Flag,          "paint_flags_mismatch");
89107843de4507b3511006cb9c77b8d0364374385aTom Hudson        static_assert(1 <<  2 == SkPaint::kDither_Flag,             "paint_flags_mismatch");
90cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy        static_assert(1 <<  3 == SkPaint::kUnderlineText_Flag,      "paint_flags_mismatch");
912af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        static_assert(1 <<  4 == SkPaint::kStrikeThruText_Flag,     "paint_flags_mismatch");
9209d5cddf67b676018700bcc10a72242641cd7eecJohn Reck        static_assert(1 <<  5 == SkPaint::kFakeBoldText_Flag,       "paint_flags_mismatch");
93daf98e941e140e8739458126640183b9f296a2abChet Haase        static_assert(1 <<  6 == SkPaint::kLinearText_Flag,         "paint_flags_mismatch");
94daf98e941e140e8739458126640183b9f296a2abChet Haase        static_assert(1 <<  7 == SkPaint::kSubpixelText_Flag,       "paint_flags_mismatch");
954aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        static_assert(1 <<  8 == SkPaint::kDevKernText_Flag,        "paint_flags_mismatch");
962af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        static_assert(1 << 10 == SkPaint::kEmbeddedBitmapText_Flag, "paint_flags_mismatch");
97984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
984aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        Paint* obj = new Paint();
994aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        defaultSettingsForAndroid(obj);
1004aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        return reinterpret_cast<jlong>(obj);
10104c9d8c2ffd028c35c750bac0a4a7b79e48059b5Romain Guy    }
10233f6beb10f98e8ba96250e284876d607055d278dRomain Guy
10333f6beb10f98e8ba96250e284876d607055d278dRomain Guy    static jlong initWithPaint(JNIEnv* env, jobject clazz, jlong paintHandle) {
10404c9d8c2ffd028c35c750bac0a4a7b79e48059b5Romain Guy        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
10533f6beb10f98e8ba96250e284876d607055d278dRomain Guy        Paint* obj = new Paint(*paint);
10633f6beb10f98e8ba96250e284876d607055d278dRomain Guy        return reinterpret_cast<jlong>(obj);
1078afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik    }
108984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
1094aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy    static void reset(JNIEnv* env, jobject clazz, jlong objHandle) {
1104aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        Paint* obj = reinterpret_cast<Paint*>(objHandle);
1114aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        obj->reset();
11227454a42de8b3c54cdd3b2b2a12446c2c10c8cb9Romain Guy        defaultSettingsForAndroid(obj);
1138afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik    }
114984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
1154aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy    static void assign(JNIEnv* env, jobject clazz, jlong dstPaintHandle, jlong srcPaintHandle) {
1164aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        Paint* dst = reinterpret_cast<Paint*>(dstPaintHandle);
1174aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        const Paint* src = reinterpret_cast<Paint*>(srcPaintHandle);
118d44fbe55a9f434cb5bb0e34c143ba1445141990dDerek Sollenberger        *dst = *src;
1194ace7305608442ab35ea9aa65a4220df152c187fChris Craik    }
1204ace7305608442ab35ea9aa65a4220df152c187fChris Craik
1214ace7305608442ab35ea9aa65a4220df152c187fChris Craik    // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
122d44fbe55a9f434cb5bb0e34c143ba1445141990dDerek Sollenberger    static const uint32_t sFilterBitmapFlag = 0x02;
123d44fbe55a9f434cb5bb0e34c143ba1445141990dDerek Sollenberger
124984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    static jint getFlags(JNIEnv* env, jobject, jlong paintHandle) {
1255b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
1265b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        uint32_t result = nativePaint->getFlags();
127b458942bb6e6cf13c68341dda35ef5cee060f5aeChris Craik        result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
128b458942bb6e6cf13c68341dda35ef5cee060f5aeChris Craik        if (nativePaint->getFilterQuality() != kNone_SkFilterQuality) {
1298afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            result |= sFilterBitmapFlag;
13033f6beb10f98e8ba96250e284876d607055d278dRomain Guy        }
13133f6beb10f98e8ba96250e284876d607055d278dRomain Guy        return static_cast<jint>(result);
1328afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik    }
133984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
1344aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy    static void setFlags(JNIEnv* env, jobject, jlong paintHandle, jint flags) {
1354aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
1364aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        // Instead of modifying 0x02, change the filter level.
1372af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        nativePaint->setFilterQuality(flags & sFilterBitmapFlag
138984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson                ? kLow_SkFilterQuality
1394aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy                : kNone_SkFilterQuality);
1404aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        // Don't pass through filter flag, which is no longer stored in paint's flags.
1414aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        flags &= ~sFilterBitmapFlag;
1422af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        // Use the existing value for 0x02.
143984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        const uint32_t existing0x02Flag = nativePaint->getFlags() & sFilterBitmapFlag;
1444aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        flags |= existing0x02Flag;
1454aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        nativePaint->setFlags(flags);
146807daf7df615b60ce6fc41355aabe3aa353cebabRomain Guy    }
1472af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
148984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    static jint getHinting(JNIEnv* env, jobject, jlong paintHandle) {
149807daf7df615b60ce6fc41355aabe3aa353cebabRomain Guy        return reinterpret_cast<Paint*>(paintHandle)->getHinting()
150807daf7df615b60ce6fc41355aabe3aa353cebabRomain Guy                == Paint::kNo_Hinting ? 0 : 1;
151139088228faa7f3c446af7387e017933998a5570Derek Sollenberger    }
1522af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
153984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    static void setHinting(JNIEnv* env, jobject, jlong paintHandle, jint mode) {
1544aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        reinterpret_cast<Paint*>(paintHandle)->setHinting(
1554aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy                mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
156139088228faa7f3c446af7387e017933998a5570Derek Sollenberger    }
1572af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
158984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    static void setAntiAlias(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) {
1594aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        reinterpret_cast<Paint*>(paintHandle)->setAntiAlias(aa);
1604aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy    }
1614aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy
1624aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy    static void setLinearText(JNIEnv* env, jobject, jlong paintHandle, jboolean linearText) {
1632af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        reinterpret_cast<Paint*>(paintHandle)->setLinearText(linearText);
164984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    }
1654aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy
1664aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy    static void setSubpixelText(JNIEnv* env, jobject, jlong paintHandle, jboolean subpixelText) {
167d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        reinterpret_cast<Paint*>(paintHandle)->setSubpixelText(subpixelText);
1682af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
1692af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
170984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    static void setUnderlineText(JNIEnv* env, jobject, jlong paintHandle, jboolean underlineText) {
171735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy        reinterpret_cast<Paint*>(paintHandle)->setUnderlineText(underlineText);
172735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy    }
173d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik
1742af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static void setStrikeThruText(JNIEnv* env, jobject, jlong paintHandle, jboolean strikeThruText) {
1752af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        reinterpret_cast<Paint*>(paintHandle)->setStrikeThruText(strikeThruText);
176984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    }
177735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy
178735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy    static void setFakeBoldText(JNIEnv* env, jobject, jlong paintHandle, jboolean fakeBoldText) {
179107843de4507b3511006cb9c77b8d0364374385aTom Hudson        reinterpret_cast<Paint*>(paintHandle)->setFakeBoldText(fakeBoldText);
1808afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik    }
1818afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik
182cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy    static void setFilterBitmap(JNIEnv* env, jobject, jlong paintHandle, jboolean filterBitmap) {
183cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy        reinterpret_cast<Paint*>(paintHandle)->setFilterQuality(
184984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson                filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality);
1858afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik    }
1860fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy
1870fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy    static void setDither(JNIEnv* env, jobject, jlong paintHandle, jboolean dither) {
188107843de4507b3511006cb9c77b8d0364374385aTom Hudson        reinterpret_cast<Paint*>(paintHandle)->setDither(dither);
1890e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck    }
190a08f95cfeca7217f9c533b03663bf0dceedd259aChris Craik
1916c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    static jint getStyle(JNIEnv* env, jobject clazz,jlong objHandle) {
1926c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        Paint* obj = reinterpret_cast<Paint*>(objHandle);
193107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return static_cast<jint>(obj->getStyle());
1942af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
1952af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
1962af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static void setStyle(JNIEnv* env, jobject clazz, jlong objHandle, jint styleHandle) {
197796475006f5d670e8383a2050f11719522437a43Chris Craik        Paint* obj = reinterpret_cast<Paint*>(objHandle);
1984aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        Paint::Style style = static_cast<Paint::Style>(styleHandle);
1994aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        obj->setStyle(style);
200107843de4507b3511006cb9c77b8d0364374385aTom Hudson    }
2014aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy
202d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik    static jint getColor(JNIEnv* env, jobject, jlong paintHandle) {
203796475006f5d670e8383a2050f11719522437a43Chris Craik        int color;
204796475006f5d670e8383a2050f11719522437a43Chris Craik        color = reinterpret_cast<Paint*>(paintHandle)->getColor();
205796475006f5d670e8383a2050f11719522437a43Chris Craik        return static_cast<jint>(color);
206796475006f5d670e8383a2050f11719522437a43Chris Craik    }
207527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
208796475006f5d670e8383a2050f11719522437a43Chris Craik    static jint getAlpha(JNIEnv* env, jobject, jlong paintHandle) {
209796475006f5d670e8383a2050f11719522437a43Chris Craik        int alpha;
210796475006f5d670e8383a2050f11719522437a43Chris Craik        alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha();
211796475006f5d670e8383a2050f11719522437a43Chris Craik        return static_cast<jint>(alpha);
212796475006f5d670e8383a2050f11719522437a43Chris Craik    }
213796475006f5d670e8383a2050f11719522437a43Chris Craik
214796475006f5d670e8383a2050f11719522437a43Chris Craik    static void setColor(JNIEnv* env, jobject, jlong paintHandle, jint color) {
215796475006f5d670e8383a2050f11719522437a43Chris Craik        reinterpret_cast<Paint*>(paintHandle)->setColor(color);
216796475006f5d670e8383a2050f11719522437a43Chris Craik    }
217796475006f5d670e8383a2050f11719522437a43Chris Craik
218796475006f5d670e8383a2050f11719522437a43Chris Craik    static void setAlpha(JNIEnv* env, jobject, jlong paintHandle, jint a) {
219527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik        reinterpret_cast<Paint*>(paintHandle)->setAlpha(a);
2204aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy    }
2214aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy
222107843de4507b3511006cb9c77b8d0364374385aTom Hudson    static jfloat getStrokeWidth(JNIEnv* env, jobject, jlong paintHandle) {
2232af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeWidth());
2242af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
2252af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
226796475006f5d670e8383a2050f11719522437a43Chris Craik    static void setStrokeWidth(JNIEnv* env, jobject, jlong paintHandle, jfloat width) {
227e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy        reinterpret_cast<Paint*>(paintHandle)->setStrokeWidth(width);
228e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy    }
229107843de4507b3511006cb9c77b8d0364374385aTom Hudson
230d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik    static jfloat getStrokeMiter(JNIEnv* env, jobject, jlong paintHandle) {
2310664fef9e2a36025b3fad85b57b4d10617b4d66eChris Craik        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeMiter());
2322af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
2330664fef9e2a36025b3fad85b57b4d10617b4d66eChris Craik
2342af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static void setStrokeMiter(JNIEnv* env, jobject, jlong paintHandle, jfloat miter) {
2350664fef9e2a36025b3fad85b57b4d10617b4d66eChris Craik        reinterpret_cast<Paint*>(paintHandle)->setStrokeMiter(miter);
2362af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
2372af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
2382af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static jint getStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle) {
2395a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        Paint* obj = reinterpret_cast<Paint*>(objHandle);
2405a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        return static_cast<jint>(obj->getStrokeCap());
241107843de4507b3511006cb9c77b8d0364374385aTom Hudson    }
242d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik
2432af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static void setStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle, jint capHandle) {
244e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        Paint* obj = reinterpret_cast<Paint*>(objHandle);
24516ea8d373b03b1e115dd505af70dbee4e3a3a182Romain Guy        Paint::Cap cap = static_cast<Paint::Cap>(capHandle);
2462af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        obj->setStrokeCap(cap);
24703c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy    }
2484aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy
2494aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy    static jint getStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle) {
250107843de4507b3511006cb9c77b8d0364374385aTom Hudson        Paint* obj = reinterpret_cast<Paint*>(objHandle);
2512af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        return static_cast<jint>(obj->getStrokeJoin());
2524aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy    }
2534aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy
254107843de4507b3511006cb9c77b8d0364374385aTom Hudson    static void setStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle, jint joinHandle) {
255d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        Paint* obj = reinterpret_cast<Paint*>(objHandle);
2562af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        Paint::Join join = (Paint::Join) joinHandle;
2572af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        obj->setStrokeJoin(join);
2584aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy    }
2594aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy
260107843de4507b3511006cb9c77b8d0364374385aTom Hudson    static jboolean getFillPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong dstHandle) {
261d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        Paint* obj = reinterpret_cast<Paint*>(objHandle);
2622af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
2632af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
26401d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
26501d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    }
266107843de4507b3511006cb9c77b8d0364374385aTom Hudson
267072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    static jlong setShader(JNIEnv* env, jobject clazz, jlong objHandle, jlong shaderHandle) {
268072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        Paint* obj = reinterpret_cast<Paint*>(objHandle);
269072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
270072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        return reinterpret_cast<jlong>(obj->setShader(shader));
2710e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck    }
2720e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck
2730e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck    static jlong setColorFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong filterHandle) {
2740e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck        Paint* obj = reinterpret_cast<Paint *>(objHandle);
2750e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck        SkColorFilter* filter  = reinterpret_cast<SkColorFilter *>(filterHandle);
2760e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck        return reinterpret_cast<jlong>(obj->setColorFilter(filter));
2770e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck    }
278072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi
279072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi    static jlong setXfermode(JNIEnv* env, jobject clazz, jlong objHandle, jlong xfermodeHandle) {
280072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        Paint* obj = reinterpret_cast<Paint*>(objHandle);
281072707dfad1da6f49f4d3ce58ca104f6c46a7266Jorim Jaggi        SkXfermode* xfermode = reinterpret_cast<SkXfermode*>(xfermodeHandle);
282107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return reinterpret_cast<jlong>(obj->setXfermode(xfermode));
2832af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
2842af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
28501d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    static jlong setPathEffect(JNIEnv* env, jobject clazz, jlong objHandle, jlong effectHandle) {
28601d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        Paint* obj = reinterpret_cast<Paint*>(objHandle);
287107843de4507b3511006cb9c77b8d0364374385aTom Hudson        SkPathEffect* effect  = reinterpret_cast<SkPathEffect*>(effectHandle);
28852244fff29042926e21fa897ef5ab11148e35299John Reck        return reinterpret_cast<jlong>(obj->setPathEffect(effect));
2890e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck    }
2900e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck
2910e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck    static jlong setMaskFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong maskfilterHandle) {
2920e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck        Paint* obj = reinterpret_cast<Paint*>(objHandle);
29352244fff29042926e21fa897ef5ab11148e35299John Reck        SkMaskFilter* maskfilter  = reinterpret_cast<SkMaskFilter*>(maskfilterHandle);
29452244fff29042926e21fa897ef5ab11148e35299John Reck        return reinterpret_cast<jlong>(obj->setMaskFilter(maskfilter));
29552244fff29042926e21fa897ef5ab11148e35299John Reck    }
29652244fff29042926e21fa897ef5ab11148e35299John Reck
297107843de4507b3511006cb9c77b8d0364374385aTom Hudson    static jlong setTypeface(JNIEnv* env, jobject clazz, jlong objHandle, jlong typefaceHandle) {
298d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        // TODO: in Paint refactoring, set typeface on android Paint, not Paint
2992af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        return NULL;
3002af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
301c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy
302c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy    static jlong setRasterizer(JNIEnv* env, jobject clazz, jlong objHandle, jlong rasterizerHandle) {
303107843de4507b3511006cb9c77b8d0364374385aTom Hudson        Paint* obj = reinterpret_cast<Paint*>(objHandle);
304d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        SkAutoTUnref<SkRasterizer> rasterizer(GraphicsJNI::refNativeRasterizer(rasterizerHandle));
305544e524db6e4da526af1c897fe5314036ede5012Chris Craik        return reinterpret_cast<jlong>(obj->setRasterizer(rasterizer));
306107843de4507b3511006cb9c77b8d0364374385aTom Hudson    }
307107843de4507b3511006cb9c77b8d0364374385aTom Hudson
308107843de4507b3511006cb9c77b8d0364374385aTom Hudson    static jint getTextAlign(JNIEnv* env, jobject clazz, jlong objHandle) {
309107843de4507b3511006cb9c77b8d0364374385aTom Hudson        Paint* obj = reinterpret_cast<Paint*>(objHandle);
310107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return static_cast<jint>(obj->getTextAlign());
3116ac174b97246ed40fe780b29561603b61770fa17Chris Craik    }
3128b2f5267f16c295f12faab810527cd6311997e34Romain Guy
3138b2f5267f16c295f12faab810527cd6311997e34Romain Guy    static void setTextAlign(JNIEnv* env, jobject clazz, jlong objHandle, jint alignHandle) {
314107843de4507b3511006cb9c77b8d0364374385aTom Hudson        Paint* obj = reinterpret_cast<Paint*>(objHandle);
3152af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        Paint::Align align = static_cast<Paint::Align>(alignHandle);
3162af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        obj->setTextAlign(align);
3172af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
3182af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
3194aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy    static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
3204aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        Paint* obj = reinterpret_cast<Paint*>(objHandle);
321107843de4507b3511006cb9c77b8d0364374385aTom Hudson        ScopedUtfChars localesChars(env, locales);
3222af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        jint minikinLangListId = FontStyle::registerLanguageList(localesChars.c_str());
3232af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        obj->setMinikinLangListId(minikinLangListId);
3242af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        return minikinLangListId;
3252af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
326ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy
327ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy    static void setTextLocalesByMinikinLangListId(JNIEnv* env, jobject clazz, jlong objHandle,
328107843de4507b3511006cb9c77b8d0364374385aTom Hudson            jint minikinLangListId) {
3292af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        Paint* obj = reinterpret_cast<Paint*>(objHandle);
3302af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        obj->setMinikinLangListId(minikinLangListId);
3312af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
3322af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
3334aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy    static jboolean isElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle) {
3344aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        Paint* obj = reinterpret_cast<Paint*>(paintHandle);
335107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return obj->getFontVariant() == VARIANT_ELEGANT;
336d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik    }
337107843de4507b3511006cb9c77b8d0364374385aTom Hudson
3382af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static void setElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) {
3392af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        Paint* obj = reinterpret_cast<Paint*>(paintHandle);
3402af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        obj->setFontVariant(aa ? VARIANT_ELEGANT : VARIANT_DEFAULT);
3412af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
3422af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
3432af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static jfloat getTextSize(JNIEnv* env, jobject, jlong paintHandle) {
3442af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSize());
3450f6675332c04c74909425d1d328f02b32c0ff40eRomain Guy    }
346996e57c84368058be793897ebc355b917a59abc2Raph Levien
347996e57c84368058be793897ebc355b917a59abc2Raph Levien    static void setTextSize(JNIEnv* env, jobject, jlong paintHandle, jfloat textSize) {
348107843de4507b3511006cb9c77b8d0364374385aTom Hudson        reinterpret_cast<Paint*>(paintHandle)->setTextSize(textSize);
349d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik    }
350107843de4507b3511006cb9c77b8d0364374385aTom Hudson
3512af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static jfloat getTextScaleX(JNIEnv* env, jobject, jlong paintHandle) {
3522af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextScaleX());
3532af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
3542af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
3552af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static void setTextScaleX(JNIEnv* env, jobject, jlong paintHandle, jfloat scaleX) {
3562af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        reinterpret_cast<Paint*>(paintHandle)->setTextScaleX(scaleX);
3570f6675332c04c74909425d1d328f02b32c0ff40eRomain Guy    }
358996e57c84368058be793897ebc355b917a59abc2Raph Levien
359996e57c84368058be793897ebc355b917a59abc2Raph Levien    static jfloat getTextSkewX(JNIEnv* env, jobject, jlong paintHandle) {
360cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSkewX());
361cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik    }
362cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik
363cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik    static void setTextSkewX(JNIEnv* env, jobject, jlong paintHandle, jfloat skewX) {
364cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        reinterpret_cast<Paint*>(paintHandle)->setTextSkewX(skewX);
365cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik    }
366cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik
367cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik    static jfloat getLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle) {
368cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
369cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        return paint->getLetterSpacing();
370107843de4507b3511006cb9c77b8d0364374385aTom Hudson    }
371d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik
37241541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik    static void setLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat letterSpacing) {
373527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
374107843de4507b3511006cb9c77b8d0364374385aTom Hudson        paint->setLetterSpacing(letterSpacing);
37533f6beb10f98e8ba96250e284876d607055d278dRomain Guy    }
3762af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
3772af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
37833f6beb10f98e8ba96250e284876d607055d278dRomain Guy        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
379cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        if (!settings) {
380cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik            paint->setFontFeatureSettings(std::string());
381cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        } else {
382cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik            ScopedUtfChars settingsChars(env, settings);
383cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik            paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
384cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        }
385cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik    }
386cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik
387cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik    static jint getHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) {
388cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
389cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        return paint->getHyphenEdit();
390cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik    }
391cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik
392cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik    static void setHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) {
393cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
394cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        paint->setHyphenEdit((uint32_t)hyphen);
395cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik    }
396cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik
397cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik    static SkScalar getMetricsInternal(jlong paintHandle, jlong typefaceHandle,
398cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik            Paint::FontMetrics *metrics) {
399cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        const int kElegantTop = 2500;
400cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        const int kElegantBottom = -1000;
401cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        const int kElegantAscent = 1900;
402cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        const int kElegantDescent = -500;
403cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        const int kElegantLeading = 0;
404cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
405cce47eb580d666ead1f6095d1e3b65233592bbaaChris Craik        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
406672433d90fab7383cd28beac9d4485b566a90940Romain Guy        typeface = TypefaceImpl_resolveDefault(typeface);
407672433d90fab7383cd28beac9d4485b566a90940Romain Guy        FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
408107843de4507b3511006cb9c77b8d0364374385aTom Hudson        float saveSkewX = paint->getTextSkewX();
409107843de4507b3511006cb9c77b8d0364374385aTom Hudson        bool savefakeBold = paint->isFakeBoldText();
410672433d90fab7383cd28beac9d4485b566a90940Romain Guy        MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
4112af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        SkScalar spacing = paint->getFontMetrics(metrics);
4122af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        // The populateSkPaint call may have changed fake bold / text skew
4132af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        // because we want to measure with those effects applied, so now
414eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        // restore the original settings.
415eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        paint->setTextSkewX(saveSkewX);
41609c2d4fe15fbac2faf8a97ba2cc59132ee12222aDerek Sollenberger        paint->setFakeBoldText(savefakeBold);
41709c2d4fe15fbac2faf8a97ba2cc59132ee12222aDerek Sollenberger        if (paint->getFontVariant() == VARIANT_ELEGANT) {
4182af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik            SkScalar size = paint->getTextSize();
4192af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik            metrics->fTop = -size * kElegantTop / 2048;
4208afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            metrics->fBottom = -size * kElegantBottom / 2048;
4218afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            metrics->fAscent = -size * kElegantAscent / 2048;
4228afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            metrics->fDescent = -size * kElegantDescent / 2048;
4238afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            metrics->fLeading = size * kElegantLeading / 2048;
4248afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
4258afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        }
4268afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        return spacing;
4272af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
4288afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik
4292af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static jfloat ascent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) {
4302af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        Paint::FontMetrics metrics;
4312af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
4322af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        return SkScalarToFloat(metrics.fAscent);
4338afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik    }
4348afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik
4352af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static jfloat descent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) {
4368afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        Paint::FontMetrics metrics;
4372af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
4382af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        return SkScalarToFloat(metrics.fDescent);
4398afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik    }
4402af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
4412af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle,
4422af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik            jlong typefaceHandle, jobject metricsObj) {
4438afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        Paint::FontMetrics metrics;
4448afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        SkScalar spacing = getMetricsInternal(paintHandle, typefaceHandle, &metrics);
4458afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik
4468afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        if (metricsObj) {
4478afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
4488afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
4498afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
4508afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
4518afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
4528afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
4538afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        }
4548afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        return SkScalarToFloat(spacing);
4558afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik    }
4568afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik
4578afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik    static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle,
4588afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            jlong typefaceHandle, jobject metricsObj) {
4598afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        Paint::FontMetrics metrics;
4608afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik
4612af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
4622af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        int ascent = SkScalarRoundToInt(metrics.fAscent);
4638afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        int descent = SkScalarRoundToInt(metrics.fDescent);
4648afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        int leading = SkScalarRoundToInt(metrics.fLeading);
4658afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik
4668afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        if (metricsObj) {
4678afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
4688afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
4698afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
4708afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
4718afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
4728afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
4738afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        }
4742af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        return descent - ascent + leading;
4753b20251a355c88193c439f928a84ae69483fb488John Reck    }
476f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik
4772af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    static jfloat doTextAdvances(JNIEnv *env, Paint *paint, TypefaceImpl* typeface,
4782af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik            const jchar *text, jint start, jint count, jint contextCount, jint bidiFlags,
4792af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik            jfloatArray advances, jint advancesIndex) {
480c1c5f0870282b56dafe5a4d756e4b9e6884655a7Chris Craik        NPE_CHECK_RETURN_ZERO(env, text);
48144fd8d24f761f82d21e9b00932648a1b6bf91449John Reck
4828afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
4838afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            doThrowAIOOBE(env);
4848afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            return 0;
4858afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        }
4868afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        if (count == 0) {
4878afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            return 0;
4888afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        }
4898afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        if (advances) {
4908afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            size_t advancesLength = env->GetArrayLength(advances);
4918afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            if ((size_t)(count  + advancesIndex) > advancesLength) {
4928afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik                doThrowAIOOBE(env);
4938afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik                return 0;
4948afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik            }
4958afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        }
4968afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik
4978afd0f245cc0c4a0366f39f41b5f78e47ee83be3Chris Craik        Layout layout;
4985ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count,
4995ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy                contextCount);
5004aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy        if (advances != NULL) {
5014aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy            std::unique_ptr<jfloat> advancesArray(new jfloat[count]);
502            layout.getAdvances(advancesArray.get());
503            env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray.get());
504        }
505        return layout.getAdvance();
506    }
507
508    static jfloat getTextAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
509            jlong typefaceHandle,
510            jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
511            jint bidiFlags, jfloatArray advances, jint advancesIndex) {
512        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
513        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
514        jchar* textArray = env->GetCharArrayElements(text, NULL);
515        jfloat result = doTextAdvances(env, paint, typeface, textArray + contextIndex,
516                index - contextIndex, count, contextCount, bidiFlags, advances, advancesIndex);
517        env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
518        return result;
519    }
520
521    static jfloat getTextAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
522            jlong typefaceHandle,
523            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint bidiFlags,
524            jfloatArray advances, jint advancesIndex) {
525        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
526        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
527        const jchar* textArray = env->GetStringChars(text, NULL);
528        jfloat result = doTextAdvances(env, paint, typeface, textArray + contextStart,
529                start - contextStart, end - start, contextEnd - contextStart, bidiFlags,
530                advances, advancesIndex);
531        env->ReleaseStringChars(text, textArray);
532        return result;
533    }
534
535    static jint doTextRunCursor(JNIEnv *env, Paint* paint, const jchar *text, jint start,
536            jint count, jint flags, jint offset, jint opt) {
537        GraphemeBreak::MoveOpt moveOpt = GraphemeBreak::MoveOpt(opt);
538        size_t result = GraphemeBreak::getTextRunCursor(text, start, count, offset, moveOpt);
539        return static_cast<jint>(result);
540    }
541
542    static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text,
543            jint contextStart, jint contextCount, jint dir, jint offset, jint cursorOpt) {
544        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
545        jchar* textArray = env->GetCharArrayElements(text, NULL);
546        jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, dir,
547                offset, cursorOpt);
548        env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
549        return result;
550    }
551
552    static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text,
553            jint contextStart, jint contextEnd, jint dir, jint offset, jint cursorOpt) {
554        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
555        const jchar* textArray = env->GetStringChars(text, NULL);
556        jint result = doTextRunCursor(env, paint, textArray, contextStart,
557                contextEnd - contextStart, dir, offset, cursorOpt);
558        env->ReleaseStringChars(text, textArray);
559        return result;
560    }
561
562    class GetTextFunctor {
563    public:
564        GetTextFunctor(const Layout& layout, SkPath* path, jfloat x, jfloat y, Paint* paint,
565                    uint16_t* glyphs, SkPoint* pos)
566                : layout(layout), path(path), x(x), y(y), paint(paint), glyphs(glyphs), pos(pos) {
567        }
568
569        void operator()(size_t start, size_t end) {
570            for (size_t i = start; i < end; i++) {
571                glyphs[i] = layout.getGlyphId(i);
572                pos[i].fX = x + layout.getX(i);
573                pos[i].fY = y + layout.getY(i);
574            }
575            if (start == 0) {
576                paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, path);
577            } else {
578                paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, &tmpPath);
579                path->addPath(tmpPath);
580            }
581        }
582    private:
583        const Layout& layout;
584        SkPath* path;
585        jfloat x;
586        jfloat y;
587        Paint* paint;
588        uint16_t* glyphs;
589        SkPoint* pos;
590        SkPath tmpPath;
591    };
592
593    static void getTextPath(JNIEnv* env, Paint* paint, TypefaceImpl* typeface, const jchar* text,
594            jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
595        Layout layout;
596        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
597        size_t nGlyphs = layout.nGlyphs();
598        uint16_t* glyphs = new uint16_t[nGlyphs];
599        SkPoint* pos = new SkPoint[nGlyphs];
600
601        x += MinikinUtils::xOffsetForTextAlign(paint, layout);
602        Paint::Align align = paint->getTextAlign();
603        paint->setTextAlign(Paint::kLeft_Align);
604        paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
605        GetTextFunctor f(layout, path, x, y, paint, glyphs, pos);
606        MinikinUtils::forFontRun(layout, paint, f);
607        paint->setTextAlign(align);
608        delete[] glyphs;
609        delete[] pos;
610    }
611
612    static void getTextPath___C(JNIEnv* env, jobject clazz, jlong paintHandle,
613            jlong typefaceHandle, jint bidiFlags,
614            jcharArray text, jint index, jint count, jfloat x, jfloat y, jlong pathHandle) {
615        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
616        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
617        SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
618        const jchar* textArray = env->GetCharArrayElements(text, NULL);
619        getTextPath(env, paint, typeface, textArray + index, count, bidiFlags, x, y, path);
620        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
621    }
622
623    static void getTextPath__String(JNIEnv* env, jobject clazz, jlong paintHandle,
624            jlong typefaceHandle, jint bidiFlags,
625            jstring text, jint start, jint end, jfloat x, jfloat y, jlong pathHandle) {
626        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
627        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
628        SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
629        const jchar* textArray = env->GetStringChars(text, NULL);
630        getTextPath(env, paint, typeface, textArray + start, end - start, bidiFlags, x, y, path);
631        env->ReleaseStringChars(text, textArray);
632    }
633
634    static void setShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius,
635                               jfloat dx, jfloat dy, jint color) {
636        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
637        if (radius <= 0) {
638            paint->setLooper(NULL);
639        }
640        else {
641            SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
642            paint->setLooper(SkBlurDrawLooper::Create((SkColor)color, sigma, dx, dy))->unref();
643        }
644    }
645
646    static jboolean hasShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle) {
647        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
648        return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
649    }
650
651    static int breakText(JNIEnv* env, const Paint& paint, TypefaceImpl* typeface, const jchar text[],
652                         int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
653                         const bool forwardScan) {
654        size_t measuredCount = 0;
655        float measured = 0;
656
657        Layout layout;
658        MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
659        float* advances = new float[count];
660        layout.getAdvances(advances);
661
662        for (int i = 0; i < count; i++) {
663            // traverse in the given direction
664            int index = forwardScan ? i : (count - i - 1);
665            float width = advances[index];
666            if (measured + width > maxWidth) {
667                break;
668            }
669            // properly handle clusters when scanning backwards
670            if (forwardScan || width != 0.0f) {
671                measuredCount = i + 1;
672            }
673            measured += width;
674        }
675        delete[] advances;
676
677        if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
678            AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
679            jfloat* array = autoMeasured.ptr();
680            array[0] = measured;
681        }
682        return measuredCount;
683    }
684
685    static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray jtext,
686            jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
687        NPE_CHECK_RETURN_ZERO(env, jtext);
688
689        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
690        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
691
692        bool forwardTextDirection;
693        if (count < 0) {
694            forwardTextDirection = false;
695            count = -count;
696        }
697        else {
698            forwardTextDirection = true;
699        }
700
701        if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
702            doThrowAIOOBE(env);
703            return 0;
704        }
705
706        const jchar* text = env->GetCharArrayElements(jtext, NULL);
707        count = breakText(env, *paint, typeface, text + index, count, maxWidth,
708                          bidiFlags, jmeasuredWidth, forwardTextDirection);
709        env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
710                                      JNI_ABORT);
711        return count;
712    }
713
714    static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
715                jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
716        NPE_CHECK_RETURN_ZERO(env, jtext);
717
718        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
719        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
720
721        int count = env->GetStringLength(jtext);
722        const jchar* text = env->GetStringChars(jtext, NULL);
723        count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, forwards);
724        env->ReleaseStringChars(jtext, text);
725        return count;
726    }
727
728    static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds,
729            const Paint& paint, TypefaceImpl* typeface, jint bidiFlags) {
730        SkRect  r;
731        SkIRect ir;
732
733        Layout layout;
734        MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
735        MinikinRect rect;
736        layout.getBounds(&rect);
737        r.fLeft = rect.mLeft;
738        r.fTop = rect.mTop;
739        r.fRight = rect.mRight;
740        r.fBottom = rect.mBottom;
741        r.roundOut(&ir);
742        GraphicsJNI::irect_to_jrect(ir, env, bounds);
743    }
744
745    static void getStringBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
746                                jstring text, jint start, jint end, jint bidiFlags, jobject bounds) {
747        const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
748        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
749        const jchar* textArray = env->GetStringChars(text, NULL);
750        doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags);
751        env->ReleaseStringChars(text, textArray);
752    }
753
754    static void getCharArrayBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
755                        jcharArray text, jint index, jint count, jint bidiFlags, jobject bounds) {
756        const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
757        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
758        const jchar* textArray = env->GetCharArrayElements(text, NULL);
759        doTextBounds(env, textArray + index, count, bounds, *paint, typeface, bidiFlags);
760        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
761                                      JNI_ABORT);
762    }
763
764    static jboolean layoutContainsNotdef(const Layout& layout) {
765        for (size_t i = 0; i < layout.nGlyphs(); i++) {
766            if (layout.getGlyphId(i) == 0) {
767                return true;
768            }
769        }
770        return false;
771    }
772
773    static jboolean hasGlyph(JNIEnv *env, jclass, jlong paintHandle, jlong typefaceHandle,
774            jint bidiFlags, jstring string) {
775        const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
776        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
777        ScopedStringChars str(env, string);
778
779        /* Start by rejecting unsupported base code point and variation selector pairs. */
780        size_t nChars = 0;
781        const uint32_t kStartOfString = 0xFFFFFFFF;
782        uint32_t prevCp = kStartOfString;
783        for (size_t i = 0; i < str.size(); i++) {
784            jchar cu = str[i];
785            uint32_t cp = cu;
786            if (U16_IS_TRAIL(cu)) {
787                // invalid UTF-16, unpaired trailing surrogate
788                return false;
789            } else if (U16_IS_LEAD(cu)) {
790                if (i + 1 == str.size()) {
791                    // invalid UTF-16, unpaired leading surrogate at end of string
792                    return false;
793                }
794                i++;
795                jchar cu2 = str[i];
796                if (!U16_IS_TRAIL(cu2)) {
797                    // invalid UTF-16, unpaired leading surrogate
798                    return false;
799                }
800                cp = U16_GET_SUPPLEMENTARY(cu, cu2);
801            }
802
803            if (prevCp != kStartOfString &&
804                ((0xFE00 <= cp && cp <= 0xFE0F) || (0xE0100 <= cp && cp <= 0xE01EF)) &&
805                !MinikinUtils::hasVariationSelector(typeface, prevCp, cp)) {
806                // No font has a glyph for the code point and variation selector pair.
807                return false;
808            }
809            nChars++;
810            prevCp = cp;
811        }
812        Layout layout;
813        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, str.get(), 0, str.size(),
814                str.size());
815        size_t nGlyphs = layout.nGlyphs();
816        if (nGlyphs != 1 && nChars > 1) {
817            // multiple-character input, and was not a ligature
818            // TODO: handle ZWJ/ZWNJ characters specially so we can detect certain ligatures
819            // in joining scripts, such as Arabic and Mongolian.
820            return false;
821        }
822        return nGlyphs > 0 && !layoutContainsNotdef(layout);
823    }
824
825    static jfloat doRunAdvance(const Paint* paint, TypefaceImpl* typeface, const jchar buf[],
826            jint start, jint count, jint bufSize, jboolean isRtl, jint offset) {
827        Layout layout;
828        int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
829        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, buf, start, count, bufSize);
830        return getRunAdvance(layout, buf, start, count, offset);
831    }
832
833    static jfloat getRunAdvance___CIIIIZI_F(JNIEnv *env, jclass, jlong paintHandle,
834            jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart,
835            jint contextEnd, jboolean isRtl, jint offset) {
836        const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
837        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
838        jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, NULL);
839        jfloat result = doRunAdvance(paint, typeface, textArray + contextStart,
840                start - contextStart, end - start, contextEnd - contextStart, isRtl,
841                offset - contextStart);
842        env->ReleasePrimitiveArrayCritical(text, textArray, JNI_ABORT);
843        return result;
844    }
845
846    static jint doOffsetForAdvance(const Paint* paint, TypefaceImpl* typeface, const jchar buf[],
847            jint start, jint count, jint bufSize, jboolean isRtl, jfloat advance) {
848        Layout layout;
849        int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
850        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, buf, start, count, bufSize);
851        return getOffsetForAdvance(layout, buf, start, count, advance);
852    }
853    static jint getOffsetForAdvance___CIIIIZF_I(JNIEnv *env, jclass, jlong paintHandle,
854            jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart,
855            jint contextEnd, jboolean isRtl, jfloat advance) {
856        const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
857        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
858        jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, NULL);
859        jint result = doOffsetForAdvance(paint, typeface, textArray + contextStart,
860                start - contextStart, end - start, contextEnd - contextStart, isRtl, advance);
861        result += contextStart;
862        env->ReleasePrimitiveArrayCritical(text, textArray, JNI_ABORT);
863        return result;
864    }
865
866}; // namespace PaintGlue
867
868static const JNINativeMethod methods[] = {
869    {"nGetNativeFinalizer", "()J", (void*) PaintGlue::getNativeFinalizer},
870    {"nInit","()J", (void*) PaintGlue::init},
871    {"nInitWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
872
873    {"nReset","!(J)V", (void*) PaintGlue::reset},
874    {"nSet","!(JJ)V", (void*) PaintGlue::assign},
875    {"nGetFlags","!(J)I", (void*) PaintGlue::getFlags},
876    {"nSetFlags","!(JI)V", (void*) PaintGlue::setFlags},
877    {"nGetHinting","!(J)I", (void*) PaintGlue::getHinting},
878    {"nSetHinting","!(JI)V", (void*) PaintGlue::setHinting},
879    {"nSetAntiAlias","!(JZ)V", (void*) PaintGlue::setAntiAlias},
880    {"nSetSubpixelText","!(JZ)V", (void*) PaintGlue::setSubpixelText},
881    {"nSetLinearText","!(JZ)V", (void*) PaintGlue::setLinearText},
882    {"nSetUnderlineText","!(JZ)V", (void*) PaintGlue::setUnderlineText},
883    {"nSetStrikeThruText","!(JZ)V", (void*) PaintGlue::setStrikeThruText},
884    {"nSetFakeBoldText","!(JZ)V", (void*) PaintGlue::setFakeBoldText},
885    {"nSetFilterBitmap","!(JZ)V", (void*) PaintGlue::setFilterBitmap},
886    {"nSetDither","!(JZ)V", (void*) PaintGlue::setDither},
887    {"nGetStyle","!(J)I", (void*) PaintGlue::getStyle},
888    {"nSetStyle","!(JI)V", (void*) PaintGlue::setStyle},
889    {"nGetColor","!(J)I", (void*) PaintGlue::getColor},
890    {"nSetColor","!(JI)V", (void*) PaintGlue::setColor},
891    {"nGetAlpha","!(J)I", (void*) PaintGlue::getAlpha},
892    {"nSetAlpha","!(JI)V", (void*) PaintGlue::setAlpha},
893    {"nGetStrokeWidth","!(J)F", (void*) PaintGlue::getStrokeWidth},
894    {"nSetStrokeWidth","!(JF)V", (void*) PaintGlue::setStrokeWidth},
895    {"nGetStrokeMiter","!(J)F", (void*) PaintGlue::getStrokeMiter},
896    {"nSetStrokeMiter","!(JF)V", (void*) PaintGlue::setStrokeMiter},
897    {"nGetStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap},
898    {"nSetStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap},
899    {"nGetStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin},
900    {"nSetStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin},
901    {"nGetFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath},
902    {"nSetShader","!(JJ)J", (void*) PaintGlue::setShader},
903    {"nSetColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter},
904    {"nSetXfermode","!(JJ)J", (void*) PaintGlue::setXfermode},
905    {"nSetPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect},
906    {"nSetMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter},
907    {"nSetTypeface","!(JJ)J", (void*) PaintGlue::setTypeface},
908    {"nSetRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer},
909    {"nGetTextAlign","!(J)I", (void*) PaintGlue::getTextAlign},
910    {"nSetTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign},
911    {"nSetTextLocales","!(JLjava/lang/String;)I", (void*) PaintGlue::setTextLocales},
912    {"nSetTextLocalesByMinikinLangListId","!(JI)V",
913            (void*) PaintGlue::setTextLocalesByMinikinLangListId},
914    {"nIsElegantTextHeight","!(J)Z", (void*) PaintGlue::isElegantTextHeight},
915    {"nSetElegantTextHeight","!(JZ)V", (void*) PaintGlue::setElegantTextHeight},
916    {"nGetTextSize","!(J)F", (void*) PaintGlue::getTextSize},
917    {"nSetTextSize","!(JF)V", (void*) PaintGlue::setTextSize},
918    {"nGetTextScaleX","!(J)F", (void*) PaintGlue::getTextScaleX},
919    {"nSetTextScaleX","!(JF)V", (void*) PaintGlue::setTextScaleX},
920    {"nGetTextSkewX","!(J)F", (void*) PaintGlue::getTextSkewX},
921    {"nSetTextSkewX","!(JF)V", (void*) PaintGlue::setTextSkewX},
922    {"nGetLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing},
923    {"nSetLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing},
924    {"nSetFontFeatureSettings","(JLjava/lang/String;)V",
925            (void*) PaintGlue::setFontFeatureSettings},
926    {"nGetHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit},
927    {"nSetHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit},
928    {"nAscent","!(JJ)F", (void*) PaintGlue::ascent},
929    {"nDescent","!(JJ)F", (void*) PaintGlue::descent},
930
931    {"nGetFontMetrics", "!(JJLandroid/graphics/Paint$FontMetrics;)F",
932            (void*)PaintGlue::getFontMetrics},
933    {"nGetFontMetricsInt", "!(JJLandroid/graphics/Paint$FontMetricsInt;)I",
934            (void*)PaintGlue::getFontMetricsInt},
935
936    {"nBreakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC},
937    {"nBreakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
938    {"nGetTextAdvances","(JJ[CIIIII[FI)F",
939            (void*) PaintGlue::getTextAdvances___CIIIII_FI},
940    {"nGetTextAdvances","(JJLjava/lang/String;IIIII[FI)F",
941            (void*) PaintGlue::getTextAdvances__StringIIIII_FI},
942
943    {"nGetTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C},
944    {"nGetTextRunCursor", "(JLjava/lang/String;IIIII)I",
945            (void*) PaintGlue::getTextRunCursor__String},
946    {"nGetTextPath", "(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C},
947    {"nGetTextPath", "(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String},
948    {"nGetStringBounds", "(JJLjava/lang/String;IIILandroid/graphics/Rect;)V",
949            (void*) PaintGlue::getStringBounds },
950    {"nGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V",
951            (void*) PaintGlue::getCharArrayBounds },
952    {"nHasGlyph", "(JJILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph },
953    {"nGetRunAdvance", "(JJ[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F},
954    {"nGetOffsetForAdvance", "(JJ[CIIIIZF)I",
955            (void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I},
956
957    {"nSetShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer},
958    {"nHasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
959};
960
961int register_android_graphics_Paint(JNIEnv* env) {
962    gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics");
963    gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class);
964
965    gFontMetrics_fieldID.top = GetFieldIDOrDie(env, gFontMetrics_class, "top", "F");
966    gFontMetrics_fieldID.ascent = GetFieldIDOrDie(env, gFontMetrics_class, "ascent", "F");
967    gFontMetrics_fieldID.descent = GetFieldIDOrDie(env, gFontMetrics_class, "descent", "F");
968    gFontMetrics_fieldID.bottom = GetFieldIDOrDie(env, gFontMetrics_class, "bottom", "F");
969    gFontMetrics_fieldID.leading = GetFieldIDOrDie(env, gFontMetrics_class, "leading", "F");
970
971    gFontMetricsInt_class = FindClassOrDie(env, "android/graphics/Paint$FontMetricsInt");
972    gFontMetricsInt_class = MakeGlobalRefOrDie(env, gFontMetricsInt_class);
973
974    gFontMetricsInt_fieldID.top = GetFieldIDOrDie(env, gFontMetricsInt_class, "top", "I");
975    gFontMetricsInt_fieldID.ascent = GetFieldIDOrDie(env, gFontMetricsInt_class, "ascent", "I");
976    gFontMetricsInt_fieldID.descent = GetFieldIDOrDie(env, gFontMetricsInt_class, "descent", "I");
977    gFontMetricsInt_fieldID.bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I");
978    gFontMetricsInt_fieldID.leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I");
979
980    return RegisterMethodsOrDie(env, "android/graphics/Paint", methods, NELEM(methods));
981}
982
983}
984