66import android .graphics .DashPathEffect ;
77import android .graphics .Matrix ;
88import android .graphics .Paint ;
9+ import android .graphics .PointF ;
910import android .graphics .PorterDuff ;
1011import android .graphics .PorterDuffXfermode ;
1112import android .graphics .Rect ;
1213import android .graphics .RectF ;
1314import android .graphics .Typeface ;
14-
15- import androidx .annotation .ColorInt ;
16- import androidx .annotation .NonNull ;
17- import androidx .annotation .Nullable ;
18- import androidx .core .graphics .ColorUtils ;
19-
15+ import android .graphics .Xfermode ;
2016import android .text .TextPaint ;
2117import android .util .Log ;
2218
19+ import com .myscript .iink .GLRenderer ;
20+ import com .myscript .iink .ParameterSet ;
2321import com .myscript .iink .graphics .Color ;
2422import com .myscript .iink .graphics .FillRule ;
2523import com .myscript .iink .graphics .ICanvas ;
2624import com .myscript .iink .graphics .IPath ;
25+ import com .myscript .iink .graphics .InkPoints ;
2726import com .myscript .iink .graphics .LineCap ;
2827import com .myscript .iink .graphics .LineJoin ;
29- import com .myscript .iink .graphics .Point ;
3028import com .myscript .iink .graphics .Style ;
3129import com .myscript .iink .graphics .Transform ;
3230
33- import java .util .List ;
3431import java .util .ArrayList ;
32+ import java .util .Collections ;
33+ import java .util .List ;
3534import java .util .Map ;
3635import java .util .Objects ;
3736
37+ import androidx .annotation .ColorInt ;
38+ import androidx .annotation .NonNull ;
39+ import androidx .annotation .Nullable ;
40+ import androidx .core .graphics .ColorUtils ;
41+
3842public class Canvas implements ICanvas
3943{
4044
4145 private static final Style DEFAULT_SVG_STYLE = new Style ();
46+ private static final PorterDuffXfermode xferModeSrcOver = new PorterDuffXfermode (PorterDuff .Mode .SRC_OVER );
4247
4348 @ Nullable
4449 private android .graphics .Canvas canvas ;
@@ -77,6 +82,9 @@ public class Canvas implements ICanvas
7782 @ Nullable
7883 private final ImageLoader imageLoader ;
7984 private final OfflineSurfaceManager offlineSurfaceManager ;
85+ @ Nullable
86+ private GLRenderer glRenderer ;
87+ private boolean keepGLRenderer = false ;
8088
8189 private boolean clearOnStartDraw = true ;
8290
@@ -85,7 +93,7 @@ public class Canvas implements ICanvas
8593 private final Map <String , Typeface > typefaceMap ;
8694
8795 private float [] dashArray ;
88- private int dashOffset = 0 ;
96+ private float dashOffset = 0 ;
8997
9098 private final float xdpi ;
9199 private final float ydpi ;
@@ -95,7 +103,37 @@ public class Canvas implements ICanvas
95103 @ NonNull
96104 private final Matrix pointScaleMatrix ;
97105
98- public Canvas (@ Nullable android .graphics .Canvas canvas , Map <String , Typeface > typefaceMap , ImageLoader imageLoader , @ Nullable OfflineSurfaceManager offlineSurfaceManager , float xdpi , float ydpi )
106+ public static class ExtraBrushConfig
107+ {
108+ @ NonNull
109+ public final String baseName ;
110+ @ NonNull
111+ public final Bitmap stampBitmap ;
112+ @ Nullable
113+ public final Bitmap backgroundBitmap ;
114+ @ NonNull
115+ public final ParameterSet config ;
116+
117+ public ExtraBrushConfig (@ NonNull String baseName , @ NonNull Bitmap stampBitmap , @ Nullable Bitmap backgroundBitmap , @ NonNull ParameterSet config )
118+ {
119+ this .baseName = baseName ;
120+ this .stampBitmap = stampBitmap ;
121+ this .backgroundBitmap = backgroundBitmap ;
122+ this .config = config ;
123+ }
124+ }
125+
126+ public Canvas (@ Nullable android .graphics .Canvas canvas , Map <String , Typeface > typefaceMap , ImageLoader imageLoader , float xdpi , float ydpi )
127+ {
128+ this (canvas , Collections .emptyList (), typefaceMap , imageLoader , null , xdpi , ydpi );
129+ }
130+
131+ public Canvas (@ Nullable android .graphics .Canvas canvas , @ NonNull List <ExtraBrushConfig > extraBrushConfigs , Map <String , Typeface > typefaceMap , ImageLoader imageLoader , float xdpi , float ydpi )
132+ {
133+ this (canvas , extraBrushConfigs , typefaceMap , imageLoader , null , xdpi , ydpi );
134+ }
135+
136+ public Canvas (@ Nullable android .graphics .Canvas canvas , @ NonNull List <ExtraBrushConfig > extraBrushConfigs , Map <String , Typeface > typefaceMap , ImageLoader imageLoader , @ Nullable OfflineSurfaceManager offlineSurfaceManager , float xdpi , float ydpi )
99137 {
100138 this .canvas = canvas ;
101139 this .typefaceMap = typefaceMap ;
@@ -104,7 +142,14 @@ public Canvas(@Nullable android.graphics.Canvas canvas, Map<String, Typeface> ty
104142 this .xdpi = xdpi ;
105143 this .ydpi = ydpi ;
106144
107- clips = new ArrayList <String >();
145+ if (!extraBrushConfigs .isEmpty () && GLRenderer .isDeviceSupported ())
146+ {
147+ glRenderer = new GLRenderer ();
148+ for (ExtraBrushConfig config : extraBrushConfigs )
149+ glRenderer .configureBrush (config .baseName , config .stampBitmap , config .backgroundBitmap , config .config );
150+ }
151+
152+ clips = new ArrayList <>();
108153
109154 strokePaint = new Paint (Paint .ANTI_ALIAS_FLAG );
110155 strokePaint .setStyle (Paint .Style .STROKE );
@@ -138,9 +183,13 @@ public Canvas(@Nullable android.graphics.Canvas canvas, Map<String, Typeface> ty
138183 applyStyle (DEFAULT_SVG_STYLE );
139184 }
140185
141- public Canvas ( @ Nullable android . graphics . Canvas canvas , Map < String , Typeface > typefaceMap , ImageLoader imageLoader , float xdpi , float ydpi )
186+ public void destroy ( )
142187 {
143- this (canvas , typefaceMap , imageLoader , null , xdpi , ydpi );
188+ if (glRenderer != null )
189+ {
190+ glRenderer .destroy ();
191+ glRenderer = null ;
192+ }
144193 }
145194
146195 public void setCanvas (@ NonNull android .graphics .Canvas canvas )
@@ -153,6 +202,11 @@ public void setClearOnStartDraw(boolean clearOnStartDraw)
153202 this .clearOnStartDraw = clearOnStartDraw ;
154203 }
155204
205+ public void setKeepGLRenderer (boolean keepGLRenderer )
206+ {
207+ this .keepGLRenderer = keepGLRenderer ;
208+ }
209+
156210 private void applyStyle (@ NonNull Style style )
157211 {
158212 setStrokeColor (style .getStrokeColor ());
@@ -279,6 +333,7 @@ public void setStrokeDashArray(float[] strokeDashArray)
279333 @ Override
280334 public void setStrokeDashOffset (float strokeDashOffset )
281335 {
336+ dashOffset = strokeDashOffset ;
282337 if (dashArray != null )
283338 strokePaint .setPathEffect (new DashPathEffect (dashArray , dashOffset ));
284339 else
@@ -347,6 +402,12 @@ public void startDraw(int x, int y, int width, int height)
347402 @ Override
348403 public void endDraw ()
349404 {
405+ if (!keepGLRenderer && glRenderer != null )
406+ {
407+ glRenderer .destroy ();
408+ glRenderer = null ;
409+ }
410+
350411 Objects .requireNonNull (canvas );
351412 canvas .restore ();
352413 }
@@ -412,6 +473,61 @@ public void drawPath(@NonNull IPath ipath)
412473 }
413474 }
414475
476+ @ Override
477+ public boolean isExtraBrushSupported (@ NonNull String brushName )
478+ {
479+ return glRenderer != null && glRenderer .isBrushSupported (brushName );
480+ }
481+
482+ @ Override
483+ public void drawStrokeWithExtraBrush (@ NonNull InkPoints inkPoints , int temporaryPoints ,
484+ float strokeWidth , @ NonNull String brushName , boolean fullStroke , long id )
485+ {
486+ Objects .requireNonNull (canvas );
487+
488+ if (!isExtraBrushSupported (brushName ))
489+ return ;
490+
491+ if (inkPoints .x .length == 0 || strokeWidth <= 0.f || android .graphics .Color .alpha (fillPaint .getColor ()) == 0 )
492+ return ;
493+
494+ if (!glRenderer .isInitialized ())
495+ {
496+ glRenderer .initialize (keepGLRenderer , canvas .getWidth (), canvas .getHeight (), xdpi , ydpi );
497+ }
498+
499+ Xfermode xfm = fillPaint .getXfermode ();
500+
501+ try
502+ {
503+ canvas .setMatrix (null ); // GLRenderer works with pixels
504+ fillPaint .setXfermode (xferModeSrcOver );
505+
506+ PointF strokeOrigin = glRenderer .drawStroke (inkPoints , temporaryPoints , transformValues , brushName , fullStroke , id , strokeWidth , fillPaint );
507+ Bitmap strokeBitmap = glRenderer .saveStroke ();
508+ if (strokeBitmap != null )
509+ canvas .drawBitmap (strokeBitmap , strokeOrigin .x , strokeOrigin .y , fillPaint );
510+
511+ if (temporaryPoints > 0 )
512+ {
513+ PointF temporaryOrigin = glRenderer .drawTemporary (inkPoints , temporaryPoints , transformValues , brushName , strokeWidth , fillPaint );
514+ Bitmap temporaryBitmap = glRenderer .saveTemporary ();
515+ if (temporaryBitmap != null )
516+ canvas .drawBitmap (temporaryBitmap , temporaryOrigin .x , temporaryOrigin .y , fillPaint );
517+ }
518+ }
519+ catch (Exception e )
520+ {
521+ Log .e ("Canvas" , "Error trying to draw stroke with extra brush: " + e .getMessage (), e );
522+ }
523+ finally
524+ {
525+ // restore
526+ fillPaint .setXfermode (xfm );
527+ canvas .setMatrix (transformMatrix );
528+ }
529+ }
530+
415531 @ Override
416532 public void drawRectangle (float x , float y , float width , float height )
417533 {
0 commit comments