//////////////////////////////////////////////////////////////////////////////// // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You under the Apache License, Version 2.0 // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// package mx.core { import flash.display.DisplayObjectContainer; import flash.events.Event; import flash.geom.Point; import flash.system.ApplicationDomain; /** * SpriteAsset is a subclass of the flash.display.Sprite class which * represents vector graphic images that you embed in an application. * It implements the IFlexDisplayObject interface, which makes it * possible for an embedded vector graphic image to be displayed in an Image * control, or to be used as a container background or a component skin. * *

The vector graphic image that you're embedding can be in an SVG file. * You can also embed a sprite symbol that is in a SWF file produced * by Flash. * In both cases, the MXML compiler autogenerates a class that extends * SpriteAsset to represent the embedded vector graphic image.

* *

You don't generally have to use the SpriteAsset class directly * when you write a Flex application. * For example, you can embed a sprite symbol from a SWF file and display * it in an Image control by writing the following:

* *
 *  <mx:Image id="logo" source="@Embed(source='Assets.swf', symbol='Logo')"/>
* *

Or use it as the application's background image in CSS syntax * by writing the following:

* *
 *  <fx:Style>
 *      @namespace mx "library://ns.adobe.com/flex/mx"
 *      mx|Application {
 *          backgroundImage: Embed(source="Assets.swf", symbol='Logo')
 *      }
 *  <fx:Style/>
* *

without having to understand that the MXML compiler has created * a subclass of BitmapAsset for you.

* *

However, it may be useful to understand what is happening * at the ActionScript level. * To embed a vector graphic image in ActionScript, you declare a variable * of type Class, and put [Embed] metadata on it. * For example, you embed a sprite symbol from a SWF file like this:

* *
 *  [Bindable]
 *  [Embed(source="Assets.swf", symbol="Logo")]
 *  private var logoClass:Class;
* *

The MXML compiler notices that the Logo symbol in Assets.swf * is a sprite, autogenerates a subclass of the SpriteAsset class * to represent it, and sets your variable to be a reference to this * autogenerated class. * You can then use this class reference to create instances of the * SpriteAsset using the new operator, and use APIs * of the Sprite class on them:

* *
 *  var logo:SpriteAsset = SpriteAsset(new logoClass());
 *  logo.rotation=45;
* *

However, you rarely need to create SpriteAsset instances yourself * because image-related properties and styles can simply be set to an * image-producing class, and components will create image instances * as necessary. * For example, to display this vector graphic image in an Image control, * you can set the Image's source property to * logoClass. * In MXML you could do this as follows:

* *
 *  <mx:Image id="logo" source="{logoClass}"/>
* * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public class SpriteAsset extends FlexSprite implements IFlexAsset, IFlexDisplayObject, IBorder, ILayoutDirectionElement { include "../core/Version.as"; // Softlink FlexVersion and MatrixUtil to remove dependencies of embeds on // framework classes. This helps to reduce swf size in AS-only projects. private static var FlexVersionClass:Class; private static var MatrixUtilClass:Class; //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructor. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function SpriteAsset() { super(); // Remember initial size as our measured size. _measuredWidth = width; _measuredHeight = height; if (FlexVersionClass == null) { var appDomain:ApplicationDomain = ApplicationDomain.currentDomain; if (appDomain.hasDefinition("mx.core::FlexVersion")) FlexVersionClass = Class(appDomain.getDefinition("mx.core::FlexVersion")); } if (FlexVersionClass && FlexVersionClass["compatibilityVersion"] >= FlexVersionClass["VERSION_4_0"]) this.addEventListener(Event.ADDED, addedHandler); } //-------------------------------------------------------------------------- // // Variables // //-------------------------------------------------------------------------- // Softlink AdvancedLayoutFeatures to remove dependencies of embeds on // framework classes. This helps to reduce swf size in AS-only projects. private var layoutFeaturesClass:Class; private var layoutFeatures:IAssetLayoutFeatures; //-------------------------------------------------------------------------- // // Overridden Properties // //-------------------------------------------------------------------------- //---------------------------------- // x //---------------------------------- /** * @private */ override public function get x():Number { // TODO(hmuller): by default get x returns transform.matrix.tx rounded to the nearest 20th. // should do the same here, if we're returning layoutFeatures.layoutX. return (layoutFeatures == null) ? super.x : layoutFeatures.layoutX; } /** * @private */ override public function set x(value:Number):void { if (x == value) return; if (layoutFeatures == null) { super.x = value; } else { layoutFeatures.layoutX = value; validateTransformMatrix(); } } //---------------------------------- // y //---------------------------------- /** * @private */ override public function get y():Number { return (layoutFeatures == null) ? super.y : layoutFeatures.layoutY; } /** * @private */ override public function set y(value:Number):void { if (y == value) return; if (layoutFeatures == null) { super.y = value; } else { layoutFeatures.layoutY = value; validateTransformMatrix(); } } //---------------------------------- // z //---------------------------------- /** * @private */ override public function get z():Number { return (layoutFeatures == null) ? super.z : layoutFeatures.layoutZ; } /** * @private */ override public function set z(value:Number):void { if (z == value) return; if (layoutFeatures == null) { super.z = value; } else { layoutFeatures.layoutZ = value; validateTransformMatrix(); } } //---------------------------------- // width //---------------------------------- /** * @private */ override public function get width():Number { if (layoutFeatures == null) return super.width; // Return bounding box width in mirroring case var p:Point; if (MatrixUtilClass != null) p = MatrixUtilClass["transformSize"](layoutFeatures.layoutWidth, _height, transform.matrix); return p ? p.x : super.width; } /** * @private */ override public function set width(value:Number):void { if (width == value) return; if (layoutFeatures == null) { super.width = value; } else { layoutFeatures.layoutWidth = value; // Calculate scaleX based on initial width. We set scaleX // here because resizing a BitmapAsset normally would adjust // the scale to match. layoutFeatures.layoutScaleX = measuredWidth != 0 ? value / measuredWidth : 0; validateTransformMatrix(); } } //---------------------------------- // height //---------------------------------- private var _height:Number; /** * @private */ override public function get height():Number { if (layoutFeatures == null) return super.height; // Return bounding box height in mirroring case var p:Point; if (MatrixUtilClass != null) p = MatrixUtilClass["transformSize"](layoutFeatures.layoutWidth, _height, transform.matrix); return p ? p.y : super.height; } /** * @private */ override public function set height(value:Number):void { if (height == value) return; if (layoutFeatures == null) { super.height = value; } else { _height = value; // Calculate scaleY based on initial height. We set scaleY // here because resizing a BitmapAsset normally would adjust // the scale to match. layoutFeatures.layoutScaleY = measuredHeight != 0 ? value / measuredHeight : 0; validateTransformMatrix(); } } //---------------------------------- // rotation //---------------------------------- /** * @private */ override public function get rotationX():Number { return (layoutFeatures == null) ? super.rotationX : layoutFeatures.layoutRotationX; } /** * @private */ override public function set rotationX(value:Number):void { if (rotationX == value) return; if (layoutFeatures == null) { super.rotationX = value; } else { layoutFeatures.layoutRotationX = value; validateTransformMatrix(); } } /** * @private */ override public function get rotationY():Number { return (layoutFeatures == null) ? super.rotationY : layoutFeatures.layoutRotationY; } /** * @private */ override public function set rotationY(value:Number):void { if (rotationY == value) return; if (layoutFeatures == null) { super.rotationY = value; } else { layoutFeatures.layoutRotationY = value; validateTransformMatrix(); } } /** * @private */ override public function get rotationZ():Number { return (layoutFeatures == null) ? super.rotationZ : layoutFeatures.layoutRotationZ; } /** * @private */ override public function set rotationZ(value:Number):void { if (rotationZ == value) return; if (layoutFeatures == null) { super.rotationZ = value; } else { layoutFeatures.layoutRotationZ = value; validateTransformMatrix(); } } /** * @private */ override public function get rotation():Number { return (layoutFeatures == null) ? super.rotation : layoutFeatures.layoutRotationZ; } /** * @private */ override public function set rotation(value:Number):void { // TODO (klin): rotation actually affects width and height as well. if (rotation == value) return; if (layoutFeatures == null) { super.rotation = value; } else { layoutFeatures.layoutRotationZ = value; validateTransformMatrix(); } } //---------------------------------- // scaleX //---------------------------------- /** * @private */ override public function get scaleX():Number { return (layoutFeatures == null) ? super.scaleX : layoutFeatures.layoutScaleX; } /** * @private */ override public function set scaleX(value:Number):void { if (scaleX == value) return; if (layoutFeatures == null) { super.scaleX = value; } else { layoutFeatures.layoutScaleX = value; layoutFeatures.layoutWidth = Math.abs(value) * measuredWidth; validateTransformMatrix(); } } //---------------------------------- // scaleY //---------------------------------- /** * @private */ override public function get scaleY():Number { return (layoutFeatures == null) ? super.scaleY : layoutFeatures.layoutScaleY; } /** * @private */ override public function set scaleY(value:Number):void { if (scaleY == value) return; if (layoutFeatures == null) { super.scaleY = value; } else { layoutFeatures.layoutScaleY = value; _height = Math.abs(value) * measuredHeight; validateTransformMatrix(); } } //---------------------------------- // scaleZ //---------------------------------- /** * @private */ override public function get scaleZ():Number { return (layoutFeatures == null) ? super.scaleZ : layoutFeatures.layoutScaleZ; } /** * @private */ override public function set scaleZ(value:Number):void { if (scaleZ == value) return; if (layoutFeatures == null) { super.scaleZ = value; } else { layoutFeatures.layoutScaleZ = value; validateTransformMatrix(); } } //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- //---------------------------------- // layoutDirection //---------------------------------- // Use "ltr" instead of LayoutDirection.LTR to avoid depending // on that framework class. private var _layoutDirection:String = "ltr"; [Inspectable(category="General", enumeration="ltr,rtl")] /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4.1 */ public function get layoutDirection():String { return _layoutDirection; } public function set layoutDirection(value:String):void { if (value == _layoutDirection) return; _layoutDirection = value; invalidateLayoutDirection(); } //---------------------------------- // measuredHeight //---------------------------------- /** * @private * Storage for the measuredHeight property. */ private var _measuredHeight:Number; /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get measuredHeight():Number { return _measuredHeight; } //---------------------------------- // measuredWidth //---------------------------------- /** * @private * Storage for the measuredWidth property. */ private var _measuredWidth:Number; /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get measuredWidth():Number { return _measuredWidth; } //---------------------------------- // borderMetrics //---------------------------------- /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get borderMetrics():EdgeMetrics { if (scale9Grid == null) { return EdgeMetrics.EMPTY; } else { return new EdgeMetrics(scale9Grid.left, scale9Grid.top, Math.ceil(measuredWidth - scale9Grid.right), Math.ceil(measuredHeight - scale9Grid.bottom)); } } //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4.1 */ public function invalidateLayoutDirection():void { var p:DisplayObjectContainer = parent; // We check the closest parent's layoutDirection property // to create or destroy layoutFeatures if needed. while (p) { if (p is ILayoutDirectionElement) { // mirror is true if our layoutDirection differs from our parent's. var mirror:Boolean = _layoutDirection != null && ILayoutDirectionElement(p).layoutDirection != null && (_layoutDirection != ILayoutDirectionElement(p).layoutDirection); // If our layoutDirection is different from our parent's and if it used to // be the same, create layoutFeatures to handle mirroring. if (mirror && layoutFeatures == null) { initAdvancedLayoutFeatures(); if (layoutFeatures != null) { layoutFeatures.mirror = mirror; validateTransformMatrix(); } } else if (!mirror && layoutFeatures) { // If our layoutDirection is not different from our parent's and if // it used to be different, then recover our matrix and remove layoutFeatures. layoutFeatures.mirror = mirror; validateTransformMatrix(); layoutFeatures = null; } break; } p = p.parent; } } /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function move(x:Number, y:Number):void { this.x = x; this.y = y; } /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function setActualSize(newWidth:Number, newHeight:Number):void { width = newWidth; height = newHeight; } /** * @private */ private function addedHandler(event:Event):void { invalidateLayoutDirection(); } /** * @private * Initializes AdvancedLayoutFeatures for this asset when mirroring. */ private function initAdvancedLayoutFeatures():void { // Get AdvancedLayoutFeatures if it exists. if (layoutFeaturesClass == null) { var appDomain:ApplicationDomain = ApplicationDomain.currentDomain; if (appDomain.hasDefinition("mx.core::AdvancedLayoutFeatures")) layoutFeaturesClass = Class(appDomain.getDefinition("mx.core::AdvancedLayoutFeatures")); // Get MatrixUtil class if it exists if (MatrixUtilClass == null) { if (appDomain.hasDefinition("mx.utils::MatrixUtil")) MatrixUtilClass = Class(appDomain.getDefinition("mx.utils::MatrixUtil")); } } if (layoutFeaturesClass != null) { var features:IAssetLayoutFeatures = new layoutFeaturesClass(); features.layoutScaleX = scaleX; features.layoutScaleY = scaleY; features.layoutScaleZ = scaleZ; features.layoutRotationX = rotationX; features.layoutRotationY = rotationY; features.layoutRotationZ = rotation; features.layoutX = x; features.layoutY = y; features.layoutZ = z; features.layoutWidth = width; // for the mirror transform _height = height; // for backing storage layoutFeatures = features; } } /** * @private * Applies the transform matrix calculated by AdvancedLayoutFeatures * so that this bitmap will not be mirrored if a parent is mirrored. */ private function validateTransformMatrix():void { if (layoutFeatures != null) { if (layoutFeatures.is3D) super.transform.matrix3D = layoutFeatures.computedMatrix3D; else super.transform.matrix = layoutFeatures.computedMatrix; } } } }