@@ -2848,7 +2848,7 @@ var Item = Base.extend(Callback, /** @lends Item# */{
28482848 ctx . fillStyle = fillColor . toCanvasStyle ( ctx ) ;
28492849 if ( strokeColor ) {
28502850 ctx . strokeStyle = strokeColor . toCanvasStyle ( ctx ) ;
2851- if ( paper . support . dash && dashArray && dashArray . length ) {
2851+ if ( paper . support . nativeDash && dashArray && dashArray . length ) {
28522852 if ( 'setLineDash' in ctx ) {
28532853 ctx . setLineDash ( dashArray ) ;
28542854 ctx . lineDashOffset = dashOffset ;
@@ -2858,11 +2858,6 @@ var Item = Base.extend(Callback, /** @lends Item# */{
28582858 }
28592859 }
28602860 }
2861- // If the item only defines a strokeColor or a fillColor, draw it
2862- // directly with the globalAlpha set, otherwise we will do it later when
2863- // we composite the temporary canvas.
2864- if ( ! fillColor || ! strokeColor )
2865- ctx . globalAlpha = this . _opacity ;
28662861 } ,
28672862
28682863 // TODO: Implement View into the drawing.
@@ -2891,51 +2886,68 @@ var Item = Base.extend(Callback, /** @lends Item# */{
28912886 // Exclude Raster items since they never draw a stroke and handle
28922887 // opacity by themselves (they also don't call _setStyles)
28932888 var blendMode = this . _blendMode ,
2894- parentCtx , itemOffset , prevOffset ;
2895- if ( blendMode !== 'normal' || this . _opacity < 1
2896- && this . _type !== 'raster' && ( this . _type !== 'path'
2897- || this . hasFill ( ) && this . hasStroke ( ) ) ) {
2889+ opacity = this . _opacity ,
2890+ type = this . _type ,
2891+ nativeBlend = BlendMode . nativeModes [ blendMode ] ,
2892+ // Determine if we can draw directly, or if we need to draw into a
2893+ // separate canvas and then composite onto the main canvas.
2894+ direct = blendMode === 'normal' && opacity === 1
2895+ // If blending natively is possible, see if the type of item
2896+ // and its color settings allow it. A path with only a fill
2897+ // or a stroke can be directly blended, but if it has both,
2898+ // it needs to be drawn into a separate canvas first.
2899+ || ( nativeBlend || opacity < 1 ) && ( type === 'raster'
2900+ || ( type === 'path' || type === 'compound-path' )
2901+ && ! ( this . hasFill ( ) && this . hasStroke ( ) ) ) ,
2902+ mainCtx , itemOffset , prevOffset ;
2903+ if ( ! direct ) {
28982904 // Apply the paren't global matrix to the calculation of correct
28992905 // bounds.
29002906 var bounds = this . getStrokeBounds ( parentMatrix ) ;
29012907 if ( ! bounds . width || ! bounds . height )
29022908 return ;
2903- // Store previous offset and save the parent context, so we can
2904- // draw onto it later
2909+ // Store previous offset and save the main context, so we can
2910+ // draw onto it later.
29052911 prevOffset = param . offset ;
29062912 // Floor the offset and ceil the size, so we don't cut off any
29072913 // antialiased pixels when drawing onto the temporary canvas.
29082914 itemOffset = param . offset = bounds . getTopLeft ( ) . floor ( ) ;
2909- // Set ctx to the context of the temporary canvas,
2910- // so we draw onto it, instead of the parentCtx
2911- parentCtx = ctx ;
2915+ // Set ctx to the context of the temporary canvas, so we draw onto
2916+ // it, instead of the mainCtx.
2917+ mainCtx = ctx ;
29122918 ctx = CanvasProvider . getContext (
29132919 bounds . getSize ( ) . ceil ( ) . add ( new Size ( 1 , 1 ) ) ) ;
29142920 }
29152921 ctx . save ( ) ;
2916- // Translate the context so the topLeft of the item is at (0, 0)
2917- // on the temporary canvas.
2918- if ( parentCtx )
2922+ // If drawing directly, handle opacity and native blending now,
2923+ // otherwise we will do it later when the temporary canvas is composited.
2924+ if ( direct ) {
2925+ ctx . globalAlpha = opacity ;
2926+ if ( nativeBlend )
2927+ ctx . globalCompositeOperation = blendMode ;
2928+ } else {
2929+ // Translate the context so the topLeft of the item is at (0, 0)
2930+ // on the temporary canvas.
29192931 ctx . translate ( - itemOffset . x , - itemOffset . y ) ;
2920- // Apply globalMatrix when blitting into temporary canvas.
2921- ( parentCtx ? globalMatrix : this . _matrix ) . applyToContext ( ctx ) ;
2932+ }
2933+ // Apply globalMatrix when drawing into temporary canvas.
2934+ ( direct ? this . _matrix : globalMatrix ) . applyToContext ( ctx ) ;
29222935 // If we're drawing into a separate canvas and a clipItem is defined for
29232936 // the current rendering loop, we need to draw the clip item again.
2924- if ( parentCtx && param . clipItem )
2937+ if ( ! direct && param . clipItem )
29252938 param . clipItem . draw ( ctx , param . extend ( { clip : true } ) ) ;
29262939 this . _draw ( ctx , param ) ;
29272940 ctx . restore ( ) ;
29282941 transforms . pop ( ) ;
29292942 if ( param . clip )
29302943 ctx . clip ( ) ;
2931- // If a temporary canvas was created before, composite it onto the
2932- // parent canvas:
2933- if ( parentCtx ) {
2944+ // If a temporary canvas was created, composite it onto the main canvas:
2945+ if ( ! direct ) {
29342946 // Use BlendMode.process even for processing normal blendMode with
29352947 // opacity.
2936- BlendMode . process ( blendMode , ctx , parentCtx , this . _opacity ,
2948+ BlendMode . process ( blendMode , ctx , mainCtx , opacity ,
29372949 // Calculate the pixel offset of the temporary canvas to the
2938- // parent canvas.
2950+ // main canvas.
29392951 itemOffset . subtract ( prevOffset ) ) ;
29402952 // Return the temporary context, so it can be reused
29412953 CanvasProvider . release ( ctx ) ;
0 commit comments