short flags = 0;
static int MOUSEINSIDE_FLAG = 0x00000001;
static int INVISIBLE_FLAG = 0x00000002;
- static int ABSOLUTE_FLAG = 0x00000004;
+ static int NOTPACKED_FLAG = 0x00000004;
static int HSHRINK_FLAG = 0x00000008;
static int VSHRINK_FLAG = 0x00000010;
static int TILE_FLAG = 0x00000020;
private int col = 0; // FEATURE use a short
private LENGTH contentwidth = 0; // == max(minwidth, textwidth+pad, sum(child.contentwidth) + pad)
private LENGTH contentheight = 0;
+ private LENGTH offset_x = 0;
+ private LENGTH offset_y = 0;
// Rendering Properties ///////////////////////////////////////////////////////////
private VectorGraphics.VectorPath path = null;
private VectorGraphics.Affine transform = null;
+
+ private VectorGraphics.RasterPath rpath = null;
+ private VectorGraphics.Affine rtransform = null;
+
//private VectorGraphics.Paint fill = null;
//private VectorGraphics.Paint stroke = null;
int strokewidth = 1;
/** Checks if the Box's size has changed, dirties it if necessary, and makes sure childrens' sizes are up to date */
void repack() {
if (!needs_reflow) return;
- if (numChildren() == 0) {
- contentwidth = max(textwidth + 2 * hpad, minwidth);
- contentheight = max(textheight + 2 * vpad, minheight);
- if (path != null) {
- contentwidth = max(contentwidth, path.boundingBoxWidth());
- contentheight = max(contentheight, path.boundingBoxHeight());
- }
- return;
- }
+ contentwidth = contentheight = 0;
// --- Phase 0 ----------------------------------------------------------------------
// recurse
// assign children to their row/column positions (assuming constrained columns)
if ((rows == 0 && cols == 0) || (rows != 0 && cols != 0)) throw new Error("rows == " + rows + " cols == " + cols);
//#repeat x/y y/x width/height col/row row/col cols/rows rows/cols colspan/rowspan rowspan/colspan colWidth/rowHeight numRowsInCol/numColsInRow INNER/INNER2 maxwidth/maxheight minwidth/minheight contentwidth/contentheight colMaxWidth/rowMaxHeight OUTER/OUTER2 INNER/INNER2
- if (rows == 0) {
+ if (rows == 0 && numChildren() != 0) {
int[] numRowsInCol = new int[cols]; // the number of cells occupied in each column
Box child = getChild(0);
- for(; child != null && (((child.flags & ABSOLUTE_FLAG) != 0) || ((child.flags & INVISIBLE_FLAG) != 0)); child = child.nextSibling());
+ for(; child != null && (((child.flags & NOTPACKED_FLAG) != 0) || ((child.flags & INVISIBLE_FLAG) != 0)); child = child.nextSibling());
OUTER: for(int row=0; child != null; row++) {
for(int col=0; child != null && col < cols;) {
INNER: while(true) { // scan across the row, looking for an unoccupied gap at least as wide as the child
child.row = row;
col += min(cols, child.colspan);
child = child.nextSibling();
- for(; child != null && (((child.flags & ABSOLUTE_FLAG) != 0) || ((child.flags & INVISIBLE_FLAG) != 0)); child = child.nextSibling());
+ for(; child != null && (((child.flags & NOTPACKED_FLAG) != 0) || ((child.flags & INVISIBLE_FLAG) != 0)); child = child.nextSibling());
}
}
}
// --- Phase 2 ----------------------------------------------------------------------
// compute the min/max sizes of the columns and rows and set our contentwidth
- //#repeat x/y y/x width/height col/row cols/rows colspan/rowspan colWidth/rowHeight maxwidth/maxheight minwidth/minheight contentwidth/contentheight colMaxWidth/rowMaxHeight numCols/numRows hpad/vpad
- contentwidth = 2 * hpad;
- int numCols = cols;
- if (numCols == 0)
+ if (numChildren() != 0) {
+ //#repeat x/y y/x width/height col/row cols/rows colspan/rowspan colWidth/rowHeight maxwidth/maxheight minwidth/minheight contentwidth/contentheight colMaxWidth/rowMaxHeight numCols/numRows hpad/vpad
+ contentwidth = 2 * hpad;
+ int numCols = cols;
+ if (numCols == 0)
+ for(Box child = getChild(0); child != null; child = child.nextSibling())
+ numCols = max(numCols, child.col + child.colspan);
+ LENGTH[] colWidth = new LENGTH[numCols];
for(Box child = getChild(0); child != null; child = child.nextSibling())
- numCols = max(numCols, child.col + child.colspan);
- LENGTH[] colWidth = new LENGTH[numCols];
- for(Box child = getChild(0); child != null; child = child.nextSibling())
- if (!(((child.flags & ABSOLUTE_FLAG) != 0) || ((child.flags & INVISIBLE_FLAG) != 0)))
- colWidth[child.col] = max(colWidth[child.col], child.contentwidth / child.colspan);
- for(int col=0; col<numCols; col++) contentwidth += colWidth[col];
- contentwidth = max(textwidth + 2 * hpad, contentwidth);
- contentwidth = bound(minwidth, contentwidth, maxwidth);
- if (path != null) {
- contentwidth = max(contentwidth, path.boundingBoxWidth());
- contentheight = max(contentheight, path.boundingBoxHeight());
+ if (!(((child.flags & NOTPACKED_FLAG) != 0) || ((child.flags & INVISIBLE_FLAG) != 0)))
+ colWidth[child.col] = max(colWidth[child.col], child.contentwidth / child.colspan);
+ for(int col=0; col<numCols; col++) contentwidth += colWidth[col];
+ contentwidth = max(textwidth + 2 * hpad, contentwidth);
+ contentwidth = bound(minwidth, contentwidth, maxwidth);
+ //#end
}
- //#end
- }
+ offset_x = 0;
+ if ((flags & NOTPACKED_FLAG) == 0) {
+ if (path != null) {
+ if (rpath == null) rpath = path.realize(transform == null ? VectorGraphics.Affine.identity() : transform);
+ if ((flags & HSHRINK_FLAG) != 0) contentwidth = max(contentwidth, rpath.boundingBoxWidth());
+ if ((flags & VSHRINK_FLAG) != 0) contentheight = max(contentheight, rpath.boundingBoxHeight());
+ // FIXME: separate offset_x needed for the path
+ }
+ //#repeat x1/y1 x2/y2 x3/y3 x4/y4 contentwidth/contentheight left/top right/bottom
+ int x1 = transform == null ? 0 : (int)transform.multiply_px(0, 0);
+ int x2 = transform == null ? 0 : (int)transform.multiply_px(contentwidth, 0);
+ int x3 = transform == null ? contentwidth : (int)transform.multiply_px(contentwidth, contentheight);
+ int x4 = transform == null ? contentwidth : (int)transform.multiply_px(0, contentheight);
+ int left = min(min(x1, x2), min(x3, x4));
+ int right = max(max(x1, x2), max(x3, x4));
+ contentwidth = max(contentwidth, right - left);
+ offset_x = -1 * left;
+ //#end
+ }
+ }
+
private void resize(LENGTH x, LENGTH y, LENGTH width, LENGTH height) {
//#end
for(Box child = getChild(0); child != null; child = child.nextSibling()) {
- if (((child.flags & ABSOLUTE_FLAG) != 0) || ((child.flags & INVISIBLE_FLAG) != 0)) continue;
+ if (((child.flags & NOTPACKED_FLAG) != 0) || ((child.flags & INVISIBLE_FLAG) != 0)) continue;
//#repeat x/y y/x width/height col/row cols/rows colspan/rowspan colWidth/rowHeight maxwidth/maxheight minwidth/minheight contentwidth/contentheight colMaxWidth/rowMaxHeight HSHRINK_FLAG/VSHRINK_FLAG numCols/numRows
colWidth[child.col] = max(colWidth[child.col], child.contentwidth / child.colspan);
for(int i=child.col; i<child.col+child.colspan && i<numCols; i++)
for(Box child = getChild(0); child != null; child = child.nextSibling()) {
if ((child.flags & INVISIBLE_FLAG) != 0) continue;
int child_x = 0, child_y = 0, child_width = 0, child_height = 0;
- if ((child.flags & ABSOLUTE_FLAG) != 0) {
+ if ((child.flags & NOTPACKED_FLAG) != 0) {
child_x = child.x;
child_y = child.y;
child_width = ((child.flags & HSHRINK_FLAG) != 0) ? child.contentwidth : min(child.maxwidth, width - child.x - hpad);
//#repeat x/y y/x width/height col/row cols/rows colspan/rowspan colWidth/rowHeight maxwidth/maxheight minwidth/minheight contentwidth/contentheight colMaxWidth/rowMaxHeight HSHRINK_FLAG/VSHRINK_FLAG marginWidth/marginHeight hpad/vpad child_x/child_y child_width/child_height
child_width = 0; for(int i=child.col; i<child.col+child.colspan && i<colWidth.length; i++) child_width += colWidth[i];
diff = bound(child.contentwidth, child_width, ((child.flags & HSHRINK_FLAG) != 0) ? child.contentwidth : child.maxwidth) - child_width;
- child_x = max(hpad, marginWidth / 2); for(int i=0; i<child.col; i++) child_x += colWidth[i];
+ if (transform == null) child_x = max(hpad, marginWidth / 2);
+ for(int i=0; i<child.col; i++) child_x += colWidth[i];
if (diff < 0) child_x += -1 * (diff / 2);
child_width += diff;
//#end
}
if (clipw <= 0 || cliph <= 0) return;
- if ((fillcolor & 0xFF000000) != 0x00000000)
- buf.fillTrapezoid(clipx, clipx + clipw, clipy, clipx, clipx + clipw, clipy + cliph, fillcolor);
+ if (path == null && (fillcolor & 0xFF000000) != 0x00000000) {
+ VectorGraphics.VectorPath path2 = VectorGraphics.parseVectorPath("M0,0H" + width + "V" + height + "H0V0z");
+ path2.realize(a).fill(buf, new VectorGraphics.SingleColorPaint(fillcolor));
+ }
if (image != null)
if ((flags & TILE_FLAG) != 0) renderTiledImage(globalx, globaly, clipx, clipy, clipw, cliph, buf);
renderText(globalx, globaly, clipx, clipy, clipw, cliph, buf);
if (path != null) {
- VectorGraphics.RasterPath rp = path.realize(a);
- if ((strokecolor & 0xff000000) != 0) rp.stroke(buf, 1, strokecolor);
- if ((fillcolor & 0xff000000) != 0) rp.fill(buf, new VectorGraphics.SingleColorPaint(fillcolor));
+ if (rtransform == null) rpath = null;
+ else if (!rtransform.equalsIgnoringTranslation(a)) rpath = null;
+ else {
+ rpath.translate((int)(a.e - rtransform.e), (int)(a.f - rtransform.f));
+ rtransform = a.copy();
+ }
+ if (rpath == null) {
+ rtransform = a;
+ rpath = path.realize(a == null ? VectorGraphics.Affine.identity() : a);
+ }
+ if ((strokecolor & 0xff000000) != 0) rpath.stroke(buf, 1, strokecolor);
+ if ((fillcolor & 0xff000000) != 0) rpath.fill(buf, new VectorGraphics.SingleColorPaint(fillcolor));
}
// now subtract the pad region from the clip region before proceeding
}
for(Box b = getChild(0); b != null; b = b.nextSibling()) {
- a.translate(b.x, b.y);
- b.render(globalx, globaly, clipx, clipy, clipw, cliph, buf, a);
- a.translate(-1 * b.x, -1 * b.y);
+ VectorGraphics.Affine a2 = VectorGraphics.Affine.translate(b.x, b.y);
+ if (transform != null) a2.multiply(transform);
+ a2.multiply(VectorGraphics.Affine.translate(offset_x, offset_y));
+ a2.multiply(a);
+ b.render(globalx, globaly, clipx, clipy, clipw, cliph, buf, a2);
}
}
// Trivial Helper Methods (should be inlined) /////////////////////////////////////////
static final int min(int a, int b) { if (a<b) return a; else return b; }
+ static final float min(float a, float b) { if (a<b) return a; else return b; }
static final double min(double a, double b) { if (a<b) return a; else return b; }
static final int max(int a, int b) { if (a>b) return a; else return b; }
+ static final float max(float a, float b) { if (a>b) return a; else return b; }
static final int min(int a, int b, int c) { if (a<=b && a<=c) return a; else if (b<=c && b<=a) return b; else return c; }
static final int max(int a, int b, int c) { if (a>=b && a>=c) return a; else if (b>=c && b>=a) return b; else return c; }
static final int bound(int a, int b, int c) { if (c < b) return c; if (a > b) return a; return b; }
}
t = t.substring(t.indexOf(')') + 1).trim();
}
+ MARK_FOR_REFLOW_b;
b.dirty();
}
public Object get(Box b) { return b.transform.toString(); }
return new Integer(b.x);
}
public void put(Box b, Object value) {
- if (!((b.flags & ABSOLUTE_FLAG) != 0)) return;
+ if (!((b.flags & NOTPACKED_FLAG) != 0)) return;
int x = stoi(value);
if (x == b.x) return;
b.dirty();
}
}});
- specialBoxProperties.put("absolute", new SpecialBoxProperty() {
- public Object get(Box b) { return ((b.flags & ABSOLUTE_FLAG) != 0) ? Boolean.TRUE : Boolean.FALSE; }
+ specialBoxProperties.put("packed", new SpecialBoxProperty() {
+ public Object get(Box b) { return ((b.flags & NOTPACKED_FLAG) != 0) ? Boolean.TRUE : Boolean.FALSE; }
public void put(Box b, Object value) {
- if (stob(value) == ((b.flags & ABSOLUTE_FLAG) != 0)) return;
- if (stob(value)) b.flags |= ABSOLUTE_FLAG; else b.flags &= ~ABSOLUTE_FLAG;
- if ((b.flags & ABSOLUTE_FLAG) != 0) { b.x = 0; b.y = 0; }
+ if (stob(value) == ((b.flags & NOTPACKED_FLAG) == 0)) return;
+ if (!stob(value)) b.flags |= NOTPACKED_FLAG; else b.flags &= ~NOTPACKED_FLAG;
+ if ((b.flags & NOTPACKED_FLAG) != 0) { b.x = 0; b.y = 0; }
if (b.parent != null) MARK_FOR_REFLOW_b_parent;
} });