1////////////////////////////////////////////////////////////////////////////////
2//
3//  ADOBE SYSTEMS INCORPORATED
4//  Copyright 2005-2007 Adobe Systems Incorporated
5//  All Rights Reserved.
6//
7//  NOTICE: Adobe permits you to use, modify, and distribute this file
8//  in accordance with the terms of the license agreement accompanying it.
9//
10////////////////////////////////////////////////////////////////////////////////
11
12package mx.core
13{
14
15import flash.display.BitmapData;
16import flash.display.DisplayObjectContainer;
17import flash.events.Event;
18import flash.geom.Point;
19import flash.system.ApplicationDomain;
20
21/**
22 *  BitmapAsset is a subclass of the flash.display.Bitmap class
23 *  which represents bitmap images that you embed in a Flex application.
24 *  It implements the IFlexDisplayObject interface, which makes it
25 *  possible for an embedded bitmap image to be displayed in an Image control,
26 *  or to be used as a container background or a component skin.
27 *
28 *  <p>The bitmap image that you're embedding can be in a JPEG, GIF,
29 *  or PNG file.
30 *  You can also embed a bitmap symbol that is in a SWF file produced
31 *  by Flash.
32 *  In each of these cases, the MXML compiler autogenerates a class
33 *  that extends BitmapAsset to represent the embedded bitmap image.</p>
34 *
35 *  <p>You don't generally have to use the BitmapAsset class directly
36 *  when you write a Flex application.
37 *  For example, you can embed a GIF file and display the image
38 *  in an Image control by writing the gollowing:</p>
39 *
40 *  <pre>
41 *  &lt;mx:Image id="logo" source="&#64;Embed(source='Logo.gif')"/&gt;</pre>
42 *
43 *  <p>or use it as the application's background image in CSS syntax
44 *  by writing</p>
45 *
46 *  <pre>
47 *  &lt;fx:Style&gt;
48 *      &#64;namespace mx "library://ns.adobe.com/flex/mx"
49 *      mx|Application {
50 *          backgroundImage: Embed(source="Logo.gif")
51 *      }
52 *  &lt;fx:Style/&gt;</pre>
53 *
54 *  <p>without having to understand that the MXML compiler has created
55 *  a subclass of BitmapAsset for you.</p>
56 *
57 *  <p>However, it may be useful to understand what is happening
58 *  at the ActionScript level.
59 *  To embed a bitmap image in ActionScript, you declare a variable
60 *  of type Class, and put <code>[Embed]</code> metadata on it.
61 *  For example, you embed a GIF file like this:</p>
62 *
63 *  <pre>
64 *  [Bindable]
65 *  [Embed(source="Logo.gif")]
66 *  private var logoClass:Class;</pre>
67 *
68 *  <p>The MXML compiler sees the .gif extension, transcodes the GIF data
69 *  into the bitmap format that the player uses, autogenerates
70 *  a subclass of the BitmapAsset class, and sets your variable
71 *  to be a reference to this autogenerated class.
72 *  You can then use this class reference to create instances of the
73 *  BitmapAsset using the <code>new</code> operator, and you can use
74 *  APIs of the BitmapAsset class on them:</p>
75 *
76 *  <pre>
77 *  var logo:BitmapAsset = BitmapAsset(new logoClass());
78 *  logo.bitmapData.noise(4);</pre>
79 *
80 *  <p>However, you rarely need to create BitmapAsset instances yourself
81 *  because image-related properties and styles can simply be set to an
82 *  image-producing class, and components will create image instances
83 *  as necessary.
84 *  For example, to display this image in an Image control, you can
85 *  set the Image's <code>source</code> property to <code>logoClass</code>.
86 *  In MXML you could do this as follows:</p>
87 *
88 *  <pre>
89 *  &lt;mx:Image id="logo" source="{logoClass}"/&gt;</pre>
90 *
91 *  @langversion 3.0
92 *  @playerversion Flash 9
93 *  @playerversion AIR 1.1
94 *  @productversion Flex 3
95 */
96public class BitmapAsset extends FlexBitmap
97                         implements IFlexAsset, IFlexDisplayObject, ILayoutDirectionElement
98{
99    include "../core/Version.as";
100
101    // Softlink FlexVersion and MatrixUtil to remove dependencies of embeds on
102    // framework classes. This helps to reduce swf size in AS-only projects.
103    private static var FlexVersionClass:Class;
104    private static var MatrixUtilClass:Class;
105
106    //--------------------------------------------------------------------------
107    //
108    //  Constructor
109    //
110    //--------------------------------------------------------------------------
111
112    /**
113     *  Constructor.
114     *
115     *  @param bitmapData The data for the bitmap image.
116     *
117     *  @param pixelSnapping Whether or not the bitmap is snapped
118     *  to the nearest pixel.
119     *
120     *  @param smoothing Whether or not the bitmap is smoothed when scaled.
121     *
122     *  @langversion 3.0
123     *  @playerversion Flash 9
124     *  @playerversion AIR 1.1
125     *  @productversion Flex 3
126     */
127    public function BitmapAsset(bitmapData:BitmapData = null,
128                                pixelSnapping:String = "auto",
129                                smoothing:Boolean = false)
130    {
131        super(bitmapData, pixelSnapping, smoothing);
132
133        if (FlexVersionClass == null)
134        {
135            var appDomain:ApplicationDomain = ApplicationDomain.currentDomain;
136            if (appDomain.hasDefinition("mx.core::FlexVersion"))
137                FlexVersionClass = Class(appDomain.getDefinition("mx.core::FlexVersion"));
138        }
139
140        if (FlexVersionClass && FlexVersionClass["compatibilityVersion"] >= FlexVersionClass["VERSION_4_0"])
141            this.addEventListener(Event.ADDED, addedHandler);
142    }
143
144    //--------------------------------------------------------------------------
145    //
146    //  Variables
147    //
148    //--------------------------------------------------------------------------
149
150    // Softlink AdvancedLayoutFeatures to remove dependencies of embeds on
151    // framework classes. This helps to reduce swf size in AS-only projects.
152    private var layoutFeaturesClass:Class;
153    private var layoutFeatures:IAssetLayoutFeatures;
154
155    //--------------------------------------------------------------------------
156    //
157    //  Overridden Properties
158    //
159    //--------------------------------------------------------------------------
160
161    //----------------------------------
162    //  x
163    //----------------------------------
164
165    /**
166     *  @private
167     */
168    override public function get x():Number
169    {
170        // TODO(hmuller): by default get x returns transform.matrix.tx rounded to the nearest 20th.
171        // should do the same here, if we're returning layoutFeatures.layoutX.
172        return (layoutFeatures == null) ? super.x : layoutFeatures.layoutX;
173    }
174
175    /**
176     *  @private
177     */
178    override public function set x(value:Number):void
179    {
180        if (x == value)
181            return;
182
183        if (layoutFeatures == null)
184        {
185            super.x = value;
186        }
187        else
188        {
189            layoutFeatures.layoutX = value;
190            validateTransformMatrix();
191        }
192    }
193
194    //----------------------------------
195    //  y
196    //----------------------------------
197
198    /**
199     *  @private
200     */
201    override public function get y():Number
202    {
203        return (layoutFeatures == null) ? super.y : layoutFeatures.layoutY;
204    }
205
206    /**
207     *  @private
208     */
209    override public function set y(value:Number):void
210    {
211        if (y == value)
212            return;
213
214        if (layoutFeatures == null)
215        {
216            super.y = value;
217        }
218        else
219        {
220            layoutFeatures.layoutY = value;
221            validateTransformMatrix();
222        }
223    }
224
225    //----------------------------------
226    //  z
227    //----------------------------------
228
229    /**
230     *  @private
231     */
232    override public function get z():Number
233    {
234        return (layoutFeatures == null) ? super.z : layoutFeatures.layoutZ;
235    }
236
237    /**
238     *  @private
239     */
240    override public function set z(value:Number):void
241    {
242        if (z == value)
243            return;
244
245        if (layoutFeatures == null)
246        {
247            super.z = value;
248        }
249        else
250        {
251            layoutFeatures.layoutZ = value;
252            validateTransformMatrix();
253        }
254    }
255
256    //----------------------------------
257    //  width
258    //----------------------------------
259
260    /**
261     *  @private
262     */
263    override public function get width():Number
264    {
265        if (layoutFeatures == null)
266            return super.width;
267
268        // Return bounding box width in mirroring case
269        var p:Point;
270        if (MatrixUtilClass != null)
271            p = MatrixUtilClass["transformSize"](layoutFeatures.layoutWidth, _height, transform.matrix);
272
273        return p ? p.x : super.width;
274    }
275
276    /**
277     *  @private
278     */
279    override public function set width(value:Number):void
280    {
281        if (width == value)
282            return;
283
284        if (layoutFeatures == null)
285        {
286            super.width = value;
287        }
288        else
289        {
290            layoutFeatures.layoutWidth = value;
291            // Calculate scaleX based on initial width. We set scaleX
292            // here because resizing a BitmapAsset normally would adjust
293            // the scale to match.
294            layoutFeatures.layoutScaleX = measuredWidth != 0 ? value / measuredWidth : 0;
295            validateTransformMatrix();
296        }
297    }
298
299    //----------------------------------
300    //  height
301    //----------------------------------
302
303    private var _height:Number;
304
305    /**
306     *  @private
307     */
308    override public function get height():Number
309    {
310
311        if (layoutFeatures == null)
312            return super.height;
313
314        // Return bounding box height in mirroring case
315        var p:Point;
316        if (MatrixUtilClass != null)
317            p = MatrixUtilClass["transformSize"](layoutFeatures.layoutWidth, _height, transform.matrix);
318
319        return p ? p.y : super.height;
320    }
321
322    /**
323     *  @private
324     */
325    override public function set height(value:Number):void
326    {
327        if (height == value)
328            return;
329
330        if (layoutFeatures == null)
331        {
332            super.height = value;
333        }
334        else
335        {
336            _height = value;
337            // Calculate scaleY based on initial height. We set scaleY
338            // here because resizing a BitmapAsset normally would adjust
339            // the scale to match.
340            layoutFeatures.layoutScaleY = measuredHeight != 0 ? value / measuredHeight : 0;
341            validateTransformMatrix();
342        }
343    }
344
345    //----------------------------------
346    //  rotation
347    //----------------------------------
348
349    /**
350     *  @private
351     */
352    override public function get rotationX():Number
353    {
354        return (layoutFeatures == null) ? super.rotationX : layoutFeatures.layoutRotationX;
355    }
356
357    /**
358     *  @private
359     */
360    override public function set rotationX(value:Number):void
361    {
362        if (rotationX == value)
363            return;
364
365        if (layoutFeatures == null)
366        {
367            super.rotationX = value;
368        }
369        else
370        {
371            layoutFeatures.layoutRotationX = value;
372            validateTransformMatrix();
373        }
374    }
375    /**
376     *  @private
377     */
378    override public function get rotationY():Number
379    {
380        return (layoutFeatures == null) ? super.rotationY : layoutFeatures.layoutRotationY;
381    }
382
383    /**
384     *  @private
385     */
386    override public function set rotationY(value:Number):void
387    {
388        if (rotationY == value)
389            return;
390
391        if (layoutFeatures == null)
392        {
393            super.rotationY = value;
394        }
395        else
396        {
397            layoutFeatures.layoutRotationY = value;
398            validateTransformMatrix();
399        }
400    }
401
402    /**
403     *  @private
404     */
405    override public function get rotationZ():Number
406    {
407        return (layoutFeatures == null) ? super.rotationZ : layoutFeatures.layoutRotationZ;
408    }
409
410    /**
411     *  @private
412     */
413    override public function set rotationZ(value:Number):void
414    {
415        if (rotationZ == value)
416            return;
417
418        if (layoutFeatures == null)
419        {
420            super.rotationZ = value;
421        }
422        else
423        {
424            layoutFeatures.layoutRotationZ = value;
425            validateTransformMatrix();
426        }
427    }
428
429    /**
430     *  @private
431     */
432    override public function get rotation():Number
433    {
434        return (layoutFeatures == null) ? super.rotation : layoutFeatures.layoutRotationZ;
435    }
436
437    /**
438     *  @private
439     */
440    override public function set rotation(value:Number):void
441    {
442        if (rotation == value)
443            return;
444
445        if (layoutFeatures == null)
446        {
447            super.rotation = value;
448        }
449        else
450        {
451            layoutFeatures.layoutRotationZ = value;
452            validateTransformMatrix();
453        }
454    }
455
456    //----------------------------------
457    //  scaleX
458    //----------------------------------
459
460    /**
461     *  @private
462     */
463    override public function get scaleX():Number
464    {
465        return (layoutFeatures == null) ? super.scaleX : layoutFeatures.layoutScaleX;
466    }
467
468    /**
469     *  @private
470     */
471    override public function set scaleX(value:Number):void
472    {
473        if (scaleX == value)
474            return;
475
476        if (layoutFeatures == null)
477        {
478            super.scaleX = value;
479        }
480        else
481        {
482            layoutFeatures.layoutScaleX = value;
483            layoutFeatures.layoutWidth = Math.abs(value) * measuredWidth;
484            validateTransformMatrix();
485        }
486    }
487
488    //----------------------------------
489    //  scaleY
490    //----------------------------------
491
492    /**
493     *  @private
494     */
495    override public function get scaleY():Number
496    {
497        return (layoutFeatures == null) ? super.scaleY : layoutFeatures.layoutScaleY;
498    }
499
500    /**
501     *  @private
502     */
503    override public function set scaleY(value:Number):void
504    {
505        if (scaleY == value)
506            return;
507
508        if (layoutFeatures == null)
509        {
510            super.scaleY = value;
511        }
512        else
513        {
514            layoutFeatures.layoutScaleY = value;
515            _height = Math.abs(value) * measuredHeight;
516            validateTransformMatrix();
517        }
518    }
519
520    //----------------------------------
521    //  scaleZ
522    //----------------------------------
523
524    /**
525     *  @private
526     */
527    override public function get scaleZ():Number
528    {
529        return (layoutFeatures == null) ? super.scaleZ : layoutFeatures.layoutScaleZ;
530    }
531
532    /**
533     *  @private
534     */
535    override public function set scaleZ(value:Number):void
536    {
537        if (scaleZ == value)
538            return;
539
540        if (layoutFeatures == null)
541        {
542            super.scaleZ = value;
543        }
544        else
545        {
546            layoutFeatures.layoutScaleZ = value;
547            validateTransformMatrix();
548        }
549    }
550
551    //--------------------------------------------------------------------------
552    //
553    //  Properties
554    //
555    //--------------------------------------------------------------------------
556
557    //----------------------------------
558    //  layoutDirection
559    //----------------------------------
560
561    // Use "ltr" instead of LayoutDirection.LTR to avoid depending
562    // on that framework class.
563    private var _layoutDirection:String = "ltr";
564
565    [Inspectable(category="General", enumeration="ltr,rtl")]
566
567    /**
568     *  @inheritDoc
569     *
570     *  @langversion 3.0
571     *  @playerversion Flash 10
572     *  @playerversion AIR 1.5
573     *  @productversion Flex 4.1
574     */
575    public function get layoutDirection():String
576    {
577        return _layoutDirection;
578    }
579
580    public function set layoutDirection(value:String):void
581    {
582        if (value == _layoutDirection)
583            return;
584
585        _layoutDirection = value;
586        invalidateLayoutDirection();
587    }
588
589    //----------------------------------
590    //  measuredHeight
591    //----------------------------------
592
593    /**
594     *  @inheritDoc
595     *
596     *  @langversion 3.0
597     *  @playerversion Flash 9
598     *  @playerversion AIR 1.1
599     *  @productversion Flex 3
600     */
601    public function get measuredHeight():Number
602    {
603        if (bitmapData)
604            return bitmapData.height
605
606        return 0;
607    }
608
609    //----------------------------------
610    //  measuredWidth
611    //----------------------------------
612
613    /**
614     *  @inheritDoc
615     *
616     *  @langversion 3.0
617     *  @playerversion Flash 9
618     *  @playerversion AIR 1.1
619     *  @productversion Flex 3
620     */
621    public function get measuredWidth():Number
622    {
623        if (bitmapData)
624            return bitmapData.width;
625
626        return 0;
627    }
628
629    //--------------------------------------------------------------------------
630    //
631    //  Methods
632    //
633    //--------------------------------------------------------------------------
634
635    /**
636     *  @inheritDoc
637     *
638     *  @langversion 3.0
639     *  @playerversion Flash 10
640     *  @playerversion AIR 1.5
641     *  @productversion Flex 4.1
642     */
643    public function invalidateLayoutDirection():void
644    {
645        var p:DisplayObjectContainer = parent;
646
647        // We check the closest parent's layoutDirection property
648        // to create or destroy layoutFeatures if needed.
649        while (p)
650        {
651            if (p is ILayoutDirectionElement)
652            {
653                // mirror is true if our layoutDirection differs from our parent's.
654                var mirror:Boolean = _layoutDirection != null &&
655                    ILayoutDirectionElement(p).layoutDirection != null &&
656                    (_layoutDirection != ILayoutDirectionElement(p).layoutDirection);
657
658                // If our layoutDirection is different from our parent's and if it used to
659                // be the same, create layoutFeatures to handle mirroring.
660                if (mirror && layoutFeatures == null)
661                {
662                    initAdvancedLayoutFeatures();
663                    if (layoutFeatures != null)
664                    {
665                        layoutFeatures.mirror = mirror;
666                        validateTransformMatrix();
667                    }
668                }
669                else if (!mirror && layoutFeatures)
670                {
671                    // If our layoutDirection is not different from our parent's and if
672                    // it used to be different, then recover our matrix and remove layoutFeatures.
673                    layoutFeatures.mirror = mirror;
674                    validateTransformMatrix();
675                    layoutFeatures = null;
676                }
677
678                break;
679            }
680
681            p = p.parent;
682        }
683    }
684
685    /**
686     *  @inheritDoc
687     *
688     *  @langversion 3.0
689     *  @playerversion Flash 9
690     *  @playerversion AIR 1.1
691     *  @productversion Flex 3
692     */
693    public function move(x:Number, y:Number):void
694    {
695        this.x = x;
696        this.y = y;
697    }
698
699    /**
700     *  @inheritDoc
701     *
702     *  @langversion 3.0
703     *  @playerversion Flash 9
704     *  @playerversion AIR 1.1
705     *  @productversion Flex 3
706     */
707    public function setActualSize(newWidth:Number, newHeight:Number):void
708    {
709        width = newWidth;
710        height = newHeight;
711    }
712
713    /**
714     *  @private
715     */
716    private function addedHandler(event:Event):void
717    {
718        invalidateLayoutDirection();
719    }
720
721    /**
722     *  @private
723     *  Initializes AdvancedLayoutFeatures for this asset when mirroring.
724     */
725    private function initAdvancedLayoutFeatures():void
726    {
727        // Get AdvancedLayoutFeatures if it exists.
728        if (layoutFeaturesClass == null)
729        {
730            var appDomain:ApplicationDomain = ApplicationDomain.currentDomain;
731
732            if (appDomain.hasDefinition("mx.core::AdvancedLayoutFeatures"))
733                layoutFeaturesClass = Class(appDomain.getDefinition("mx.core::AdvancedLayoutFeatures"));
734
735            // Get MatrixUtil class if it exists
736            if (MatrixUtilClass == null)
737            {
738                if (appDomain.hasDefinition("mx.utils::MatrixUtil"))
739                    MatrixUtilClass = Class(appDomain.getDefinition("mx.utils::MatrixUtil"));
740            }
741        }
742
743        if (layoutFeaturesClass != null)
744        {
745            var features:IAssetLayoutFeatures = new layoutFeaturesClass();
746
747            features.layoutScaleX = scaleX;
748            features.layoutScaleY = scaleY;
749            features.layoutScaleZ = scaleZ;
750            features.layoutRotationX = rotationX;
751            features.layoutRotationY = rotationY;
752            features.layoutRotationZ = rotation;
753            features.layoutX = x;
754            features.layoutY = y;
755            features.layoutZ = z;
756            features.layoutWidth = width;  // for the mirror transform
757            _height = height;  // for backing storage
758            layoutFeatures = features;
759        }
760    }
761
762    /**
763     *  @private
764     *  Applies the transform matrix calculated by AdvancedLayoutFeatures
765     *  so that this bitmap will not be mirrored if a parent is mirrored.
766     */
767    private function validateTransformMatrix():void
768    {
769        if (layoutFeatures != null)
770        {
771            if (layoutFeatures.is3D)
772                super.transform.matrix3D = layoutFeatures.computedMatrix3D;
773            else
774                super.transform.matrix = layoutFeatures.computedMatrix;
775        }
776    }
777}
778
779}
780