diff --git a/src/item/ChangeFlag.js b/src/item/ChangeFlag.js index f6e1c0ff..91422abe 100644 --- a/src/item/ChangeFlag.js +++ b/src/item/ChangeFlag.js @@ -27,10 +27,12 @@ var ChangeFlag = { // Fill style or stroke color / dash STYLE: 16, // Item attributes: visible, blendMode, locked, name, opacity, clipMask ... - ATTRIBUTE: 32 + ATTRIBUTE: 32, + // Clipping in one of the child items + CLIPPING: 64 }; -// Shortcuts to the ChangeFlag to send to #_changed(), all including appearance +// Shortcuts to often used ChangeFlag values including APPEARANCE var Change = { HIERARCHY: ChangeFlag.HIERARCHY | ChangeFlag.APPEARANCE, GEOMETRY: ChangeFlag.GEOMETRY | ChangeFlag.APPEARANCE, diff --git a/src/item/Group.js b/src/item/Group.js index 15c333d9..e09f7afe 100644 --- a/src/item/Group.js +++ b/src/item/Group.js @@ -74,13 +74,24 @@ var Group = this.Group = Item.extend({ || typeof items[0] !== 'object' ? arguments : items); }, - _getClipMask: function() { - // TODO: Use caching once Change.HIERARCHY is implemented + _changed: function(flags) { + if (flags & (ChangeFlag.HIERARCHY | ChangeFlag.CLIPPING)) { + // Clear cached clip item whenever hierarchy changes + delete this._clipItem; + } + }, + + _getClipItem: function() { + // Allow us to set _clipItem to null when none is found and still return + // it as a defined value without searching again + if (this._clipItem !== undefined) + return this._clipItem; for (var i = 0, l = this._children.length; i < l; i++) { var child = this._children[i]; if (child._clipMask) - return child; + return this._clipItem = child; } + return this._clipItem = null; }, /** @@ -92,7 +103,7 @@ var Group = this.Group = Item.extend({ * @bean */ isClipped: function() { - return !!this._getClipMask(); + return !!this._getClipItem(); }, setClipped: function(clipped) { @@ -103,12 +114,12 @@ var Group = this.Group = Item.extend({ }, draw: function(ctx, param) { - var clipMask = this._getClipMask(); - if (clipMask) - Item.draw(clipMask, ctx, param); + var clipItem = this._getClipItem(); + if (clipItem) + Item.draw(clipItem, ctx, param); for (var i = 0, l = this._children.length; i < l; i++) { var item = this._children[i]; - if (item != clipMask) + if (item != clipItem) Item.draw(item, ctx, param); } } diff --git a/src/item/Item.js b/src/item/Item.js index 21ae1942..b0b12c2c 100644 --- a/src/item/Item.js +++ b/src/item/Item.js @@ -362,12 +362,18 @@ var Item = this.Item = Base.extend({ }, setClipMask: function(clipMask) { - this._clipMask = clipMask; - if (clipMask) { - this.setFillColor(null); - this.setStrokeColor(null); + // On-the-fly conversion to boolean: + if (this._clipMask != (clipMask = !!clipMask)) { + this._clipMask = clipMask; + if (clipMask) { + this.setFillColor(null); + this.setStrokeColor(null); + } + this._changed(Change.ATTRIBUTE); + // Tell the parent the clipping mask has changed + if (this._parent) + this._parent._changed(ChangeFlag.CLIPPING); } - this._changed(Change.ATTRIBUTE); }, _clipMask: false,