@@ -42,12 +42,23 @@ export module ad {
4242 private _borderWidth : number ;
4343 private _cornerRadius : number ;
4444 private _borderColor : number ;
45+ private _clipPath : string ;
4546
4647 constructor ( ) {
4748 super ( ) ;
4849 return global . __native ( this ) ;
4950 }
5051
52+ get clipPath ( ) : string {
53+ return this . _clipPath ;
54+ }
55+ set clipPath ( value : string ) {
56+ if ( this . _clipPath !== value ) {
57+ this . _clipPath = value ;
58+ this . invalidateSelf ( ) ;
59+ }
60+ }
61+
5162 get borderWidth ( ) : number {
5263 return this . _borderWidth ;
5364 }
@@ -101,15 +112,19 @@ export module ad {
101112 let backgroundBoundsF = new android . graphics . RectF ( bounds . left + backoffAntialias , bounds . top + backoffAntialias , bounds . right - backoffAntialias , bounds . bottom - backoffAntialias ) ;
102113
103114 let outerRadius = this . _cornerRadius * this . _density ;
104-
115+
105116 // draw background
106117 if ( this . background . color && this . background . color . android ) {
107118 let backgroundColorPaint = new android . graphics . Paint ( ) ;
108119 backgroundColorPaint . setStyle ( android . graphics . Paint . Style . FILL ) ;
109120 backgroundColorPaint . setColor ( this . background . color . android ) ;
110121 backgroundColorPaint . setAntiAlias ( true ) ;
111122
112- canvas . drawRoundRect ( backgroundBoundsF , outerRadius , outerRadius , backgroundColorPaint ) ;
123+ if ( this . clipPath ) {
124+ drawClipPath ( this . clipPath , canvas , backgroundColorPaint , backgroundBoundsF ) ;
125+ } else {
126+ canvas . drawRoundRect ( backgroundBoundsF , outerRadius , outerRadius , backgroundColorPaint ) ;
127+ }
113128 }
114129
115130 // draw image
@@ -139,21 +154,25 @@ export module ad {
139154 params . posX = params . repeatX ? 0 : params . posX ;
140155 params . posY = params . repeatY ? 0 : params . posY ;
141156
142- let supportsPathOp = android . os . Build . VERSION . SDK_INT >= 19 ;
143- if ( supportsPathOp ) {
144- // Path.Op can be used in API level 19+ to achieve the perfect geometry.
145- let backgroundPath = new android . graphics . Path ( ) ;
146- backgroundPath . addRoundRect ( backgroundBoundsF , outerRadius , outerRadius , android . graphics . Path . Direction . CCW ) ;
147- let backgroundNoRepeatPath = new android . graphics . Path ( ) ;
148- backgroundNoRepeatPath . addRect ( params . posX , params . posY , params . posX + imageWidth , params . posY + imageHeight , android . graphics . Path . Direction . CCW ) ;
149- ( < any > backgroundPath ) . op ( backgroundNoRepeatPath , ( < any > android ) . graphics . Path . Op . INTERSECT ) ;
150- canvas . drawPath ( backgroundPath , backgroundImagePaint ) ;
157+ if ( this . clipPath ) {
158+ drawClipPath ( this . clipPath , canvas , backgroundImagePaint , backgroundBoundsF ) ;
151159 } else {
152- // Clipping here will not be antialiased but at least it won't shine through the rounded corners.
153- canvas . save ( ) ;
154- canvas . clipRect ( params . posX , params . posY , params . posX + imageWidth , params . posY + imageHeight ) ;
155- canvas . drawRoundRect ( backgroundBoundsF , outerRadius , outerRadius , backgroundImagePaint ) ;
156- canvas . restore ( ) ;
160+ let supportsPathOp = android . os . Build . VERSION . SDK_INT >= 19 ;
161+ if ( supportsPathOp ) {
162+ // Path.Op can be used in API level 19+ to achieve the perfect geometry.
163+ let backgroundPath = new android . graphics . Path ( ) ;
164+ backgroundPath . addRoundRect ( backgroundBoundsF , outerRadius , outerRadius , android . graphics . Path . Direction . CCW ) ;
165+ let backgroundNoRepeatPath = new android . graphics . Path ( ) ;
166+ backgroundNoRepeatPath . addRect ( params . posX , params . posY , params . posX + imageWidth , params . posY + imageHeight , android . graphics . Path . Direction . CCW ) ;
167+ ( < any > backgroundPath ) . op ( backgroundNoRepeatPath , ( < any > android ) . graphics . Path . Op . INTERSECT ) ;
168+ canvas . drawPath ( backgroundPath , backgroundImagePaint ) ;
169+ } else {
170+ // Clipping here will not be antialiased but at least it won't shine through the rounded corners.
171+ canvas . save ( ) ;
172+ canvas . clipRect ( params . posX , params . posY , params . posX + imageWidth , params . posY + imageHeight ) ;
173+ canvas . drawRoundRect ( backgroundBoundsF , outerRadius , outerRadius , backgroundImagePaint ) ;
174+ canvas . restore ( ) ;
175+ }
157176 }
158177 }
159178
@@ -164,23 +183,29 @@ export module ad {
164183 borderPaint . setColor ( this . _borderColor ) ;
165184 borderPaint . setAntiAlias ( true ) ;
166185
167- if ( outerRadius <= 0 ) {
168- borderPaint . setStyle ( android . graphics . Paint . Style . STROKE ) ;
169- borderPaint . setStrokeWidth ( borderWidth ) ;
170- canvas . drawRect ( middleBoundsF , borderPaint ) ;
171- } else if ( outerRadius >= borderWidth ) {
186+ if ( this . clipPath ) {
172187 borderPaint . setStyle ( android . graphics . Paint . Style . STROKE ) ;
173188 borderPaint . setStrokeWidth ( borderWidth ) ;
174- let middleRadius = Math . max ( 0 , outerRadius - halfBorderWidth ) ;
175- canvas . drawRoundRect ( middleBoundsF , middleRadius , middleRadius , borderPaint ) ;
189+ drawClipPath ( this . clipPath , canvas , borderPaint , backgroundBoundsF ) ;
176190 } else {
177- let borderPath = new android . graphics . Path ( ) ;
178- let borderOuterBoundsF = new android . graphics . RectF ( bounds . left , bounds . top , bounds . right , bounds . bottom ) ;
179- borderPath . addRoundRect ( borderOuterBoundsF , outerRadius , outerRadius , android . graphics . Path . Direction . CCW ) ;
180- let borderInnerBoundsF = new android . graphics . RectF ( bounds . left + borderWidth , bounds . top + borderWidth , bounds . right - borderWidth , bounds . bottom - borderWidth ) ;
181- borderPath . addRect ( borderInnerBoundsF , android . graphics . Path . Direction . CW ) ;
182- borderPaint . setStyle ( android . graphics . Paint . Style . FILL ) ;
183- canvas . drawPath ( borderPath , borderPaint ) ;
191+ if ( outerRadius <= 0 ) {
192+ borderPaint . setStyle ( android . graphics . Paint . Style . STROKE ) ;
193+ borderPaint . setStrokeWidth ( borderWidth ) ;
194+ canvas . drawRect ( middleBoundsF , borderPaint ) ;
195+ } else if ( outerRadius >= borderWidth ) {
196+ borderPaint . setStyle ( android . graphics . Paint . Style . STROKE ) ;
197+ borderPaint . setStrokeWidth ( borderWidth ) ;
198+ let middleRadius = Math . max ( 0 , outerRadius - halfBorderWidth ) ;
199+ canvas . drawRoundRect ( middleBoundsF , middleRadius , middleRadius , borderPaint ) ;
200+ } else {
201+ let borderPath = new android . graphics . Path ( ) ;
202+ let borderOuterBoundsF = new android . graphics . RectF ( bounds . left , bounds . top , bounds . right , bounds . bottom ) ;
203+ borderPath . addRoundRect ( borderOuterBoundsF , outerRadius , outerRadius , android . graphics . Path . Direction . CCW ) ;
204+ let borderInnerBoundsF = new android . graphics . RectF ( bounds . left + borderWidth , bounds . top + borderWidth , bounds . right - borderWidth , bounds . bottom - borderWidth ) ;
205+ borderPath . addRect ( borderInnerBoundsF , android . graphics . Path . Direction . CW ) ;
206+ borderPaint . setStyle ( android . graphics . Paint . Style . FILL ) ;
207+ canvas . drawPath ( borderPath , borderPaint ) ;
208+ }
184209 }
185210 }
186211 }
@@ -209,6 +234,8 @@ export module ad {
209234 ensureBorderDrawable ( ) ;
210235 ensureLazyRequires ( ) ;
211236
237+ var clipPathValue = v . style . _getValue ( style . clipPathProperty ) ;
238+
212239 var backgroundValue = v . style . _getValue ( style . backgroundInternalProperty ) ;
213240 var borderWidth = v . borderWidth ;
214241 var bkg = < any > nativeView . getBackground ( ) ;
@@ -220,7 +247,7 @@ export module ad {
220247 let backgroundColor = bkg . backgroundColor = v . style . _getValue ( style . backgroundColorProperty ) . android ;
221248 bkg . setColorFilter ( backgroundColor , android . graphics . PorterDuff . Mode . SRC_IN ) ;
222249 bkg . backgroundColor = backgroundColor ;
223- } else if ( v . borderWidth !== 0 || v . borderRadius !== 0 || ! backgroundValue . isEmpty ( ) ) {
250+ } else if ( v . borderWidth !== 0 || v . borderRadius !== 0 || ! backgroundValue . isEmpty ( ) || ! clipPathValue . isEmpty ( ) ) {
224251
225252 if ( ! ( bkg instanceof BorderDrawableClass ) ) {
226253 bkg = new BorderDrawableClass ( ) ;
@@ -236,6 +263,7 @@ export module ad {
236263 bkg . cornerRadius = v . borderRadius ;
237264 bkg . borderColor = v . borderColor ? v . borderColor . android : android . graphics . Color . TRANSPARENT ;
238265 bkg . background = backgroundValue ;
266+ bkg . clipPath = clipPathValue ;
239267
240268 if ( getSDK ( ) < 18 ) {
241269 // Switch to software because of unsupported canvas methods if hardware acceleration is on:
@@ -274,3 +302,66 @@ export module ad {
274302 ) ;
275303 }
276304}
305+
306+ function drawClipPath ( clipPath : string , canvas : android . graphics . Canvas , paint : android . graphics . Paint , bounds : android . graphics . RectF ) {
307+ var functionName = clipPath . substring ( 0 , clipPath . indexOf ( "(" ) ) ;
308+ var value = clipPath . replace ( `${ functionName } (` , "" ) . replace ( ")" , "" ) ;
309+
310+ if ( functionName === "rect" ) {
311+ var arr = value . split ( / [ \s ] + / ) ;
312+
313+ var top = common . cssValueToDevicePixels ( arr [ 0 ] , bounds . top ) ;
314+ var left = common . cssValueToDevicePixels ( arr [ 1 ] , bounds . left ) ;
315+ var bottom = common . cssValueToDevicePixels ( arr [ 2 ] , bounds . bottom ) ;
316+ var right = common . cssValueToDevicePixels ( arr [ 3 ] , bounds . right ) ;
317+
318+ canvas . drawRect ( left , top , right , bottom , paint ) ;
319+
320+ } else if ( functionName === "circle" ) {
321+ var arr = value . split ( / [ \s ] + / ) ;
322+
323+ var radius = common . cssValueToDevicePixels ( arr [ 0 ] , ( bounds . width ( ) > bounds . height ( ) ? bounds . height ( ) : bounds . width ( ) ) / 2 ) ;
324+ var y = common . cssValueToDevicePixels ( arr [ 2 ] , bounds . height ( ) ) ;
325+ var x = common . cssValueToDevicePixels ( arr [ 3 ] , bounds . width ( ) ) ;
326+
327+ canvas . drawCircle ( x , y , radius , paint ) ;
328+
329+ } else if ( functionName === "ellipse" ) {
330+ var arr = value . split ( / [ \s ] + / ) ;
331+
332+ var rX = common . cssValueToDevicePixels ( arr [ 0 ] , bounds . right ) ;
333+ var rY = common . cssValueToDevicePixels ( arr [ 1 ] , bounds . bottom ) ;
334+ var cX = common . cssValueToDevicePixels ( arr [ 3 ] , bounds . right ) ;
335+ var cY = common . cssValueToDevicePixels ( arr [ 4 ] , bounds . bottom ) ;
336+
337+ var left = cX - rX ;
338+ var top = cY - rY ;
339+ var right = ( rX * 2 ) + left ;
340+ var bottom = ( rY * 2 ) + top ;
341+
342+ canvas . drawOval ( new android . graphics . RectF ( left , top , right , bottom ) , paint ) ;
343+
344+ } else if ( functionName === "polygon" ) {
345+ var path = new android . graphics . Path ( ) ;
346+ var firstPoint : view . Point ;
347+ var arr = value . split ( / [ , ] + / ) ;
348+ for ( let i = 0 ; i < arr . length ; i ++ ) {
349+ let xy = arr [ i ] . trim ( ) . split ( / [ \s ] + / ) ;
350+ let point : view . Point = {
351+ x : common . cssValueToDevicePixels ( xy [ 0 ] , bounds . width ( ) ) ,
352+ y : common . cssValueToDevicePixels ( xy [ 1 ] , bounds . height ( ) )
353+ } ;
354+
355+ if ( ! firstPoint ) {
356+ firstPoint = point ;
357+ path . moveTo ( point . x , point . y ) ;
358+ }
359+
360+ path . lineTo ( point . x , point . y ) ;
361+ }
362+
363+ path . lineTo ( firstPoint . x , firstPoint . y ) ;
364+
365+ canvas . drawPath ( path , paint ) ;
366+ }
367+ }
0 commit comments