1 goog.provide('lime.Renderer.CANVAS');
  2 
  3 goog.require('goog.math.Box.size');
  4 goog.require('goog.math.Size.scaleVec2');
  5 goog.require('lime.Renderer');
  6 
  7 /**
  8 * Canvas renderer. This renders as canvas element or just
  9 * draws on parent context.
 10 * @const
 11 * @type {lime.Renderer}
 12 */
 13 lime.Renderer.CANVAS = new lime.Renderer();
 14 
 15 /**
 16 * Update the DOM tree relations of the element.
 17 * @this {lime.Node}
 18 */
 19 lime.Renderer.CANVAS.updateLayout = function() {};
 20 
 21 /**
 22 * Initalize canvas element and start the drawing process
 23 * @this {lime.Node}
 24 */
 25 lime.Renderer.CANVAS.drawCanvas = function() {
 26     var quality = this.getQuality(),
 27     bounds = this.measureContents(),
 28     rquality = this.relativeQuality_ || 1,
 29     ownquality = rquality / quality,
 30     sizediff,
 31     PADDING = 12;
 32 
 33 
 34     if (!this.domElement) return;
 35 
 36     if (this.boundsCache && this.boundsCache.contains(bounds) &&
 37     (sizediff = this.boundsCache.size().area() / bounds.size().area()) &&
 38     sizediff < 1.6 && sizediff > 0.5) {
 39         //use the cached canvas size
 40         bounds = this.boundsCache;
 41 
 42     }
 43     else {
 44         if (this.staticCanvas != 1 && this.children_.length != 0) {
 45            if(!(this instanceof lime.Scene)){
 46                bounds.expand(PADDING, PADDING, PADDING, PADDING);
 47            }
 48         }
 49     }
 50 
 51 
 52     //clip to director
 53     /* var dir = this.getDirector();
 54     if (this.rotation_ == 0 && dir) {
 55     var fr = dir.getFrame();
 56     var br = dir.localToNode(
 57     new goog.math.Coordinate(fr.right, fr.bottom), this);
 58     var tl = dir.localToNode(
 59     new goog.math.Coordinate(fr.left, fr.top), this);
 60     if (br.x < bounds.right) {
 61     bounds.right = br.x;
 62     }
 63     if (br.y < bounds.bottom) {
 64     bounds.bottom = br.y;
 65     }
 66     if (tl.x > bounds.left) {
 67     bounds.left = tl.x;
 68     }
 69     if (tl.y > bounds.top) {
 70     bounds.top = tl.y;
 71     }
 72     }*/
 73 
 74     this.boundsCache = bounds; //save for later use
 75 
 76     var bsize = bounds.size();
 77     var pxsize = bsize.clone().scale(rquality).ceil();
 78 
 79     if (this.domElement.width != pxsize.width ||
 80         this.domElement.height != pxsize.height) {
 81             this.domElement.width = pxsize.width;
 82             this.domElement.height = pxsize.height;
 83             this.redraw_ = 1;
 84             //   console.log('redraw');
 85         }
 86 
 87 
 88 
 89         var realScale = this.getScale().clone();
 90         if (this.transitionsActive_[lime.Transition.SCALE]) {
 91             realScale = this.transitionsActive_[lime.Transition.SCALE];
 92             //this.redraw_ = 1;
 93         }
 94         if (pxsize.width != 0) {
 95             realScale.scale(bsize.width * ownquality / pxsize.width);
 96         }
 97         else {
 98             realScale.scale(1 / quality);
 99         }
100 
101 
102         var fr = this.getFrame();
103         this.ax = (fr.left - bounds.left) * rquality;
104         this.ay = (fr.top - bounds.top) * rquality;
105 
106 
107         var ap_offset = this.getSize().clone().
108         scaleVec2(this.getAnchorPoint()).scale(rquality);
109 
110         var pos = this.getPosition().clone();
111 
112         if (this.transitionsActive_[lime.Transition.POSITION]) {
113             pos = this.transitionsActive_[lime.Transition.POSITION];
114             //this.redraw_ = 1;
115         }
116 
117         pos.x *= ownquality;
118         pos.y *= ownquality;
119 
120         pos.x -= ap_offset.width + this.ax;
121         pos.y -= ap_offset.height + this.ay;
122 
123         lime.style.setTransformOrigin(this.domElement,
124             (this.ax + ap_offset.width) / pxsize.width * 100,
125             (this.ay + ap_offset.height) / pxsize.height * 100, true);
126 
127         if (!this.transitionsActiveSet_[lime.Transition.POSITION] && !this.transitionsActiveSet_[lime.Transition.SCALE] && !this.transitionsActiveSet_[lime.Transition.ROTATION]) {
128 
129             var rotation = -this.getRotation();
130             if (goog.isDef(this.transitionsActive_[lime.Transition.ROTATION])) {
131                 rotation = -this.transitionsActive_[lime.Transition.ROTATION];
132             }
133             lime.style.setTransform(this.domElement,
134                 new lime.style.Transform().setPrecision(.1).translate(pos.x, pos.y).
135                 scale(realScale.x, realScale.y).rotate(rotation));
136         }
137 
138         if (this.redraw_) {
139             var context = this.domElement.getContext('2d');
140             rquality = this.relativeQuality_ || 1;
141 
142             context.clearRect(0, 0, pxsize.width, pxsize.height);
143             context.save();
144             context.translate(this.ax, this.ay);
145             context.scale(rquality, rquality);
146 
147 
148             var size = this.getSize(), anchor = this.getAnchorPoint();
149 
150             context.translate(size.width * anchor.x, size.height * anchor.y);
151 
152             this.renderer.drawCanvasObject.call(this, context);
153 
154             context.restore();
155             this.redraw_ = 0;
156 
157 
158         }
159     };
160 
161 /**
162 * Update nodes dirty values and call draw after
163 * @this {lime.Node}
164 */
165 lime.Renderer.CANVAS.update = function() {
166 };
167 
168 
169 /**
170 * Draw single object to the canvas context
171 * @param {Object} context Canvas2DContext where to draw.
172 * @this {lime.Node}
173 */
174 lime.Renderer.CANVAS.drawCanvasObject = function(context) {
175 
176     if(!this.inTree_) return;
177 
178     if (this.mask_ != this.activeMask_) {
179         if (this.activeMask_) {
180             lime.Renderer.DOM.removeMask.call(this);
181         }
182 
183         if (this.mask_) {
184             lime.Renderer.DOM.addMask.call(this);
185         }
186     }
187 
188     // if element is mask the only update mask prop and return
189     if (this.maskTarget_) {
190         return;
191     }
192 
193     if (this.hidden_ || this.opacity_ == 0 || this.isMask == 1) {
194         return;
195     }
196 
197     if (this.opacity_ != 1) {
198         context.globalAlpha *= this.opacity_;
199     }
200 
201     if (this.mask_) {
202         lime.Renderer.DOM.calculateMaskPosition.call(this.mask_);
203         var m = this.activeMask_, scale = this.scale_;
204         context.save();
205         context.save();
206         context.translate(m.mPos.x, m.mPos.y);
207         context.rotate(-m.mRot);
208         if (this.needsDomElement) {
209             context.rotate(this.getRotation() * Math.PI / 180);
210         }
211         context.beginPath();
212         context.moveTo(0, 0);
213         context.lineTo(m.mWidth/scale.x, 0);
214         context.lineTo(m.mWidth/scale.x, m.mHeight/scale.y);
215         context.lineTo(0, m.mHeight/scale.y);
216         context.closePath();
217         context.restore();
218         context.clip();
219     }
220 
221 
222     var zero = new goog.math.Coordinate(0, 0);
223 
224     this.renderer.draw.call(this, context);
225 
226     for (var i = 0, child; child = this.children_[i]; i++) {
227         var pos = child.localToParent(zero).clone(), rot = child.getRotation(), scale = child.getScale();
228         context.save();
229         context.translate(pos.x, pos.y);
230         context.scale(scale.x,scale.y);
231 
232         if (rot != 0) {
233             context.rotate(-rot * Math.PI / 180);
234         }
235         this.renderer.drawCanvasObject.call(child, context);
236         context.restore();
237 
238     }
239 
240     if (this.opacity_ != 1) {
241         context.globalAlpha /= this.opacity_;
242     }
243     if (this.activeMask_) {
244         context.restore();
245     }
246 
247 };
248 
249