diff -r 55e988390a0f -r 6f18188702fc javafx-ui-common/src/com/sun/javafx/css/parser/CSSParser.java --- a/javafx-ui-common/src/com/sun/javafx/css/parser/CSSParser.java Fri Jan 18 00:09:25 2013 +0100 +++ b/javafx-ui-common/src/com/sun/javafx/css/parser/CSSParser.java Fri Jan 18 00:39:18 2013 +0100 @@ -2391,6 +2391,10 @@ private final static ParsedValueImpl ONE_HUNDRED_PERCENT = new ParsedValueImpl(new Size(100f, SizeUnits.PERCENT), null); + private static boolean isPositionKeyWord(String value) { + return "center".equalsIgnoreCase(value) || "top".equalsIgnoreCase(value) || "bottom".equalsIgnoreCase(value) || "left".equalsIgnoreCase(value) || "right".equalsIgnoreCase(value); + } + /* * http://www.w3.org/TR/css3-background/#the-background-position * @@ -2428,228 +2432,283 @@ Term termFour = (termThree != null) ? termThree.nextInSeries : null; Token valueFour = (termFour != null) ? termFour.token : null; + // are the horizontal and vertical exchanged + if( valueOne != null && valueTwo != null && valueThree == null && valueFour == null ) { + // 2 values filled + String v1 = valueOne.getText(); + String v2 = valueTwo.getText(); + if( ("top".equals(v1) || "bottom".equals(v1)) + && ("left".equals(v2) || "right".equals(v2) || "center".equals(v2)) ) { + { + Token tmp = valueTwo; + valueTwo = valueOne; + valueOne = tmp; + } + + { + Term tmp = termTwo; + termTwo = termOne; + termOne = tmp; + } + } + } else if( valueOne != null && valueTwo != null && valueThree != null ) { + Term[] termArray = null; + Token[] tokeArray = null; + // 4 values filled + if( valueFour != null ) { + if( ("top".equals(valueOne.getText()) || "bottom".equals(valueOne.getText())) + && ("left".equals(valueThree.getText()) || "right".equals(valueThree.getText())) ) { + // e.g. top 50 left 20 + termArray = new Term[] { termThree, termFour, termOne, termTwo }; + tokeArray = new Token[] { valueThree, valueFour, valueOne, valueTwo }; + } + } else { + if( ("top".equals(valueOne.getText()) || "bottom".equals(valueOne.getText())) ) { + if( ("left".equals(valueTwo.getText()) || "right".equals(valueTwo.getText())) ) { + // e.g. top left 50 + termArray = new Term[] { termTwo, termThree, termOne, null }; + tokeArray = new Token[] { valueTwo, valueThree, valueOne, null }; + } else { + // e.g. top 50 left + termArray = new Term[] { termThree, termOne, termTwo, null }; + tokeArray = new Token[] { valueThree, valueOne, valueTwo, null }; + } + } + } + + if( termArray != null ) { + termOne = termArray[0]; + termTwo = termArray[1]; + termThree = termArray[2]; + termFour = termArray[3]; + + valueOne = tokeArray[0]; + valueTwo = tokeArray[1]; + valueThree = tokeArray[2]; + valueFour = tokeArray[3]; + } + } + + ParsedValueImpl top, right, bottom, left; top = right = bottom = left = ZERO_PERCENT; - - // http://www.w3.org/TR/css3-background/#the-background-position states: - // If three or four values are given, then each or - // represents an offset and must be preceded by a keyword, which specifies - // from which edge the offset is given. - if (valueTwo != null && valueThree != null) { - - // - // to make this a little easier, if there are only three values, - // the values are rearranged so that valueOne and valueThree are - // the identifiers. So, if valueTwo is an identifier, everything - // has to move. - // - if (valueTwo.getType() == CSSLexer.IDENT) { - if (valueFour != null) - error(termTwo, "Unexpected value in \'\'"); - - valueFour = valueThree; termFour = termThree; - valueThree = valueTwo; termThree = termTwo; - valueTwo = null; termTwo = null; - } - - // Now valueTwo and valueFour are either null or a size... - - if (valueOne.getType() != CSSLexer.IDENT || - valueOne.getText() == null || - valueOne.getText().isEmpty()) - error(termOne, "Expected \'center\', \'left\' or \'right\'"); - - ParsedValueImpl sizeTwo = null; - if (valueTwo != null && isSize(valueTwo)) { - sizeTwo = parseSize(termTwo); + { + if(valueOne == null && valueTwo == null && valueThree == null && valueFour == null) { + error(term, "No value found for background-position"); + } else if( valueOne != null && valueTwo == null && valueThree == null && valueFour == null ) { + // Only one value + String v1 = valueOne.getText(); + + if( "center".equals(v1) ) { + left = FIFTY_PERCENT; + right = ZERO_PERCENT; + + top = FIFTY_PERCENT; + bottom = ZERO_PERCENT; + + } else if("left".equals(v1)) { + left = ZERO_PERCENT; + right = ZERO_PERCENT; + + top = FIFTY_PERCENT; + bottom = ZERO_PERCENT; + + } else if( "right".equals(v1) ) { + left = ONE_HUNDRED_PERCENT; + right = ZERO_PERCENT; + + top = FIFTY_PERCENT; + bottom = ZERO_PERCENT; + + } else if( "top".equals(v1) ) { + left = FIFTY_PERCENT; + right = ZERO_PERCENT; + + top = ZERO_PERCENT; + bottom = ZERO_PERCENT; + + } else if( "bottom".equals(v1) ) { + left = FIFTY_PERCENT; + right = ZERO_PERCENT; + + top = ONE_HUNDRED_PERCENT; + bottom = ZERO_PERCENT; + } else { + left = parseSize(termOne); + right = ZERO_PERCENT; + top = ZERO_PERCENT; + bottom = ZERO_PERCENT; + } + } else if( valueOne != null && valueTwo != null && valueThree == null && valueFour == null ) { + // 2 values + String v1 = valueOne.getText().toLowerCase(); + String v2 = valueTwo.getText().toLowerCase(); + + if( ! isPositionKeyWord(v1) ) { + left = parseSize(termOne); + right = ZERO_PERCENT; + + if( "top".equals(v2) ) { + top = ZERO_PERCENT; + bottom = ZERO_PERCENT; + } else if( "bottom".equals(v2) ) { + top = ONE_HUNDRED_PERCENT; + bottom = ZERO_PERCENT; + } else if( "center".equals(v2) ) { + top = FIFTY_PERCENT; + bottom = ZERO_PERCENT; + } else if( !isPositionKeyWord(v2) ) { + top = parseSize(termTwo); + bottom = ZERO_PERCENT; + } else { + error(termTwo,"Expected 'top', 'bottom', 'center' or "); + } + } else if( v1.equals("left") || v1.equals("right") ) { + left = v1.equals("right") ? ONE_HUNDRED_PERCENT : ZERO_PERCENT; + right = ZERO_PERCENT; + + if( ! isPositionKeyWord(v2) ) { + top = parseSize(termTwo); + bottom = ZERO_PERCENT; + } else if( v2.equals("top") || v2.equals("bottom") || v2.equals("center") ) { + if( v2.equals("top") ) { + top = ZERO_PERCENT; + bottom = ZERO_PERCENT; + } else if(v2.equals("center")) { + top = FIFTY_PERCENT; + bottom = ZERO_PERCENT; + } else { + top = ONE_HUNDRED_PERCENT; + bottom = ZERO_PERCENT; + } + } else { + error(termTwo,"Expected 'top', 'bottom', 'center' or "); + } + } else if( v1.equals("center") ) { + left = FIFTY_PERCENT; + right = ZERO_PERCENT; + + if( v2.equals("top") ) { + top = ZERO_PERCENT; + bottom = ZERO_PERCENT; + } else if( v2.equals("bottom") ) { + top = ONE_HUNDRED_PERCENT; + bottom = ZERO_PERCENT; + } else if( v2.equals("center") ) { + top = FIFTY_PERCENT; + bottom = ZERO_PERCENT; + } else if( ! isPositionKeyWord(v2) ) { + top = parseSize(termTwo); + bottom = ZERO_PERCENT; + } else { + error(termTwo,"Expected 'top', 'bottom', 'center' or "); + } + } + } else if( valueOne != null && valueTwo != null && valueThree != null && valueFour == null ) { + String v1 = valueOne.getText().toLowerCase(); + String v2 = valueTwo.getText().toLowerCase(); + String v3 = valueThree.getText().toLowerCase(); + + if( ! isPositionKeyWord(v1) || "center".equals(v1) ) { + // 1 is horizontal + // means 2 & 3 are vertical + if( "center".equals(v1) ) { + left = FIFTY_PERCENT; + } else { + left = parseSize(termOne); + } + right = ZERO_PERCENT; + + if( !isPositionKeyWord(v3) ) { + if( "top".equals(v2) ) { + top = parseSize(termThree); + bottom = ZERO_PERCENT; + } else if( "bottom".equals(v2) ) { + top = ZERO_PERCENT; + bottom = parseSize(termThree); + } else { + error(termTwo,"Expected 'top' or 'bottom'"); + } + } else { + error(termThree,"Expected "); + } + } else if( "left".equals(v1) || "right".equals(v1) ) { + if( ! isPositionKeyWord(v2) ) { + // 1 & 2 are horizontal + // 3 is vertical + if( "left".equals(v1) ) { + left = parseSize(termTwo); + right = ZERO_PERCENT; + } else { + left = ZERO_PERCENT; + right = parseSize(termTwo); + } + + if( "top".equals(v3) ) { + top = ZERO_PERCENT; + bottom = ZERO_PERCENT; + } else if( "bottom".equals(v3) ) { + top = ONE_HUNDRED_PERCENT; + bottom = ZERO_PERCENT; + } else if( "center".equals(v3) ) { + top = FIFTY_PERCENT; + bottom = ZERO_PERCENT; + } else { + error(termThree,"Expected 'top', 'bottom' or 'center'"); + } + } else { + // 1 is horizontal + // 2 & 3 are vertical + if( "left".equals(v1) ) { + left = ZERO_PERCENT; + right = ZERO_PERCENT; + } else { + left = ONE_HUNDRED_PERCENT; + right = ZERO_PERCENT; + } + + if( ! isPositionKeyWord(v3) ) { + if( "top".equals(v2) ) { + top = parseSize(termThree); + bottom = ZERO_PERCENT; + } else if( "bottom".equals(v2) ) { + top = ZERO_PERCENT; + bottom = parseSize(termThree); + } else { + error(termTwo,"Expected 'top' or 'bottom'"); + } + } else { + error(termThree,"Expected "); + } + } + } } else { - error(termTwo, "Expected \'\'"); - } - - if (valueThree.getType() != CSSLexer.IDENT || - valueThree.getText() == null || - valueThree.getText().isEmpty()) - error(termThree, "Expected \'center\', \'left\' or \'right\'"); - - ParsedValueImpl sizeFour = null; - if (valueFour != null) { - if (isSize(valueFour)) { - sizeFour = parseSize(termFour); + String v1 = valueOne.getText().toLowerCase(); + String v2 = valueTwo.getText().toLowerCase(); + String v3 = valueThree.getText().toLowerCase(); + String v4 = valueFour.getText().toLowerCase(); + + if( (v1.equals("left") || v1.equals("right")) && (v3.equals("top") || v3.equals("bottom") ) && ! isPositionKeyWord(v2) && ! isPositionKeyWord(v4) ) { + if( v1.equals("left") ) { + left = parseSize(termTwo); + right = ZERO_PERCENT; + } else { + left = ZERO_PERCENT; + right = parseSize(termTwo); + } + + if( v3.equals("top") ) { + top = parseSize(termFour); + bottom = ZERO_PERCENT; + } else { + top = ZERO_PERCENT; + bottom = parseSize(termFour); + } + } else { - error(termFour, "Expected \'\'"); + error(term,"Expected 'left' or 'right' followed by followed by 'top' or 'bottom' followed by "); } } - - String keyword = valueOne.getText().toLowerCase(); - - if ("center".equals(keyword)) { - - left = FIFTY_PERCENT; - if (sizeTwo != null) - error(termTwo, "Unexpected \'\'"); - - } else if ("left".equals(keyword)) { - - if (sizeTwo != null) left = sizeTwo; - else left = ZERO_PERCENT; - - } else if ("right".equals(keyword)) { - - if (sizeTwo != null) right = sizeTwo; - else left = ONE_HUNDRED_PERCENT; - - } else { - error(termOne, "Expected \'center\', \'left\' or \'right\'"); - } - - keyword = valueThree.getText().toLowerCase(); - - if ("center".equals(keyword)) { - - top = FIFTY_PERCENT; - if (sizeFour != null) - error(termFour, "Unexpected \'\'"); - - } else if ("top".equals(keyword)) { - - if (sizeFour != null) top = sizeFour; - else top = ZERO_PERCENT; - - } else if ("bottom".equals(keyword)) { - - if (sizeFour != null) bottom = sizeFour; - else top = ONE_HUNDRED_PERCENT; - - } else { - error(termThree, "Expected \'center\', \'left\' or \'right\'"); - } - - } - - // http://www.w3.org/TR/css3-background/#the-background-position states: - // If two values are given and at least one value is not a keyword, then - // the first value represents the horizontal position (or offset) and the - // second represents the vertical position (or offset). and - // values here represent an offset of the top left corner of the - // background image from the top left corner of the background positioning - // area. - else if (valueTwo != null) { - - if (valueOne.getType() == CSSLexer.IDENT) { - - String keyword = - (valueOne.getText() != null) ? - valueOne.getText().toLowerCase() : null; - - if ("center".equals(keyword)) { - - left = FIFTY_PERCENT; - - } else if ("left".equals(keyword)) { - - left = ZERO_PERCENT; - - } else if ("right".equals(keyword)) { - - left = ONE_HUNDRED_PERCENT; - - } else { - - error(termOne, "Expected \'center\', \'left\' or \'right\'"); - - } - - } else if (isSize(valueOne)) { - left = parseSize(termOne); - } else { - error(termOne, "Expected \'\', \'center\', \'left\' or \'right\'"); - } - - - if (valueTwo.getType() == CSSLexer.IDENT) { - - String keyword = - (valueTwo.getText() != null) ? - valueTwo.getText().toLowerCase() : null; - - if ("center".equals(keyword)) { - - top = FIFTY_PERCENT; - - } else if ("top".equals(keyword)) { - - top = ZERO_PERCENT; - - } else if ("bottom".equals(keyword)) { - - top = ONE_HUNDRED_PERCENT; - - } else { - - error(termTwo, "Expected \'center\', \'left\' or \'right\'"); - - } - - } else if (isSize(valueTwo)) { - - top = parseSize(termTwo); - - } else { - error(termTwo, "Expected \'\', \'center\', \'left\' or \'right\'"); - } - - } - - // http://www.w3.org/TR/css3-background/#the-background-position states: - // If only one value is specified, the second value is assumed to be 'center'. - else { - - if (valueOne.getType() == CSSLexer.IDENT) { - - String keyword = - (valueOne.getText() != null) ? - valueOne.getText().toLowerCase() : null; - - if ("center".equals(keyword)) { - - left = FIFTY_PERCENT; - top = FIFTY_PERCENT; - - } else if ("left".equals(keyword)) { - - left = ZERO_PERCENT; - top = FIFTY_PERCENT; - - } else if ("right".equals(keyword)) { - - left = ONE_HUNDRED_PERCENT; - top = FIFTY_PERCENT; - - } else if ("top".equals(keyword)) { - - top = ZERO_PERCENT; - left = FIFTY_PERCENT; - - } else if ("bottom".equals(keyword)) { - - top = ONE_HUNDRED_PERCENT; - left = FIFTY_PERCENT; - - } else { - - error(termOne, "Expected \'center\', \'left\' or \'right\'"); - - } - - } else if (isSize(valueOne)) { - - left = parseSize(termOne); - top = FIFTY_PERCENT; - - } else { - error(termOne, "Expected \'\', \'center\', \'left\' or \'right\'"); - } - } ParsedValueImpl[] values = new ParsedValueImpl[] {top, right, bottom, left}; diff -r 55e988390a0f -r 6f18188702fc javafx-ui-common/src/com/sun/javafx/scene/layout/region/BackgroundPositionConverter.java --- a/javafx-ui-common/src/com/sun/javafx/scene/layout/region/BackgroundPositionConverter.java Fri Jan 18 00:09:25 2013 +0100 +++ b/javafx-ui-common/src/com/sun/javafx/scene/layout/region/BackgroundPositionConverter.java Fri Jan 18 00:39:18 2013 +0100 @@ -43,7 +43,7 @@ public static BackgroundPositionConverter getInstance() { return BACKGROUND_POSITION_CONVERTER; } - + // Disallow instantiation private BackgroundPositionConverter() { } @@ -59,12 +59,14 @@ boolean verticalEdgeProportional = (bottom.getValue() > 0 && bottom.getUnits() == SizeUnits.PERCENT) - || (top.getValue() > 0 && top.getUnits() == SizeUnits.PERCENT); + || (top.getValue() > 0 && top.getUnits() == SizeUnits.PERCENT) + || (top.getValue() == 0 && bottom.getValue() == 0); // either left or right will be set, not both boolean horizontalEdgeProportional = (right.getValue() > 0 && right.getUnits() == SizeUnits.PERCENT) - || ( left.getValue() > 0 && left.getUnits() == SizeUnits.PERCENT); + || ( left.getValue() > 0 && left.getUnits() == SizeUnits.PERCENT) + || (left.getValue() == 0 && right.getValue() == 0); final double t = top.pixels(font); final double r = right.pixels(font); diff -r 55e988390a0f -r 6f18188702fc javafx-ui-common/test/unit/javafx/scene/layout/RegionCSSTest.java --- a/javafx-ui-common/test/unit/javafx/scene/layout/RegionCSSTest.java Fri Jan 18 00:09:25 2013 +0100 +++ b/javafx-ui-common/test/unit/javafx/scene/layout/RegionCSSTest.java Fri Jan 18 00:39:18 2013 +0100 @@ -54,6 +54,7 @@ // private Region region; private Scene scene; + private static final String NL = System.getProperty("line.separator"); private void processCSS() { scene.getRoot().impl_processCSS(true); @@ -475,8 +476,6 @@ // try "50% left" -- shouldn't work // try 3 values... remaining one should be 0 // If only one value is specified, the second value is assumed to be ???center??? -- whatever this means... - - @Ignore("Bug in Parser sets the proportional hpos / vpos flags when they shouldn't be set") @Test public void backgroundImagePosition_right_bottom() { region.setStyle( "-fx-background-image: url('javafx/scene/layout/red.png');" + @@ -491,11 +490,45 @@ BackgroundImage expected = new BackgroundImage(image.getImage(), BackgroundRepeat.REPEAT, BackgroundRepeat.REPEAT, new BackgroundPosition(Side.RIGHT, 20, false, Side.BOTTOM, 10, false), - new BackgroundSize(0, 0, false, false, false, false)); + new BackgroundSize(AUTO, AUTO, true, true, false, false)); assertEquals(expected, image); } - @Ignore("This test should work according to the spec, but doesn't.") + private static String dump(BackgroundImage image) { + StringBuilder b = new StringBuilder("BackgroundImage["); + b.append(NL + " image: " + image.getImage()); + b.append(NL + " position: " + dump(image.getPosition())); + b.append(NL + " repeat-x: " + image.getRepeatX()); + b.append(NL + " repeat-y: " + image.getRepeatY()); + b.append(NL + " size: " + dump(image.getSize())); + b.append(NL + "]"); + return b.toString(); + } + + private static String dump(BackgroundSize size) { + StringBuilder b = new StringBuilder("BackgroundSize["); + b.append(NL + " width: " + size.getWidth()); + b.append(NL + " height: " + size.getHeight()); + b.append(NL + " widthAsPercentage: " + size.isHeightAsPercentage()); + b.append(NL + " heightAsPercentage: " + size.isWidthAsPercentage()); + b.append(NL + " contain: " + size.isContain()); + b.append(NL + " cover: " + size.isCover()); + b.append(NL + " ]"); + return b.toString(); + } + + private static String dump(BackgroundPosition position) { + StringBuilder b = new StringBuilder("BackgroundPosition["); + b.append(NL + " hSide: " + position.getHorizontalSide()); + b.append(NL + " hPosition: " + position.getHorizontalPosition()); + b.append(NL + " hAsPercentage: " + position.isHorizontalAsPercentage()); + b.append(NL + " vSide: " + position.getVerticalSide()); + b.append(NL + " vPosition: " + position.getVerticalPosition()); + b.append(NL + " vAsPercentage: " + position.isVerticalAsPercentage()); + b.append(NL + " ]"); + return b.toString(); + } + @Test public void backgroundImagePosition_bottom_right() { region.setStyle( "-fx-background-image: url('javafx/scene/layout/red.png');" + @@ -510,11 +543,11 @@ BackgroundImage expected = new BackgroundImage(image.getImage(), BackgroundRepeat.REPEAT, BackgroundRepeat.REPEAT, new BackgroundPosition(Side.RIGHT, 20, false, Side.BOTTOM, 10, false), - new BackgroundSize(0, 0, false, false, false, false)); + new BackgroundSize(AUTO, AUTO, true, true, false, false)); assertEquals(expected, image); } - @Test @Ignore public void backgroundImagePosition_top() { + @Test public void backgroundImagePosition_top() { region.setStyle( "-fx-background-image: url('javafx/scene/layout/red.png');" + "-fx-background-position: top;"); @@ -532,7 +565,7 @@ assertEquals(expected, image); } - @Test @Ignore public void backgroundImagePosition_left() { + @Test public void backgroundImagePosition_left() { region.setStyle( "-fx-background-image: url('javafx/scene/layout/red.png');" + "-fx-background-position: left;"); @@ -604,7 +637,7 @@ assertEquals(expected, image); } - @Test @Ignore public void backgroundImagePosition_center_top() { + @Test public void backgroundImagePosition_center_top() { region.setStyle( "-fx-background-image: url('javafx/scene/layout/red.png');" + "-fx-background-position: center top;"); @@ -640,7 +673,7 @@ assertEquals(expected, image); } - @Test @Ignore public void backgroundImagePosition_Example8_2() { + @Test public void backgroundImagePosition_Example8_2() { region.setStyle( "-fx-background-image: url('javafx/scene/layout/red.png');" + "-fx-background-position: left top;"); @@ -676,7 +709,7 @@ assertEquals(expected, image); } - @Test @Ignore public void backgroundImagePosition_Example8_4() { + @Test public void backgroundImagePosition_Example8_4() { region.setStyle( "-fx-background-image: url('javafx/scene/layout/red.png');" + "-fx-background-position: left 15px;"); @@ -694,7 +727,7 @@ assertEquals(expected, image); } - @Test @Ignore public void backgroundImagePosition_Example8_5() { + @Test public void backgroundImagePosition_Example8_5() { region.setStyle( "-fx-background-image: url('javafx/scene/layout/red.png');" + "-fx-background-position: 10px top;"); @@ -712,7 +745,6 @@ assertEquals(expected, image); } - @Ignore("Parser error. According to the spec this should work.") @Test public void backgroundImagePosition_Example8_6() { region.setStyle( "-fx-background-image: url('javafx/scene/layout/red.png');" + @@ -731,7 +763,7 @@ assertEquals(expected, image); } - @Test @Ignore public void backgroundImagePosition_Example8_7() { + @Test public void backgroundImagePosition_Example8_7() { region.setStyle( "-fx-background-image: url('javafx/scene/layout/red.png');" + "-fx-background-position: left 10px top;"); @@ -749,7 +781,7 @@ assertEquals(expected, image); } - @Test @Ignore public void backgroundImagePosition_Example10_1() { + @Test public void backgroundImagePosition_Example10_1() { region.setStyle( "-fx-background-image: url('javafx/scene/layout/red.png');" + "-fx-background-position: right top;"); @@ -767,7 +799,6 @@ assertEquals(expected, image); } - @Ignore ("Fails because the parser does not allow out-of-order declaration") @Test public void backgroundImagePosition_Example10_2() { region.setStyle( "-fx-background-image: url('javafx/scene/layout/red.png');" +