Wow - this is awesome - thanks Raju!  Replies below:

Regards,
Max Carlson
OpenLaszlo.org

On 1/31/10 7:42 AM, Raju Bitter wrote:
Henry, Max, I've done some testing to improve the functionality for rounded 
corners in AS3 based runtimes. Currently clipping still uses a rectangle mask 
independent of the cornerradius. I made some modifications to enable clipping. 
Here's a screenshot of the small sample app I used for testing:




I basically use a view with a drop shadow and rounded corners and yellow background. The 
2nd item is the same view class with a red child view, centered and reduced by 12px in 
length and height. The 3rd item is the same yellow view with a child view containing an 
image that's larger then the parent view. All of the first three items use 
clip="true" on the yellow view. The 4th item is the same as the 3rd with 
clipping turned off.

In this process I ran into some thinks that are unclear to me in 
lps/kernel/swf9/LzSprite.as:

1) LzSprite.clip property
Seems to be never set. The method LzSprite#setClip just calls applyMask and 
removeMask. But for clipping rounded corners, we need to access the setting for 
clip in the setCornerradius method. Would it be safe to store that value?

   public function setClip( clip:Boolean ):void {
         // Clip is never stored, but it's need in setCornerradius
         // to check if we have to apply a mask.
         this.clip = clip;
         if (clip) {
             applyMask();
         } else {
             removeMask();
         }
     }

Yes, it should be safe to set the property.

2) Drawing background and LzKernelUtils#rect
When drawing the background you use the method LzKernelUtils#rect. Why didn't 
you use the AS3 Grahipcs#rect method instead?

Mostly for consistency - it's a highly optimized method.

3) Scaling within applyMask()
The rectangle mask MovieClip in applyMask is created with a width of 1px by 1px 
and then scaled based on the width and height
                 ms.graphics.drawRect(0, 0, 1, 1);
                 ms.scaleX = this.lzwidth;
                 ms.scaleY = this.lzheight;
For rounded corners, that approach doesn't work, since we need to take the 
cornerradius value when drawing the mask using drawRoundRect(). Why did you 
choose to scale the mask here instead of directly setting it to lzwidth and 
lzheight? I used this code for creating the mask:
             if (this.cornerradius>  0) {
               ms.graphics.drawRoundRect(0, 0, this.lzwidth, this.lzheight, 
this.cornerradius*2);
             } else {
                 ms.graphics.drawRect(0, 0, 1, 1);
                 ms.scaleX = this.lzwidth;
                 ms.scaleY = this.lzheight;
             }

I suspect scaling is faster than redraws - hence the use of scaling. This looks great!

4) Removing the mask MovieClip child from the LzSprite child list
Within LzSprite#removeMask you call this.removeChild(this.masksprite). I 
detected that after the removeChild call the LzSprite.masksprite still points 
to the same MovieClip object. That's a problem when I try to reapply a mask by 
removing the old one and creating a new (which needs to be done when 
setCornerradius is called and the mask has to be modified). So I explicitly set 
this.masksprite = null to make that work.
     public function removeMask():void {
         if (this.mask != null) {
             this.removeChild(this.masksprite);
             // With add explicitely setting the masksprite to 'null'
             // it will still contain the old sprite reference and
             // applyMask() will fail to create a new mask
             this.masksprite = null;
             this.mask = null;
         }
     }

Gret - good catch there!

5) Setting the cornerradius
When a cornerradius is set, the mask needs to be updated if clip=true. Here's 
the modified code I tested:
     var cornerradius = 0;
     function setCornerRadius(radius) {
         this.cornerradius = radius;
         if (this.clip) {
             this.removeMask();
             this.applyMask();
         }
         this.drawBackground();
     }

Awesome!

With those changes it would be possible to clip the content of a view at the 
view border defined by the cornerradius. But there's a bug somewhere, the app 
renders correctly in SWF10 70-80% of the times, with some views sometimes not 
showing up when the views are clipped or the content still overlapping the mask 
. An interesting fact is that the drop shadow doesn't show up for the clipped 
elements that are visible in that case.

Hmm - I'm not sure why that would be. This seems like a big improvement. Let's get it checked in and diagnose from there. Please send me a changeset when you get a chance!

Here's a screenshot: The 3rd item is not showing up, and in the 2nd item the 
red box is not clipped with the drop shadow missing on the first 2 items. I 
guess there's a timing problem with initialization, where the order of when a 
value is set varies - but you'll probably know much better.






With DHTML there are some other problems, mainly missing browser support for 
clipping based on corner radius settings. I added a comment 
http://jira.openlaszlo.org/jira/browse/LPP-8508 with detailed info. I attached 
a diff for LzSprite.as and a zip file with the example app, if you want to test.

Grr - yeah, there are lots of niggling issues there. I don't think there's much we can do about them, short of filing bugs with the browser manufacturers!

-Max

Reply via email to