• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.graphics;
18 
19 import com.android.ide.common.rendering.api.LayoutLog;
20 import com.android.layoutlib.bridge.Bridge;
21 import com.android.layoutlib.bridge.impl.DelegateManager;
22 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
23 
24 import android.graphics.FontFamily_Delegate.FontVariant;
25 import android.graphics.Paint.FontMetrics;
26 import android.graphics.Paint.FontMetricsInt;
27 import android.text.TextUtils;
28 
29 import java.awt.BasicStroke;
30 import java.awt.Font;
31 import java.awt.Shape;
32 import java.awt.Stroke;
33 import java.awt.Toolkit;
34 import java.awt.geom.AffineTransform;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.List;
38 import java.util.Locale;
39 
40 /**
41  * Delegate implementing the native methods of android.graphics.Paint
42  *
43  * Through the layoutlib_create tool, the original native methods of Paint have been replaced
44  * by calls to methods of the same name in this delegate class.
45  *
46  * This class behaves like the original native implementation, but in Java, keeping previously
47  * native data into its own objects and mapping them to int that are sent back and forth between
48  * it and the original Paint class.
49  *
50  * @see DelegateManager
51  *
52  */
53 public class Paint_Delegate {
54 
55     /**
56      * Class associating a {@link Font} and its {@link java.awt.FontMetrics}.
57      */
58     /*package*/ static final class FontInfo {
59         Font mFont;
60         java.awt.FontMetrics mMetrics;
61     }
62 
63     // ---- delegate manager ----
64     private static final DelegateManager<Paint_Delegate> sManager =
65             new DelegateManager<Paint_Delegate>(Paint_Delegate.class);
66 
67     // ---- delegate helper data ----
68 
69     // This list can contain null elements.
70     private List<FontInfo> mFonts;
71 
72     // ---- delegate data ----
73     private int mFlags;
74     private int mColor;
75     private int mStyle;
76     private int mCap;
77     private int mJoin;
78     private int mTextAlign;
79     private Typeface_Delegate mTypeface;
80     private float mStrokeWidth;
81     private float mStrokeMiter;
82     private float mTextSize;
83     private float mTextScaleX;
84     private float mTextSkewX;
85     private int mHintingMode = Paint.HINTING_ON;
86     // Variant of the font. A paint's variant can only be compact or elegant.
87     private FontVariant mFontVariant = FontVariant.COMPACT;
88 
89     private Xfermode_Delegate mXfermode;
90     private ColorFilter_Delegate mColorFilter;
91     private Shader_Delegate mShader;
92     private PathEffect_Delegate mPathEffect;
93     private MaskFilter_Delegate mMaskFilter;
94     private Rasterizer_Delegate mRasterizer;
95 
96     private Locale mLocale = Locale.getDefault();
97 
98     // Used only to assert invariants.
99     public long mNativeTypeface;
100 
101     // ---- Public Helper methods ----
102 
getDelegate(long native_paint)103     public static Paint_Delegate getDelegate(long native_paint) {
104         return sManager.getDelegate(native_paint);
105     }
106 
107     /**
108      * Returns the list of {@link Font} objects.
109      */
getFonts()110     public List<FontInfo> getFonts() {
111         return mFonts;
112     }
113 
isAntiAliased()114     public boolean isAntiAliased() {
115         return (mFlags & Paint.ANTI_ALIAS_FLAG) != 0;
116     }
117 
isFilterBitmap()118     public boolean isFilterBitmap() {
119         return (mFlags & Paint.FILTER_BITMAP_FLAG) != 0;
120     }
121 
getStyle()122     public int getStyle() {
123         return mStyle;
124     }
125 
getColor()126     public int getColor() {
127         return mColor;
128     }
129 
getAlpha()130     public int getAlpha() {
131         return mColor >>> 24;
132     }
133 
setAlpha(int alpha)134     public void setAlpha(int alpha) {
135         mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
136     }
137 
getTextAlign()138     public int getTextAlign() {
139         return mTextAlign;
140     }
141 
getStrokeWidth()142     public float getStrokeWidth() {
143         return mStrokeWidth;
144     }
145 
146     /**
147      * returns the value of stroke miter needed by the java api.
148      */
getJavaStrokeMiter()149     public float getJavaStrokeMiter() {
150         float miter = mStrokeMiter * mStrokeWidth;
151         if (miter < 1.f) {
152             miter = 1.f;
153         }
154         return miter;
155     }
156 
getJavaCap()157     public int getJavaCap() {
158         switch (Paint.sCapArray[mCap]) {
159             case BUTT:
160                 return BasicStroke.CAP_BUTT;
161             case ROUND:
162                 return BasicStroke.CAP_ROUND;
163             default:
164             case SQUARE:
165                 return BasicStroke.CAP_SQUARE;
166         }
167     }
168 
getJavaJoin()169     public int getJavaJoin() {
170         switch (Paint.sJoinArray[mJoin]) {
171             default:
172             case MITER:
173                 return BasicStroke.JOIN_MITER;
174             case ROUND:
175                 return BasicStroke.JOIN_ROUND;
176             case BEVEL:
177                 return BasicStroke.JOIN_BEVEL;
178         }
179     }
180 
getJavaStroke()181     public Stroke getJavaStroke() {
182         if (mPathEffect != null) {
183             if (mPathEffect.isSupported()) {
184                 Stroke stroke = mPathEffect.getStroke(this);
185                 assert stroke != null;
186                 if (stroke != null) {
187                     return stroke;
188                 }
189             } else {
190                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_PATHEFFECT,
191                         mPathEffect.getSupportMessage(),
192                         null, null /*data*/);
193             }
194         }
195 
196         // if no custom stroke as been set, set the default one.
197         return new BasicStroke(
198                     getStrokeWidth(),
199                     getJavaCap(),
200                     getJavaJoin(),
201                     getJavaStrokeMiter());
202     }
203 
204     /**
205      * Returns the {@link Xfermode} delegate or null if none have been set
206      *
207      * @return the delegate or null.
208      */
getXfermode()209     public Xfermode_Delegate getXfermode() {
210         return mXfermode;
211     }
212 
213     /**
214      * Returns the {@link ColorFilter} delegate or null if none have been set
215      *
216      * @return the delegate or null.
217      */
getColorFilter()218     public ColorFilter_Delegate getColorFilter() {
219         return mColorFilter;
220     }
221 
222     /**
223      * Returns the {@link Shader} delegate or null if none have been set
224      *
225      * @return the delegate or null.
226      */
getShader()227     public Shader_Delegate getShader() {
228         return mShader;
229     }
230 
231     /**
232      * Returns the {@link MaskFilter} delegate or null if none have been set
233      *
234      * @return the delegate or null.
235      */
getMaskFilter()236     public MaskFilter_Delegate getMaskFilter() {
237         return mMaskFilter;
238     }
239 
240     /**
241      * Returns the {@link Rasterizer} delegate or null if none have been set
242      *
243      * @return the delegate or null.
244      */
getRasterizer()245     public Rasterizer_Delegate getRasterizer() {
246         return mRasterizer;
247     }
248 
249     // ---- native methods ----
250 
251     @LayoutlibDelegate
getFlags(Paint thisPaint)252     /*package*/ static int getFlags(Paint thisPaint) {
253         // get the delegate from the native int.
254         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
255         if (delegate == null) {
256             return 0;
257         }
258 
259         return delegate.mFlags;
260     }
261 
262 
263 
264     @LayoutlibDelegate
setFlags(Paint thisPaint, int flags)265     /*package*/ static void setFlags(Paint thisPaint, int flags) {
266         // get the delegate from the native int.
267         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
268         if (delegate == null) {
269             return;
270         }
271 
272         delegate.mFlags = flags;
273     }
274 
275     @LayoutlibDelegate
setFilterBitmap(Paint thisPaint, boolean filter)276     /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
277         setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
278     }
279 
280     @LayoutlibDelegate
getHinting(Paint thisPaint)281     /*package*/ static int getHinting(Paint thisPaint) {
282         // get the delegate from the native int.
283         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
284         if (delegate == null) {
285             return Paint.HINTING_ON;
286         }
287 
288         return delegate.mHintingMode;
289     }
290 
291     @LayoutlibDelegate
setHinting(Paint thisPaint, int mode)292     /*package*/ static void setHinting(Paint thisPaint, int mode) {
293         // get the delegate from the native int.
294         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
295         if (delegate == null) {
296             return;
297         }
298 
299         delegate.mHintingMode = mode;
300     }
301 
302     @LayoutlibDelegate
setAntiAlias(Paint thisPaint, boolean aa)303     /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
304         setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
305     }
306 
307     @LayoutlibDelegate
setSubpixelText(Paint thisPaint, boolean subpixelText)308     /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
309         setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
310     }
311 
312     @LayoutlibDelegate
setUnderlineText(Paint thisPaint, boolean underlineText)313     /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
314         setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
315     }
316 
317     @LayoutlibDelegate
setStrikeThruText(Paint thisPaint, boolean strikeThruText)318     /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
319         setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
320     }
321 
322     @LayoutlibDelegate
setFakeBoldText(Paint thisPaint, boolean fakeBoldText)323     /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
324         setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
325     }
326 
327     @LayoutlibDelegate
setDither(Paint thisPaint, boolean dither)328     /*package*/ static void setDither(Paint thisPaint, boolean dither) {
329         setFlag(thisPaint, Paint.DITHER_FLAG, dither);
330     }
331 
332     @LayoutlibDelegate
setLinearText(Paint thisPaint, boolean linearText)333     /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
334         setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
335     }
336 
337     @LayoutlibDelegate
getColor(Paint thisPaint)338     /*package*/ static int getColor(Paint thisPaint) {
339         // get the delegate from the native int.
340         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
341         if (delegate == null) {
342             return 0;
343         }
344 
345         return delegate.mColor;
346     }
347 
348     @LayoutlibDelegate
setColor(Paint thisPaint, int color)349     /*package*/ static void setColor(Paint thisPaint, int color) {
350         // get the delegate from the native int.
351         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
352         if (delegate == null) {
353             return;
354         }
355 
356         delegate.mColor = color;
357     }
358 
359     @LayoutlibDelegate
getAlpha(Paint thisPaint)360     /*package*/ static int getAlpha(Paint thisPaint) {
361         // get the delegate from the native int.
362         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
363         if (delegate == null) {
364             return 0;
365         }
366 
367         return delegate.getAlpha();
368     }
369 
370     @LayoutlibDelegate
setAlpha(Paint thisPaint, int a)371     /*package*/ static void setAlpha(Paint thisPaint, int a) {
372         // get the delegate from the native int.
373         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
374         if (delegate == null) {
375             return;
376         }
377 
378         delegate.setAlpha(a);
379     }
380 
381     @LayoutlibDelegate
getStrokeWidth(Paint thisPaint)382     /*package*/ static float getStrokeWidth(Paint thisPaint) {
383         // get the delegate from the native int.
384         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
385         if (delegate == null) {
386             return 1.f;
387         }
388 
389         return delegate.mStrokeWidth;
390     }
391 
392     @LayoutlibDelegate
setStrokeWidth(Paint thisPaint, float width)393     /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
394         // get the delegate from the native int.
395         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
396         if (delegate == null) {
397             return;
398         }
399 
400         delegate.mStrokeWidth = width;
401     }
402 
403     @LayoutlibDelegate
getStrokeMiter(Paint thisPaint)404     /*package*/ static float getStrokeMiter(Paint thisPaint) {
405         // get the delegate from the native int.
406         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
407         if (delegate == null) {
408             return 1.f;
409         }
410 
411         return delegate.mStrokeMiter;
412     }
413 
414     @LayoutlibDelegate
setStrokeMiter(Paint thisPaint, float miter)415     /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
416         // get the delegate from the native int.
417         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
418         if (delegate == null) {
419             return;
420         }
421 
422         delegate.mStrokeMiter = miter;
423     }
424 
425     @LayoutlibDelegate
native_setShadowLayer(long paint, float radius, float dx, float dy, int color)426     /*package*/ static void native_setShadowLayer(long paint, float radius, float dx, float dy,
427             int color) {
428         // FIXME
429         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
430                 "Paint.setShadowLayer is not supported.", null, null /*data*/);
431     }
432 
433     @LayoutlibDelegate
native_hasShadowLayer(long paint)434     /*package*/ static boolean native_hasShadowLayer(long paint) {
435         // FIXME
436         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
437                 "Paint.hasShadowLayer is not supported.", null, null /*data*/);
438         return false;
439     }
440 
441     @LayoutlibDelegate
isElegantTextHeight(Paint thisPaint)442     /*package*/ static boolean isElegantTextHeight(Paint thisPaint) {
443         // get the delegate from the native int.
444         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
445         return delegate != null && delegate.mFontVariant == FontVariant.ELEGANT;
446     }
447 
448     @LayoutlibDelegate
setElegantTextHeight(Paint thisPaint, boolean elegant)449     /*package*/ static void setElegantTextHeight(Paint thisPaint, boolean elegant) {
450         // get the delegate from the native int.
451         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
452         if (delegate == null) {
453             return;
454         }
455 
456         delegate.mFontVariant = elegant ? FontVariant.ELEGANT : FontVariant.COMPACT;
457     }
458 
459     @LayoutlibDelegate
getTextSize(Paint thisPaint)460     /*package*/ static float getTextSize(Paint thisPaint) {
461         // get the delegate from the native int.
462         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
463         if (delegate == null) {
464             return 1.f;
465         }
466 
467         return delegate.mTextSize;
468     }
469 
470     @LayoutlibDelegate
setTextSize(Paint thisPaint, float textSize)471     /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
472         // get the delegate from the native int.
473         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
474         if (delegate == null) {
475             return;
476         }
477 
478         delegate.mTextSize = textSize;
479         delegate.updateFontObject();
480     }
481 
482     @LayoutlibDelegate
getTextScaleX(Paint thisPaint)483     /*package*/ static float getTextScaleX(Paint thisPaint) {
484         // get the delegate from the native int.
485         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
486         if (delegate == null) {
487             return 1.f;
488         }
489 
490         return delegate.mTextScaleX;
491     }
492 
493     @LayoutlibDelegate
setTextScaleX(Paint thisPaint, float scaleX)494     /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
495         // get the delegate from the native int.
496         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
497         if (delegate == null) {
498             return;
499         }
500 
501         delegate.mTextScaleX = scaleX;
502         delegate.updateFontObject();
503     }
504 
505     @LayoutlibDelegate
getTextSkewX(Paint thisPaint)506     /*package*/ static float getTextSkewX(Paint thisPaint) {
507         // get the delegate from the native int.
508         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
509         if (delegate == null) {
510             return 1.f;
511         }
512 
513         return delegate.mTextSkewX;
514     }
515 
516     @LayoutlibDelegate
setTextSkewX(Paint thisPaint, float skewX)517     /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
518         // get the delegate from the native int.
519         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
520         if (delegate == null) {
521             return;
522         }
523 
524         delegate.mTextSkewX = skewX;
525         delegate.updateFontObject();
526     }
527 
528     @LayoutlibDelegate
ascent(Paint thisPaint)529     /*package*/ static float ascent(Paint thisPaint) {
530         // get the delegate
531         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
532         if (delegate == null) {
533             return 0;
534         }
535 
536         if (delegate.mFonts.size() > 0) {
537             java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
538             // Android expects negative ascent so we invert the value from Java.
539             return - javaMetrics.getAscent();
540         }
541 
542         return 0;
543     }
544 
545     @LayoutlibDelegate
descent(Paint thisPaint)546     /*package*/ static float descent(Paint thisPaint) {
547         // get the delegate
548         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
549         if (delegate == null) {
550             return 0;
551         }
552 
553         if (delegate.mFonts.size() > 0) {
554             java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
555             return javaMetrics.getDescent();
556         }
557 
558         return 0;
559 
560     }
561 
562     @LayoutlibDelegate
getFontMetrics(Paint thisPaint, FontMetrics metrics)563     /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
564         // get the delegate
565         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
566         if (delegate == null) {
567             return 0;
568         }
569 
570         return delegate.getFontMetrics(metrics);
571     }
572 
573     @LayoutlibDelegate
getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi)574     /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
575         // get the delegate
576         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
577         if (delegate == null) {
578             return 0;
579         }
580 
581         if (delegate.mFonts.size() > 0) {
582             java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
583             if (fmi != null) {
584                 // Android expects negative ascent so we invert the value from Java.
585                 fmi.top = - javaMetrics.getMaxAscent();
586                 fmi.ascent = - javaMetrics.getAscent();
587                 fmi.descent = javaMetrics.getDescent();
588                 fmi.bottom = javaMetrics.getMaxDescent();
589                 fmi.leading = javaMetrics.getLeading();
590             }
591 
592             return javaMetrics.getHeight();
593         }
594 
595         return 0;
596     }
597 
598     @LayoutlibDelegate
native_measureText(Paint thisPaint, char[] text, int index, int count, int bidiFlags)599     /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
600             int count, int bidiFlags) {
601         // get the delegate
602         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
603         if (delegate == null) {
604             return 0;
605         }
606 
607         RectF bounds = delegate.measureText(text, index, count, null, 0, bidiFlags);
608         return bounds.right - bounds.left;
609     }
610 
611     @LayoutlibDelegate
native_measureText(Paint thisPaint, String text, int start, int end, int bidiFlags)612     /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end,
613         int bidiFlags) {
614         return native_measureText(thisPaint, text.toCharArray(), start, end - start, bidiFlags);
615     }
616 
617     @LayoutlibDelegate
native_measureText(Paint thisPaint, String text, int bidiFlags)618     /*package*/ static float native_measureText(Paint thisPaint, String text, int bidiFlags) {
619         return native_measureText(thisPaint, text.toCharArray(), 0, text.length(), bidiFlags);
620     }
621 
622     @LayoutlibDelegate
native_breakText(long nativePaint, long nativeTypeface, char[] text, int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth)623     /*package*/ static int native_breakText(long nativePaint, long nativeTypeface, char[] text,
624             int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth) {
625 
626         // get the delegate
627         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
628         if (delegate == null) {
629             return 0;
630         }
631 
632         int inc = count > 0 ? 1 : -1;
633 
634         int measureIndex = 0;
635         for (int i = index; i != index + count; i += inc, measureIndex++) {
636             int start, end;
637             if (i < index) {
638                 start = i;
639                 end = index;
640             } else {
641                 start = index;
642                 end = i;
643             }
644 
645             // measure from start to end
646             RectF bounds = delegate.measureText(text, start, end - start + 1, null, 0, bidiFlags);
647             float res = bounds.right - bounds.left;
648 
649             if (measuredWidth != null) {
650                 measuredWidth[measureIndex] = res;
651             }
652 
653             if (res > maxWidth) {
654                 // we should not return this char index, but since it's 0-based
655                 // and we need to return a count, we simply return measureIndex;
656                 return measureIndex;
657             }
658 
659         }
660 
661         return measureIndex;
662     }
663 
664     @LayoutlibDelegate
native_breakText(long nativePaint, long nativeTypeface, String text, boolean measureForwards, float maxWidth, int bidiFlags, float[] measuredWidth)665     /*package*/ static int native_breakText(long nativePaint, long nativeTypeface, String text,
666             boolean measureForwards,
667             float maxWidth, int bidiFlags, float[] measuredWidth) {
668         return native_breakText(nativePaint, nativeTypeface, text.toCharArray(), 0, text.length(),
669                 maxWidth, bidiFlags, measuredWidth);
670     }
671 
672     @LayoutlibDelegate
native_init()673     /*package*/ static long native_init() {
674         Paint_Delegate newDelegate = new Paint_Delegate();
675         return sManager.addNewDelegate(newDelegate);
676     }
677 
678     @LayoutlibDelegate
native_initWithPaint(long paint)679     /*package*/ static long native_initWithPaint(long paint) {
680         // get the delegate from the native int.
681         Paint_Delegate delegate = sManager.getDelegate(paint);
682         if (delegate == null) {
683             return 0;
684         }
685 
686         Paint_Delegate newDelegate = new Paint_Delegate(delegate);
687         return sManager.addNewDelegate(newDelegate);
688     }
689 
690     @LayoutlibDelegate
native_reset(long native_object)691     /*package*/ static void native_reset(long native_object) {
692         // get the delegate from the native int.
693         Paint_Delegate delegate = sManager.getDelegate(native_object);
694         if (delegate == null) {
695             return;
696         }
697 
698         delegate.reset();
699     }
700 
701     @LayoutlibDelegate
native_set(long native_dst, long native_src)702     /*package*/ static void native_set(long native_dst, long native_src) {
703         // get the delegate from the native int.
704         Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
705         if (delegate_dst == null) {
706             return;
707         }
708 
709         // get the delegate from the native int.
710         Paint_Delegate delegate_src = sManager.getDelegate(native_src);
711         if (delegate_src == null) {
712             return;
713         }
714 
715         delegate_dst.set(delegate_src);
716     }
717 
718     @LayoutlibDelegate
native_getStyle(long native_object)719     /*package*/ static int native_getStyle(long native_object) {
720         // get the delegate from the native int.
721         Paint_Delegate delegate = sManager.getDelegate(native_object);
722         if (delegate == null) {
723             return 0;
724         }
725 
726         return delegate.mStyle;
727     }
728 
729     @LayoutlibDelegate
native_setStyle(long native_object, int style)730     /*package*/ static void native_setStyle(long native_object, int style) {
731         // get the delegate from the native int.
732         Paint_Delegate delegate = sManager.getDelegate(native_object);
733         if (delegate == null) {
734             return;
735         }
736 
737         delegate.mStyle = style;
738     }
739 
740     @LayoutlibDelegate
native_getStrokeCap(long native_object)741     /*package*/ static int native_getStrokeCap(long native_object) {
742         // get the delegate from the native int.
743         Paint_Delegate delegate = sManager.getDelegate(native_object);
744         if (delegate == null) {
745             return 0;
746         }
747 
748         return delegate.mCap;
749     }
750 
751     @LayoutlibDelegate
native_setStrokeCap(long native_object, int cap)752     /*package*/ static void native_setStrokeCap(long native_object, int cap) {
753         // get the delegate from the native int.
754         Paint_Delegate delegate = sManager.getDelegate(native_object);
755         if (delegate == null) {
756             return;
757         }
758 
759         delegate.mCap = cap;
760     }
761 
762     @LayoutlibDelegate
native_getStrokeJoin(long native_object)763     /*package*/ static int native_getStrokeJoin(long native_object) {
764         // get the delegate from the native int.
765         Paint_Delegate delegate = sManager.getDelegate(native_object);
766         if (delegate == null) {
767             return 0;
768         }
769 
770         return delegate.mJoin;
771     }
772 
773     @LayoutlibDelegate
native_setStrokeJoin(long native_object, int join)774     /*package*/ static void native_setStrokeJoin(long native_object, int join) {
775         // get the delegate from the native int.
776         Paint_Delegate delegate = sManager.getDelegate(native_object);
777         if (delegate == null) {
778             return;
779         }
780 
781         delegate.mJoin = join;
782     }
783 
784     @LayoutlibDelegate
native_getFillPath(long native_object, long src, long dst)785     /*package*/ static boolean native_getFillPath(long native_object, long src, long dst) {
786         Paint_Delegate paint = sManager.getDelegate(native_object);
787         if (paint == null) {
788             return false;
789         }
790 
791         Path_Delegate srcPath = Path_Delegate.getDelegate(src);
792         if (srcPath == null) {
793             return true;
794         }
795 
796         Path_Delegate dstPath = Path_Delegate.getDelegate(dst);
797         if (dstPath == null) {
798             return true;
799         }
800 
801         Stroke stroke = paint.getJavaStroke();
802         Shape strokeShape = stroke.createStrokedShape(srcPath.getJavaShape());
803 
804         dstPath.setJavaShape(strokeShape);
805 
806         // FIXME figure out the return value?
807         return true;
808     }
809 
810     @LayoutlibDelegate
native_setShader(long native_object, long shader)811     /*package*/ static long native_setShader(long native_object, long shader) {
812         // get the delegate from the native int.
813         Paint_Delegate delegate = sManager.getDelegate(native_object);
814         if (delegate == null) {
815             return shader;
816         }
817 
818         delegate.mShader = Shader_Delegate.getDelegate(shader);
819 
820         return shader;
821     }
822 
823     @LayoutlibDelegate
native_setColorFilter(long native_object, long filter)824     /*package*/ static long native_setColorFilter(long native_object, long filter) {
825         // get the delegate from the native int.
826         Paint_Delegate delegate = sManager.getDelegate(native_object);
827         if (delegate == null) {
828             return filter;
829         }
830 
831         delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter);
832 
833         // Log warning if it's not supported.
834         if (delegate.mColorFilter != null && !delegate.mColorFilter.isSupported()) {
835             Bridge.getLog().fidelityWarning(LayoutLog.TAG_COLORFILTER,
836                     delegate.mColorFilter.getSupportMessage(), null, null /*data*/);
837         }
838 
839         return filter;
840     }
841 
842     @LayoutlibDelegate
native_setXfermode(long native_object, long xfermode)843     /*package*/ static long native_setXfermode(long native_object, long xfermode) {
844         // get the delegate from the native int.
845         Paint_Delegate delegate = sManager.getDelegate(native_object);
846         if (delegate == null) {
847             return xfermode;
848         }
849 
850         delegate.mXfermode = Xfermode_Delegate.getDelegate(xfermode);
851 
852         return xfermode;
853     }
854 
855     @LayoutlibDelegate
native_setPathEffect(long native_object, long effect)856     /*package*/ static long native_setPathEffect(long native_object, long effect) {
857         // get the delegate from the native int.
858         Paint_Delegate delegate = sManager.getDelegate(native_object);
859         if (delegate == null) {
860             return effect;
861         }
862 
863         delegate.mPathEffect = PathEffect_Delegate.getDelegate(effect);
864 
865         return effect;
866     }
867 
868     @LayoutlibDelegate
native_setMaskFilter(long native_object, long maskfilter)869     /*package*/ static long native_setMaskFilter(long native_object, long maskfilter) {
870         // get the delegate from the native int.
871         Paint_Delegate delegate = sManager.getDelegate(native_object);
872         if (delegate == null) {
873             return maskfilter;
874         }
875 
876         delegate.mMaskFilter = MaskFilter_Delegate.getDelegate(maskfilter);
877 
878         // since none of those are supported, display a fidelity warning right away
879         if (delegate.mMaskFilter != null && !delegate.mMaskFilter.isSupported()) {
880             Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER,
881                     delegate.mMaskFilter.getSupportMessage(), null, null /*data*/);
882         }
883 
884         return maskfilter;
885     }
886 
887     @LayoutlibDelegate
native_setTypeface(long native_object, long typeface)888     /*package*/ static long native_setTypeface(long native_object, long typeface) {
889         // get the delegate from the native int.
890         Paint_Delegate delegate = sManager.getDelegate(native_object);
891         if (delegate == null) {
892             return 0;
893         }
894 
895         delegate.mTypeface = Typeface_Delegate.getDelegate(typeface);
896         delegate.mNativeTypeface = typeface;
897         delegate.updateFontObject();
898         return typeface;
899     }
900 
901     @LayoutlibDelegate
native_setRasterizer(long native_object, long rasterizer)902     /*package*/ static long native_setRasterizer(long native_object, long rasterizer) {
903         // get the delegate from the native int.
904         Paint_Delegate delegate = sManager.getDelegate(native_object);
905         if (delegate == null) {
906             return rasterizer;
907         }
908 
909         delegate.mRasterizer = Rasterizer_Delegate.getDelegate(rasterizer);
910 
911         // since none of those are supported, display a fidelity warning right away
912         if (delegate.mRasterizer != null && !delegate.mRasterizer.isSupported()) {
913             Bridge.getLog().fidelityWarning(LayoutLog.TAG_RASTERIZER,
914                     delegate.mRasterizer.getSupportMessage(), null, null /*data*/);
915         }
916 
917         return rasterizer;
918     }
919 
920     @LayoutlibDelegate
native_getTextAlign(long native_object)921     /*package*/ static int native_getTextAlign(long native_object) {
922         // get the delegate from the native int.
923         Paint_Delegate delegate = sManager.getDelegate(native_object);
924         if (delegate == null) {
925             return 0;
926         }
927 
928         return delegate.mTextAlign;
929     }
930 
931     @LayoutlibDelegate
native_setTextAlign(long native_object, int align)932     /*package*/ static void native_setTextAlign(long native_object, int align) {
933         // get the delegate from the native int.
934         Paint_Delegate delegate = sManager.getDelegate(native_object);
935         if (delegate == null) {
936             return;
937         }
938 
939         delegate.mTextAlign = align;
940     }
941 
942     @LayoutlibDelegate
native_setTextLocale(long native_object, String locale)943     /*package*/ static void native_setTextLocale(long native_object, String locale) {
944         // get the delegate from the native int.
945         Paint_Delegate delegate = sManager.getDelegate(native_object);
946         if (delegate == null) {
947             return;
948         }
949 
950         delegate.setTextLocale(locale);
951     }
952 
953     @LayoutlibDelegate
native_getTextWidths(long native_object, long native_typeface, char[] text, int index, int count, int bidiFlags, float[] widths)954     /*package*/ static int native_getTextWidths(long native_object, long native_typeface,
955             char[] text, int index, int count, int bidiFlags, float[] widths) {
956 
957         if (widths != null) {
958             for (int i = 0; i< count; i++) {
959                 widths[i]=0;
960             }
961         }
962         // get the delegate from the native int.
963         Paint_Delegate delegate = sManager.getDelegate(native_object);
964         if (delegate == null) {
965             return 0;
966         }
967 
968         // native_typeface is passed here since Framework's old implementation did not have the
969         // typeface object associated with the Paint. Since, we follow the new framework way,
970         // we store the typeface with the paint and use it directly.
971         assert (native_typeface == delegate.mNativeTypeface);
972 
973         RectF bounds = delegate.measureText(text, index, count, widths, 0, bidiFlags);
974         return ((int) (bounds.right - bounds.left));
975     }
976 
977     @LayoutlibDelegate
native_getTextWidths(long native_object, long native_typeface, String text, int start, int end, int bidiFlags, float[] widths)978     /*package*/ static int native_getTextWidths(long native_object, long native_typeface,
979             String text, int start, int end, int bidiFlags, float[] widths) {
980         return native_getTextWidths(native_object, native_typeface, text.toCharArray(), start,
981                 end - start, bidiFlags, widths);
982     }
983 
984     @LayoutlibDelegate
native_getTextGlyphs(long native_object, String text, int start, int end, int contextStart, int contextEnd, int flags, char[] glyphs)985     /* package */static int native_getTextGlyphs(long native_object, String text, int start,
986             int end, int contextStart, int contextEnd, int flags, char[] glyphs) {
987         // FIXME
988         return 0;
989     }
990 
991     @LayoutlibDelegate
native_getTextRunAdvances(long native_object, long native_typeface, char[] text, int index, int count, int contextIndex, int contextCount, boolean isRtl, float[] advances, int advancesIndex)992     /*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface,
993             char[] text, int index, int count, int contextIndex, int contextCount,
994             boolean isRtl, float[] advances, int advancesIndex) {
995 
996         if (advances != null)
997             for (int i = advancesIndex; i< advancesIndex+count; i++)
998                 advances[i]=0;
999         // get the delegate from the native int.
1000         Paint_Delegate delegate = sManager.getDelegate(native_object);
1001         if (delegate == null) {
1002             return 0.f;
1003         }
1004 
1005         // native_typeface is passed here since Framework's old implementation did not have the
1006         // typeface object associated with the Paint. Since, we follow the new framework way,
1007         // we store the typeface with the paint and use it directly.
1008         assert (native_typeface == delegate.mNativeTypeface);
1009 
1010         RectF bounds = delegate.measureText(text, index, count, advances, advancesIndex, isRtl);
1011         return bounds.right - bounds.left;
1012     }
1013 
1014     @LayoutlibDelegate
native_getTextRunAdvances(long native_object, long native_typeface, String text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float[] advances, int advancesIndex)1015     /*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface,
1016             String text, int start, int end, int contextStart, int contextEnd,
1017             boolean isRtl, float[] advances, int advancesIndex) {
1018         // FIXME: support contextStart and contextEnd
1019         int count = end - start;
1020         char[] buffer = TemporaryBuffer.obtain(count);
1021         TextUtils.getChars(text, start, end, buffer, 0);
1022 
1023         return native_getTextRunAdvances(native_object, native_typeface, buffer, 0, count,
1024                 contextStart, contextEnd - contextStart, isRtl, advances, advancesIndex);
1025     }
1026 
1027     @LayoutlibDelegate
native_getTextRunCursor(Paint thisPaint, long native_object, char[] text, int contextStart, int contextLength, int flags, int offset, int cursorOpt)1028     /*package*/ static int native_getTextRunCursor(Paint thisPaint, long native_object, char[] text,
1029             int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
1030         // FIXME
1031         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
1032                 "Paint.getTextRunCursor is not supported.", null, null /*data*/);
1033         return 0;
1034     }
1035 
1036     @LayoutlibDelegate
native_getTextRunCursor(Paint thisPaint, long native_object, String text, int contextStart, int contextEnd, int flags, int offset, int cursorOpt)1037     /*package*/ static int native_getTextRunCursor(Paint thisPaint, long native_object, String text,
1038             int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
1039         // FIXME
1040         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
1041                 "Paint.getTextRunCursor is not supported.", null, null /*data*/);
1042         return 0;
1043     }
1044 
1045     @LayoutlibDelegate
native_getTextPath(long native_object, long native_typeface, int bidiFlags, char[] text, int index, int count, float x, float y, long path)1046     /*package*/ static void native_getTextPath(long native_object, long native_typeface,
1047             int bidiFlags, char[] text, int index, int count, float x, float y, long path) {
1048         // FIXME
1049         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
1050                 "Paint.getTextPath is not supported.", null, null /*data*/);
1051     }
1052 
1053     @LayoutlibDelegate
native_getTextPath(long native_object, long native_typeface, int bidiFlags, String text, int start, int end, float x, float y, long path)1054     /*package*/ static void native_getTextPath(long native_object, long native_typeface,
1055             int bidiFlags, String text, int start, int end, float x, float y, long path) {
1056         // FIXME
1057         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
1058                 "Paint.getTextPath is not supported.", null, null /*data*/);
1059     }
1060 
1061     @LayoutlibDelegate
nativeGetStringBounds(long nativePaint, long native_typeface, String text, int start, int end, int bidiFlags, Rect bounds)1062     /*package*/ static void nativeGetStringBounds(long nativePaint, long native_typeface,
1063             String text, int start, int end, int bidiFlags, Rect bounds) {
1064         nativeGetCharArrayBounds(nativePaint, native_typeface, text.toCharArray(), start,
1065                 end - start, bidiFlags, bounds);
1066     }
1067 
1068     @LayoutlibDelegate
nativeGetCharArrayBounds(long nativePaint, long native_typeface, char[] text, int index, int count, int bidiFlags, Rect bounds)1069     /*package*/ static void nativeGetCharArrayBounds(long nativePaint, long native_typeface,
1070             char[] text, int index, int count, int bidiFlags, Rect bounds) {
1071 
1072         // get the delegate from the native int.
1073         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
1074         if (delegate == null) {
1075             return;
1076         }
1077 
1078         // assert that the typeface passed is actually the one that we had stored.
1079         assert (native_typeface == delegate.mNativeTypeface);
1080 
1081         delegate.measureText(text, index, count, null, 0, bidiFlags).roundOut(bounds);
1082     }
1083 
1084     @LayoutlibDelegate
finalizer(long nativePaint)1085     /*package*/ static void finalizer(long nativePaint) {
1086         sManager.removeJavaReferenceFor(nativePaint);
1087     }
1088 
1089     @LayoutlibDelegate
native_getLetterSpacing(long nativePaint)1090     /*package*/ static float native_getLetterSpacing(long nativePaint) {
1091         // TODO: throw a fidelity warning.
1092         return 0;
1093     }
1094 
1095     @LayoutlibDelegate
native_setLetterSpacing(long nativePaint, float letterSpacing)1096     /*package*/ static void native_setLetterSpacing(long nativePaint, float letterSpacing) {
1097         // pass.
1098     }
1099 
1100     @LayoutlibDelegate
native_setFontFeatureSettings(long nativePaint, String settings)1101     /*package*/ static void native_setFontFeatureSettings(long nativePaint, String settings) {
1102         // pass.
1103     }
1104 
1105     // ---- Private delegate/helper methods ----
1106 
Paint_Delegate()1107     /*package*/ Paint_Delegate() {
1108         reset();
1109     }
1110 
Paint_Delegate(Paint_Delegate paint)1111     private Paint_Delegate(Paint_Delegate paint) {
1112         set(paint);
1113     }
1114 
set(Paint_Delegate paint)1115     private void set(Paint_Delegate paint) {
1116         mFlags = paint.mFlags;
1117         mColor = paint.mColor;
1118         mStyle = paint.mStyle;
1119         mCap = paint.mCap;
1120         mJoin = paint.mJoin;
1121         mTextAlign = paint.mTextAlign;
1122         mTypeface = paint.mTypeface;
1123         mNativeTypeface = paint.mNativeTypeface;
1124         mStrokeWidth = paint.mStrokeWidth;
1125         mStrokeMiter = paint.mStrokeMiter;
1126         mTextSize = paint.mTextSize;
1127         mTextScaleX = paint.mTextScaleX;
1128         mTextSkewX = paint.mTextSkewX;
1129         mXfermode = paint.mXfermode;
1130         mColorFilter = paint.mColorFilter;
1131         mShader = paint.mShader;
1132         mPathEffect = paint.mPathEffect;
1133         mMaskFilter = paint.mMaskFilter;
1134         mRasterizer = paint.mRasterizer;
1135         mHintingMode = paint.mHintingMode;
1136         updateFontObject();
1137     }
1138 
reset()1139     private void reset() {
1140         mFlags = Paint.DEFAULT_PAINT_FLAGS;
1141         mColor = 0xFF000000;
1142         mStyle = Paint.Style.FILL.nativeInt;
1143         mCap = Paint.Cap.BUTT.nativeInt;
1144         mJoin = Paint.Join.MITER.nativeInt;
1145         mTextAlign = 0;
1146         mTypeface = Typeface_Delegate.getDelegate(Typeface.sDefaults[0].native_instance);
1147         mNativeTypeface = 0;
1148         mStrokeWidth = 1.f;
1149         mStrokeMiter = 4.f;
1150         mTextSize = 20.f;
1151         mTextScaleX = 1.f;
1152         mTextSkewX = 0.f;
1153         mXfermode = null;
1154         mColorFilter = null;
1155         mShader = null;
1156         mPathEffect = null;
1157         mMaskFilter = null;
1158         mRasterizer = null;
1159         updateFontObject();
1160         mHintingMode = Paint.HINTING_ON;
1161     }
1162 
1163     /**
1164      * Update the {@link Font} object from the typeface, text size and scaling
1165      */
1166     @SuppressWarnings("deprecation")
updateFontObject()1167     private void updateFontObject() {
1168         if (mTypeface != null) {
1169             // Get the fonts from the TypeFace object.
1170             List<Font> fonts = mTypeface.getFonts(mFontVariant);
1171 
1172             // create new font objects as well as FontMetrics, based on the current text size
1173             // and skew info.
1174             ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
1175             for (Font font : fonts) {
1176                 if (font == null) {
1177                     // If the font is null, add null to infoList. When rendering the text, if this
1178                     // null is reached, a warning will be logged.
1179                     infoList.add(null);
1180                     continue;
1181                 }
1182                 FontInfo info = new FontInfo();
1183                 info.mFont = font.deriveFont(mTextSize);
1184                 if (mTextScaleX != 1.0 || mTextSkewX != 0) {
1185                     // TODO: support skew
1186                     info.mFont = info.mFont.deriveFont(new AffineTransform(
1187                             mTextScaleX, mTextSkewX, 0, 1, 0, 0));
1188                 }
1189                 // The metrics here don't have anti-aliasing set.
1190                 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
1191 
1192                 infoList.add(info);
1193             }
1194 
1195             mFonts = Collections.unmodifiableList(infoList);
1196         }
1197     }
1198 
measureText(char[] text, int index, int count, float[] advances, int advancesIndex, int bidiFlags)1199     /*package*/ RectF measureText(char[] text, int index, int count, float[] advances,
1200             int advancesIndex, int bidiFlags) {
1201         return new BidiRenderer(null, this, text)
1202                 .renderText(index, index + count, bidiFlags, advances, advancesIndex, false);
1203     }
1204 
measureText(char[] text, int index, int count, float[] advances, int advancesIndex, boolean isRtl)1205     /*package*/ RectF measureText(char[] text, int index, int count, float[] advances,
1206             int advancesIndex, boolean isRtl) {
1207         return new BidiRenderer(null, this, text)
1208                 .renderText(index, index + count, isRtl, advances, advancesIndex, false);
1209     }
1210 
getFontMetrics(FontMetrics metrics)1211     private float getFontMetrics(FontMetrics metrics) {
1212         if (mFonts.size() > 0) {
1213             java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
1214             if (metrics != null) {
1215                 // Android expects negative ascent so we invert the value from Java.
1216                 metrics.top = - javaMetrics.getMaxAscent();
1217                 metrics.ascent = - javaMetrics.getAscent();
1218                 metrics.descent = javaMetrics.getDescent();
1219                 metrics.bottom = javaMetrics.getMaxDescent();
1220                 metrics.leading = javaMetrics.getLeading();
1221             }
1222 
1223             return javaMetrics.getHeight();
1224         }
1225 
1226         return 0;
1227     }
1228 
setTextLocale(String locale)1229     private void setTextLocale(String locale) {
1230         mLocale = new Locale(locale);
1231     }
1232 
setFlag(Paint thisPaint, int flagMask, boolean flagValue)1233     private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
1234         // get the delegate from the native int.
1235         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
1236         if (delegate == null) {
1237             return;
1238         }
1239 
1240         if (flagValue) {
1241             delegate.mFlags |= flagMask;
1242         } else {
1243             delegate.mFlags &= ~flagMask;
1244         }
1245     }
1246 }
1247