Source: fill/frame.js

goog.provide('lime.fill.Frame');

goog.require('lime.fill.Fill');
goog.require('lime.fill.Image');
goog.require('goog.math.Rect');
goog.require('goog.style');
goog.require('goog.cssom');
goog.require('goog.dom.classes');
goog.require('goog.dom');
goog.require('goog.math.Vec2');
goog.require('goog.math.Size');

/**
 * Image fill.
 * @param {string|Image|lime.Sprite} img Image.
 * @param {goog.math.Rect|number} rect Crop frame.
 * @param {goog.math.Vec2=} opt_offset Frame offset.
 * @param {goog.math.Size=} opt_size Frame size.
 * @param {boolean=} opt_rotated Is frame rotated.
 * @constructor
 * @extends lime.fill.Image
 */
lime.fill.Frame = function(img, rect, opt_offset, opt_size, opt_rotated) {
    lime.fill.Image.call(this, img);

    if (goog.isNumber(rect)) {
        rect = new goog.math.Rect(arguments[1], arguments[2], arguments[3], arguments[4]);
        opt_offset = new goog.math.Vec2(0, 0);
        opt_size = new goog.math.Size(rect.width, rect.height);
        opt_rotated = false;
    }

    this.rect_ = rect;
    this.coffset_ = opt_offset;
    this.csize_ = opt_size;
    this.rotated_ = opt_rotated;

    var r = this.rect_,
        key = [this.url_, r.width, r.height, r.left, r.top, this.coffset_.x, this.coffset_.y].join('_');
    if (goog.isDef(this.dataCache_[key])) {
        this.data_ = this.dataCache_[key];
        if (!this.data_.processed) {
            goog.events.listen(this.data_.initializer, 'processed', function() {
                this.dispatchEvent(new goog.events.Event('processed'));
            }, false, this);
        }
    } else {
        this.data_ = {};
        this.data_.processed = false;
        this.data_.initializer = this;
        this.data_.classname = this.getNextCssClass_();
        this.dataCache_[key] = this.data_;

        if (this.USE_CSS_CANVAS) {
            this.ctx = document.getCSSCanvasContext('2d', this.data_.classname, this.csize_.width, this.csize_.height);
        } else {
            //todo: FF4 has support for element backgrounds. probably faster than this png url.
            this.ctx = this.makeCanvas();
        }

        if (this.isLoaded()) {
            this.makeFrameData_();
        } else {
            goog.events.listen(this, goog.events.EventType.LOAD, this.makeFrameData_, false, this);
        }
    }
};
goog.inherits(lime.fill.Frame, lime.fill.Image);

/**
 * Common name for Frame objects
 * @type {string}
 */
lime.fill.Frame.prototype.id = 'frame';

/**
 * @private
 */
lime.fill.Frame.prototype.dataCache_ = {};

/**
 * @type {boolean}
 */
lime.fill.Frame.prototype.USE_CSS_CANVAS = goog.isFunction(document.getCSSCanvasContext);

/**
 * @inheritDoc
 */
lime.fill.Frame.prototype.initForSprite = function(sprite) {

    var size = sprite.getSize();
    if (size.width == 0 && size.height == 0) {
        sprite.setSize(this.csize_.width, this.csize_.height);
    }

    lime.fill.Image.prototype.initForSprite.call(this, sprite);

    if (!this.isProcessed()) {
        goog.events.listen(this, 'processed', function() {
            sprite.setDirty(lime.Dirty.CONTENT);
        }, false, this);
    }

    //switch to canvas if no support
};

lime.fill.Frame.prototype.isProcessed = function() {
    return this.data_ && this.data_.processed;
};

(function() {

    var pfx = 'cvsbg_' + Math.round(Math.random() * 1000) + '_',
        index = 0,
        styleSheet;

    /**
     * @private
     */
    lime.fill.Frame.prototype.getNextCssClass_ = function() {
        index++;
        return pfx + index;
    }

    /**
     * @private
     */
    lime.fill.Frame.prototype.makeFrameData_ = function() {
        this.writeToCanvas(this.ctx);

        if (!this.USE_CSS_CANVAS) {

            var contents = this.cvs.toDataURL("image/png"),
                rule = '.' + this.data_.classname + '{background-image:url(' + contents + ') !important}';
            if (!styleSheet) {
                goog.style.installStyles(rule);
                styleSheet = document.styleSheets[document.styleSheets.length - 1];
            } else {
                // why doesn't addCssRule work in IE9???
                if (goog.userAgent.IE) styleSheet.cssText += rule;
                else goog.cssom.addCssRule(styleSheet, rule);
            }

            // laoding into image to avoid flickery onf firefox firat load
            this.data_.img = goog.dom.createDom('img');
            this.data_.img.src = contents;

        }

        this.data_.processed = true;
        this.dispatchEvent(new goog.events.Event('processed'));

    };

})();

/**
 * @inheritDoc
 */
lime.fill.Frame.prototype.getImageElement = function() {
    if (!this.frameImgCache_) {
        if (this.data_.initializer && this.data_.initializer.frameImgCache_) {
            this.frameImgCache_ = this.data_.initializer.frameImgCache_;
        } else {
            if (!this.cvs) {
                var ctx = this.makeCanvas();
                this.writeToCanvas(ctx);
            }
            this.frameImgCache_ = this.cvs;
        }
    }
    return this.frameImgCache_;
};

lime.fill.Frame.prototype.makeCanvas = function() {
    this.cvs = goog.dom.createDom('canvas');
    var ctx = this.cvs.getContext('2d');
    this.cvs.width = this.csize_.width;
    this.cvs.height = this.csize_.height;
    return ctx;
};

lime.fill.Frame.prototype.writeToCanvas = function(ctx) {
    var r = this.rect_,
        w = r.width,
        h = r.height,
        l = r.left,
        t = r.top,
        ox, oy;
    if (l < 0) {
        w += l;
        l = 0;
    }
    if (t < 0) {
        h += t;
        t = 0;
    }
    if (w + l > this.image_.width) w = this.image_.width - l;
    if (h + t > this.image_.height) h = this.image_.height - t;
    if (this.rotated_) {
        ctx.rotate(-Math.PI * .5);
        ctx.translate(-this.csize_.height, 0);
        ox = this.csize_.height - this.coffset_.y - w;
        oy = this.coffset_.x;
    } else {
        ox = this.coffset_.x;
        oy = this.coffset_.y;
    }

    ctx.drawImage(this.image_, l, t, w, h, ox, oy, w, h);
};

/** @inheritDoc */
lime.fill.Frame.prototype.setDOMStyle = function(domEl, shape) {
    if (this.USE_CSS_CANVAS) {
        domEl.style['background'] = '-webkit-canvas(' + this.data_.classname + ')';
    } else if (this.data_.classname != shape.cvs_background_class_) {
        goog.dom.classes.add(domEl, this.data_.classname);
        domEl.style['background'] = '';
        if (shape.cvs_background_class_)
            goog.dom.classes.remove(domEl, shape.cvs_background_class_);
        shape.cvs_background_class_ = this.data_.classname;
    }

    this.setDOMBackgroundProp_(domEl, shape);
};