protected Size2D arrangeFR(BlockContainer container, Graphics2D g2,
                               RectangleConstraint constraint) {

        Size2D s = arrangeFN(container, g2, constraint);
        if (constraint.getHeightRange().contains(s.height)) {
            return s;   
        }
        else {
            RectangleConstraint c = constraint.toFixedHeight(
                constraint.getHeightRange().constrain(s.getHeight())
            );
            return arrangeFF(container, g2, c);
        }
    }

    /**
     * Arranges the blocks in the container with the overall height and width
     * specified as fixed constraints.
     * 
     * @param container  the container.
     * @param constraint  the constraint.
     * @param g2  the graphics device.
     * 
     * @return The size following the arrangement.
     */
    protected Size2D arrangeFF(BlockContainer container, Graphics2D g2,
                               RectangleConstraint constraint) {

        // TODO: implement this properly
        return arrangeFN(container, g2, constraint);
    }

    /**
     * Arranges the blocks with the overall width and height to fit within 
     * specified ranges.
     * 
     * @param container  the container.
     * @param constraint  the constraint.
     * @param g2  the graphics device.
     * 
     * @return The size after the arrangement.
     */
    protected Size2D arrangeRR(BlockContainer container, Graphics2D g2,
                               RectangleConstraint constraint) {

        // first arrange without constraints, and see if this fits within
        // the required ranges...
        Size2D s1 = arrangeNN(container, g2);
        if (constraint.getWidthRange().contains(s1.width)) {
            return s1;  // TODO: we didn't check the height yet
        }
        else {
            RectangleConstraint c = constraint.toFixedWidth(
                constraint.getWidthRange().getUpperBound()
            );
            return arrangeFR(container, g2, c);
        }
    }
    
    /**
     * Arranges the blocks in the container with a range constraint on the
     * width and a fixed height.
     * 
     * @param container  the container.
     * @param constraint  the constraint.
     * @param g2  the graphics device.
     * 
     * @return The size following the arrangement.
     */
    protected Size2D arrangeRF(BlockContainer container, Graphics2D g2,
                               RectangleConstraint constraint) {

        Size2D s = arrangeNF(container, g2, constraint);
        if (constraint.getWidthRange().contains(s.width)) {
            return s;   
        }
        else {
            RectangleConstraint c = constraint.toFixedWidth(
                constraint.getWidthRange().constrain(s.getWidth())
            );
            return arrangeFF(container, g2, c);
        }
    }

    /**
     * Arranges the block with a range constraint on the width, and no 
     * constraint on the height.
     * 
     * @param container  the container.
     * @param constraint  the constraint.
     * @param g2  the graphics device.
     * 
     * @return The size following the arrangement.
     */
    protected Size2D arrangeRN(BlockContainer container, Graphics2D g2,
                               RectangleConstraint constraint) {
        // first arrange without constraints, then see if the width fits
        // within the required range...if not, call arrangeFN() at max width
        Size2D s1 = arrangeNN(container, g2);
        if (constraint.getWidthRange().contains(s1.width)) {
            return s1;   
        }
        else {
            RectangleConstraint c = constraint.toFixedWidth(
                constraint.getWidthRange().getUpperBound()
            );
            return arrangeFN(container, g2, c);