Fix for Bug 503
[org.ibex.core.git] / src / org / ibex / Box.java
index 0e5d2a7..180a652 100644 (file)
@@ -177,9 +177,10 @@ public final class Box extends JSScope implements Scheduler.Task {
         // as external events have occured, check the state of box
         if (texture != null) {
             if (texture.isLoaded) { minwidth = min(texture.width, maxwidth); minheight = min(texture.height, maxheight); }
-            else { JS res = texture.stream; texture = null; throw new JSExn("image not found: "+res); }
+            else { JS res = texture.stream; texture = null; throw new JSExn("image not found: "+res.unclone()); }
+        } else {
+            Log.warn(Box.class, "perform() called with null texture");
         }
-
         MARK_REPACK;
         MARK_REFLOW;
         MARK_RESIZE;
@@ -214,12 +215,10 @@ public final class Box extends JSScope implements Scheduler.Task {
     // static stuff so we don't have to keep reallocating
     private static int[] numRowsInCol = new int[65535];
     private static LENGTH[] colWidth = new LENGTH[65535];
-    private static LENGTH[] colMinWidth = new LENGTH[65535];
     private static LENGTH[] colMaxWidth = new LENGTH[65535];
     private static LENGTH[] rowHeight = new LENGTH[65535];
-    private static LENGTH[] rowMinHeight = new LENGTH[65535];
     private static LENGTH[] rowMaxHeight = new LENGTH[65535];
-    static { for(int i=0; i<rowMaxHeight.length; i++) { rowMaxHeight[i] = MAX_LENGTH; colMaxWidth[i] = MAX_LENGTH; } }
+    static { for(int i=0; i<rowMaxHeight.length; i++) { rowMaxHeight[i] = 0; colMaxWidth[i] = 0; } }
 
     Box nextPackedSibling() { Box b = nextSibling(); return b == null || (b.test(PACKED | VISIBLE)) ? b : b.nextPackedSibling(); }
     Box firstPackedChild() { Box b = getChild(0); return b == null || (b.test(PACKED | VISIBLE)) ? b : b.nextPackedSibling(); }
@@ -247,14 +246,12 @@ public final class Box extends JSScope implements Scheduler.Task {
         }
         //#end
 
-        //#repeat contentwidth/contentheight colMinWidth/rowMinHeight colspan/rowspan col/row cols/rows minwidth/minheight \
-        //        textwidth/textheight maxwidth/maxheight colWidth/rowHeight
+        //#repeat contentwidth/contentheight colWidth/rowHeight colspan/rowspan col/row cols/rows minwidth/minheight \
+        //        textwidth/textheight maxwidth/maxheight
         contentwidth = 0;
-        for(Box child = firstPackedChild(); child != null; child = child.nextPackedSibling()) {
-            colMinWidth[child.col] = max(colMinWidth[child.col], child.contentwidth / child.colspan);
-            colWidth[child.col] = 0;
-        }
-        for(int i=0; i<cols; i++) { contentwidth += colMinWidth[i]; colMinWidth[i] = 0; }
+        for(Box child = firstPackedChild(); child != null; child = child.nextPackedSibling())
+            colWidth[child.col] = max(colWidth[child.col], child.contentwidth / child.colspan);
+        for(int i=0; i<cols; i++) { contentwidth += colWidth[i]; colWidth[i] = 0; }
         contentwidth = bound(minwidth, max(font == null || text == null ? 0 : font.textwidth(text), contentwidth), maxwidth);
         //#end               
     }
@@ -295,34 +292,26 @@ public final class Box extends JSScope implements Scheduler.Task {
 
     void resize_children() {
 
-        int eligible;
         //#repeat col/row colspan/rowspan contentwidth/contentheight x/y width/height colMaxWidth/rowMaxHeight colWidth/rowHeight \
-        //        colMinWidth/rowMinHeight HSHRINK/VSHRINK maxwidth/maxheight cols/rows minwidth/minheight colWidth/rowHeight \
-        //        x_slack/y_slack
+        //        HSHRINK/VSHRINK maxwidth/maxheight cols/rows minwidth/minheight colWidth/rowHeight x_slack/y_slack
         // PHASE 1: compute column min/max sizes
         int x_slack = width;
-        eligible = 0;
         for(int i=0; i<cols; i++) x_slack -= colWidth[i];
         for(Box child = firstPackedChild(); child != null; child = child.nextPackedSibling())
             for(int i=child.col; i < child.col + child.colspan; i++) {
-                colMinWidth[i] = max(colWidth[i], child.contentwidth / child.colspan);
-                colMaxWidth[i] = min(colMaxWidth[i], child.test(HSHRINK) ? child.contentwidth : child.maxwidth) / child.colspan;
-                colWidth[i] = 0;
-                eligible++;
+                x_slack += colWidth[i];
+                colWidth[i] = max(colWidth[i], child.contentwidth / child.colspan);
+                x_slack -= colWidth[i];
+                colMaxWidth[i] = max(colMaxWidth[i], (child.test(HSHRINK) ? child.contentwidth : child.maxwidth) / child.colspan);
             }
         
         // PHASE 2: hand out slack
         for(int startslack = 0; x_slack > 0 && cols > 0 && startslack != x_slack;) {
-            if (eligible == 0) break;
-            int increment = x_slack / eligible;
-            eligible = 0;
+            int increment = max(1, x_slack / cols);
             startslack = x_slack;
             for(short col=0; col < cols; col++) {
                 // FIXME: double check this
                 int diff = min(min(colMaxWidth[col], colWidth[col] + increment) - colWidth[col], x_slack);
-                if (colWidth[col] + diff < colMinWidth[col]) diff = colMinWidth[col] - colWidth[col];
-                if (diff == 0) continue;
-                eligible++;
                 x_slack -= diff;
                 colWidth[col] += diff;
             }
@@ -359,8 +348,8 @@ public final class Box extends JSScope implements Scheduler.Task {
         }
 
         // cleanup
-        for(int i=0; i<cols; i++) { colWidth[i] = 0; colMaxWidth[i] = MAX_LENGTH; }
-        for(int i=0; i<rows; i++) { rowHeight[i] = 0; rowMaxHeight[i] = MAX_LENGTH; }
+        for(int i=0; i<cols; i++) { colWidth[i] = 0; colMaxWidth[i] = 0; }
+        for(int i=0; i<rows; i++) { rowHeight[i] = 0; rowMaxHeight[i] = 0; }
 
         for(Box child = getChild(0); child != null; child = child.nextSibling())
             if (test(VISIBLE))
@@ -378,10 +367,9 @@ public final class Box extends JSScope implements Scheduler.Task {
         int globaly = parenty + (parent == null ? 0 : y);
 
         // intersect the x,y,w,h rendering window with ourselves; quit if it's empty
-
         if (test(CLIP)) {
-            cx1 = max(cx1, parent == null ? 0 : globalx);
-            cy1 = max(cy1, parent == null ? 0 : globaly);
+            cx1 = max(cx1, globalx);
+            cy1 = max(cy1, globaly);
             cx2 = min(cx2, globalx + width);
             cy2 = min(cy2, globaly + height);
             if (cx2 <= cx1 || cy2 <= cy1) return;
@@ -557,15 +545,35 @@ public final class Box extends JSScope implements Scheduler.Task {
         case "Minimized": if (parent == null && getSurface() != null) getSurface().minimized = toBoolean(value);  // FEATURE
         case "Maximized": if (parent == null && getSurface() != null) getSurface().maximized = toBoolean(value);  // FEATURE
         case "Close": if (parent == null && getSurface() != null) getSurface().dispose(true);
-        case "redirect": if (redirect == this) redirect = (Box)value; else Log.info(this, "redirect can only be set once");
+        case "redirect":
+            for(Box cur = (Box)value; cur != null; cur = cur.parent)
+                if (cur == redirect) {
+                    redirect = (Box)value;
+                    return;
+                }
+            JS.error("redirect can only be set to a descendant of its current value");
         case "font":
             if(!(value instanceof Stream)) throw new JSExn("You can only put streams to the font property");
             font = value == null ? null : Font.getFont((Stream)value, font == null ? 10 : font.pointsize);
             MARK_RESIZE;
             dirty();
         case "fontsize": font = Font.getFont(font == null ? null : font.stream, toInt(value)); MARK_RESIZE; dirty();
-        case "x": if (parent==null && Surface.fromBox(this)!=null) { CHECKSET_INT(x); } else { if (test(PACKED) && parent != null) return; dirty(); CHECKSET_INT(ax); dirty(); MARK_RESIZE; dirty(); }
-        case "y": if (parent==null && Surface.fromBox(this)!=null) { CHECKSET_INT(y); } else { if (test(PACKED) && parent != null) return; dirty(); CHECKSET_INT(ay); dirty(); MARK_RESIZE; dirty(); }
+        case "x": if (parent==null && Surface.fromBox(this)!=null) {
+            CHECKSET_INT(x);
+        } else {
+            if (test(PACKED) && parent != null) return;
+            dirty(); CHECKSET_INT(ax);
+            dirty(); MARK_RESIZE;
+            dirty();
+        }
+        case "y": if (parent==null && Surface.fromBox(this)!=null) {
+            CHECKSET_INT(y);
+        } else {
+            if (test(PACKED) && parent != null) return;
+            dirty(); CHECKSET_INT(ay);
+            dirty(); MARK_RESIZE;
+            dirty();
+        }
         case "titlebar":
             if (getSurface() != null && value != null) getSurface().setTitleBarText(JS.toString(value));
             super.put(name,value);