1 goog.provide('lime.fill.Image');
  2 
  3 goog.require('lime.fill.Fill');
  4 
  5 /**
  6  * Image fill.
  7  * @param {string|Image|lime.Sprite} img Image.
  8  * @constructor
  9  * @extends lime.fill.Fill
 10  */
 11 lime.fill.Image = function(img) {
 12     lime.fill.Fill.call(this);
 13     
 14     /*if ((img instanceof lime.Sprite)) {
 15         sprite.setRenderMode( lime.RenderMode.BACKGROUND_CANVAS );
 16         this.image_ = img;
 17         goog.events.listenOnce(this.image_.eventTarget, 'update',
 18             this.updateHandler_, false, this);
 19     }
 20     else */
 21     
 22     if(img && goog.isFunction(img.data)){
 23         img = img.data();
 24     }
 25     
 26     if (goog.isString(img)) {
 27         this.url_ = img;
 28         if(this.url_.length>50)
 29             this.url_ = this.url_.substr(-50);
 30         if(lime.fill.Image.loadedImages_[this.url_]){
 31             this.image_ = lime.fill.Image.loadedImages_[this.url_];
 32         }
 33         else {
 34             this.image_ = new Image();
 35             this.image_.src = img;
 36         }
 37     }
 38     else {
 39         this.url_ = img.src;
 40         if(this.url_.length>50)
 41             this.url_ = this.url_.substr(-50);
 42         if(lime.fill.Image.loadedImages_[this.url_]){
 43             this.image_ = lime.fill.Image.loadedImages_[this.url_];
 44         }
 45         else {
 46             this.image_ = img;
 47         }
 48         
 49     }
 50     
 51     if (!this.isLoaded()){
 52         this.addLoadHandler_();
 53     }
 54     
 55     lime.fill.Image.loadedImages_[this.url_] = this.image_;
 56     
 57 
 58 };
 59 goog.inherits(lime.fill.Image, lime.fill.Fill);
 60 
 61 /**
 62  * Already loaded image cache to reuse all img objects.
 63  * @private
 64  */
 65 lime.fill.Image.loadedImages_ = {};
 66 
 67 /**
 68  * Common name for Image objects
 69  * @type {string}
 70  */
 71 lime.fill.Image.prototype.id = 'image';
 72 
 73 /**
 74  * @inheritDoc
 75  */
 76 lime.fill.Image.prototype.initForSprite = function(sprite){
 77     var size = sprite.getSize(),that = this;
 78     if(!size.width && !size.height){
 79         if(!this.isLoaded()){
 80         
 81         goog.events.listen(this,goog.events.EventType.LOAD,function(){
 82             var size = this.getSize();
 83             if(!size.width && !size.height){
 84                 this.setSize(that.image_.width,that.image_.height);
 85             }
 86         },false,sprite);
 87         
 88         }
 89         else {
 90         
 91         sprite.setSize(this.image_.width,this.image_.height);
 92             
 93         }
 94     }
 95     
 96     if(!this.isLoaded()){
 97         goog.events.listen(this,goog.events.EventType.LOAD,function(){
 98             sprite.setDirty(lime.Dirty.CONTENT);
 99         },false,this);
100     }
101 };
102 
103 /**
104  * @private
105  */
106 lime.fill.Image.prototype.addLoadHandler_ = function(){
107     goog.events.listen(this.image_, goog.events.EventType.LOAD,
108         this.imageLoadedHandler_, false, this);
109 }
110 
111 /**
112  * Update sprite dimensions after image has been loaded
113  * @param {Event} e Event.
114  * @private
115  */
116 lime.fill.Image.prototype.imageLoadedHandler_ = function(e) {
117     this.dispatchEvent(e);
118 };
119 
120 /**
121  * Return core DOM Image element for the fill.
122  * @return {Element} Image element.
123  */
124 lime.fill.Image.prototype.getImageElement = function(){
125     return this.image_;
126 };
127 
128 /**
129  * Return true if image object has been loaded from network.
130  * @return {boolean} If image has been loaded.
131  */
132 lime.fill.Image.prototype.isLoaded = function(){
133     return this.image_ && this.image_.width && this.image_.height;
134 }
135 
136 /**
137  * Set the drawing size for the fill. Size can also be passed in 
138  * with two numbers.
139  * @param {(goog.math.Size|number)} size Image fill size.
140  * @param {(boolean|number)=} opt_perc If size is relative factor from original.
141  * @return {lime.fill.Image} object itself.
142  */
143 lime.fill.Image.prototype.setSize = function(size,opt_perc){
144     if(goog.isNumber(size)){
145         size = new goog.math.Size(arguments[0],arguments[1]);
146         opt_perc = arguments[2] || false;
147     }
148     this.size_ = size;
149     this.size_perc_ = opt_perc;
150     return this;
151 }
152 
153 /**
154  * Set the offset that defines the drawing start position. Default is top-left(0,0).
155  * @param {goog.math.Coordinate} offset Image fill offset.
156  * @param {boolean=} opt_perc If offset is relative factor from size.
157  * @return {lime.fill.Image} object itself.
158  */
159 lime.fill.Image.prototype.setOffset = function(offset,opt_perc){
160     if(goog.isNumber(offset)){
161         offset = new goog.math.Coordinate(arguments[0],arguments[1]);
162         opt_perc = arguments[2] || false;
163     }
164     this.offset_ = offset;
165     this.offset_perc_ = opt_perc;
166     return this;
167 }
168 
169 lime.fill.Image.prototype.getPixelSizeAndOffset = function(shape){
170     var size = shape.getSize().clone();
171     if(this.size_){
172        if(this.size_perc_){
173            size.width*=this.size_.width;
174            size.height*=this.size_.height;
175        }
176        else {
177            size = this.size_;
178        }
179     }
180     var offset = new goog.math.Coordinate(0,0);
181     if(this.offset_){
182         if(this.offset_perc_){
183             offset.x=size.width*this.offset_.x;
184             offset.y=size.height*this.offset_.y;
185         }
186         else {
187             offset = this.offset_;
188         }
189     }
190     return [size,offset];
191 }
192 
193 
194 /**
195  * Common functionality so it could be reused on Frame
196  * @protected
197  */
198 lime.fill.Image.prototype.setDOMBackgroundProp_ = function(domEl,shape){
199     var so = this.getPixelSizeAndOffset(shape),size=so[0],offset=so[1],q = shape.getRelativeQuality();
200     domEl.style[lime.style.getCSSproperty('BackgroundSize')] = size.width*q+'px '+size.height*q+'px';
201     var stroke =  shape.stroke_?shape.stroke_.width_:0;
202     domEl.style['backgroundPosition'] = (offset.x*q-stroke)+'px '+(offset.y*q-stroke)+'px';
203     //domEl.style['backgroundRepeat'] = 'no-repeat';
204     if (this.qualityRenderer)
205     domEl.style['imageRendering'] = 'optimizeQuality';
206 }
207 
208 /** @inheritDoc */
209 lime.fill.Image.prototype.setDOMStyle = function(domEl,shape) {
210     domEl.style['background'] = 'url(' + this.image_.src + ')';
211     this.setDOMBackgroundProp_(domEl,shape);
212 };
213 
214 lime.fill.Image.prototype.setCanvasStyle = function(context,shape) {
215     var size = shape.getSize(),frame = shape.getFrame();
216     if (!size.width || !size.height) return;
217     try {
218         var img = this.getImageElement();
219         var so = this.getPixelSizeAndOffset(shape),s=so[0],offset=so[1];
220         /* todo: No idea if drawimage() with loops is faster or if the
221            pattern object needs to be cached. Needs to be tested! */
222         var ptrn = context.createPattern(img,'repeat');
223         var aspx = s.width/img.width, aspy =s.height/img.height; 
224         context.save();
225         context.translate(frame.left+offset.x,frame.top+offset.y);
226         context.scale(aspx,aspy);
227         context.fillStyle = ptrn;
228         context.fillRect(-offset.x/aspx,-offset.y/aspy,size.width/aspx, size.height/aspy);
229         context.restore();
230     }catch(e){}
231 };
232