diff --git a/demo/example/src/main/java/org/geotools/demo/Quickstart.java b/demo/example/src/main/java/org/geotools/demo/Quickstart.java
index 478ab58..c705135 100644
--- a/demo/example/src/main/java/org/geotools/demo/Quickstart.java
+++ b/demo/example/src/main/java/org/geotools/demo/Quickstart.java
@@ -12,12 +12,18 @@ package org.geotools.demo;
 
 import java.io.File;
 
+import javax.measure.unit.SI;
+
 import org.geotools.data.CachingFeatureSource;
 import org.geotools.data.FeatureSource;
 import org.geotools.data.FileDataStore;
 import org.geotools.data.FileDataStoreFinder;
+import org.geotools.data.shapefile.ShapefileDataStore;
 import org.geotools.map.DefaultMapContext;
 import org.geotools.map.MapContext;
+import org.geotools.styling.ExternalGraphic;
+import org.geotools.styling.PointSymbolizer;
+import org.geotools.styling.StyleBuilder;
 import org.geotools.swing.JMapFrame;
 import org.geotools.swing.data.JFileDataStoreChooser;
 
@@ -35,18 +41,23 @@ public class Quickstart {
      */    
     public static void main(String[] args) throws Exception {
         // display a data store file chooser dialog for shapefiles
-        File file = JFileDataStoreChooser.showOpenFile("shp", null);
-        if (file == null) {
-            return;
-        }
+//        File file = JFileDataStoreChooser.showOpenFile("shp", null);
+//        if (file == null) {
+//            return;dsdd
+//        }
 
-        FileDataStore store = FileDataStoreFinder.getDataStore(file);
+        FileDataStore store = new ShapefileDataStore(new File("/home/aaime/devel/gisData/bc_shapefiles/bc_pubs.shp").toURL());
         FeatureSource featureSource = store.getFeatureSource();
 
         // Create a map context and add our shapefile to it
         MapContext map = new DefaultMapContext();
         map.setTitle("Quickstart");
-        map.addLayer(featureSource, null);
+        StyleBuilder sb = new StyleBuilder();
+        ExternalGraphic eg = sb.createExternalGraphic(new File("/home/aaime/devel/dg/gt2.5.4/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/draw.png").toURI().toString(), "image/png");
+        PointSymbolizer ps = sb.createPointSymbolizer(sb.createGraphic(eg, null, null));
+        ps.getGraphic().setSize(sb.getFilterFactory().literal(10));
+        ps.setUnitOfMeasure(SI.METER);
+        map.addLayer(featureSource, sb.createStyle(ps));
 
         // Now display the map
         JMapFrame.showMap(map);
diff --git a/modules/library/main/src/main/java/org/geotools/styling/UomOgcMapping.java b/modules/library/main/src/main/java/org/geotools/styling/UomOgcMapping.java
index 8df402b..5e47c21 100644
--- a/modules/library/main/src/main/java/org/geotools/styling/UomOgcMapping.java
+++ b/modules/library/main/src/main/java/org/geotools/styling/UomOgcMapping.java
@@ -22,93 +22,90 @@ import javax.measure.unit.SI;
 import javax.measure.unit.Unit;
 
 /**
- * Defines the Units of Measure (UOMs) specified by the OGC SE standard and
- * their mappings to Java Units defined in <code>javax.measure.unit</code>. Each
- * entry in this enum provides both the Java Unit for the given UOM and the
- * corresponding String that is defined by the SE standard.
+ * Defines the Units of Measure (UOMs) specified by the OGC SE standard and their mappings to Java
+ * Units defined in <code>javax.measure.unit</code>. Each entry in this enum provides both the Java
+ * Unit for the given UOM and the corresponding String that is defined by the SE standard.
  */
 public enum UomOgcMapping {
 
-	METRE(SI.METER, "http://www.opengeospatial.org/se/units/metre"), FOOT(
-			NonSI.FOOT, "http://www.opengeospatial.org/se/units/foot"), PIXEL(
-			NonSI.PIXEL, "http://www.opengeospatial.org/se/units/pixel");
+    METRE(SI.METER, "http://www.opengeospatial.org/se/units/metre"), FOOT(NonSI.FOOT,
+            "http://www.opengeospatial.org/se/units/foot"), PIXEL(NonSI.PIXEL,
+            "http://www.opengeospatial.org/se/units/pixel");
 
-	private String seString;
-	private Unit<Length> unit;
+    private String seString;
 
-	/**
-	 * Internal constructor: specifies the UOM mapping passing a specific Java
-	 * Unit and the corresponding OGC SE string.
-	 * 
-	 * @param unit
-	 *            a Java Unit (e.g., <code>SI.METER</code>).
-	 * @param seString
-	 *            a String that follows the OGC SE specification.
-	 */
-	private UomOgcMapping(Unit<Length> unit, String seString) {
-		this.unit = unit;
-		this.seString = seString;
-	}
+    private Unit<Length> unit;
 
-	@Override
-	public String toString() {
-		return seString;
-	}
+    /**
+     * Internal constructor: specifies the UOM mapping passing a specific Java Unit and the
+     * corresponding OGC SE string.
+     * 
+     * @param unit
+     *            a Java Unit (e.g., <code>SI.METER</code>).
+     * @param seString
+     *            a String that follows the OGC SE specification.
+     */
+    private UomOgcMapping(Unit<Length> unit, String seString) {
+        this.unit = unit;
+        this.seString = seString;
+    }
 
-	/**
-	 * Returns the String defined by the OGC SE specification for the unit of
-	 * measure.
-	 * 
-	 * @return a String that follows the OGC SE specification
-	 */
-	public String getSEString() {
-		return seString;
-	}
+    @Override
+    public String toString() {
+        return seString;
+    }
 
-	/**
-	 * Returns the Java Unit that corresponds to the unit of measure.
-	 * 
-	 * @return a Java Unit (e.g., <code>SI.METER</code>).
-	 */
-	public Unit<Length> getUnit() {
-		return unit;
-	}
+    /**
+     * Returns the String defined by the OGC SE specification for the unit of measure.
+     * 
+     * @return a String that follows the OGC SE specification
+     */
+    public String getSEString() {
+        return seString;
+    }
 
-	/**
-	 * Returns the appropriate UOM mapping for a given OGC SE standard string.
-	 * 
-	 * @param seString
-	 *            a String that follows the OGC SE specification.
-	 * @return the corresponding UnitOfMeasure.
-	 * @throws IllegalArgumentException
-	 *             if the provided String is not a valid OGC SE value.
-	 */
-	public static UomOgcMapping get(String seString)
-			throws IllegalArgumentException {
-		for (UomOgcMapping uom : UomOgcMapping.values()) {
-			if (uom.getSEString().equals(seString))
-				return uom;
-		}
-		throw new IllegalArgumentException("'" + seString
-				+ "' is not a valid OGC SE standard Unit of Measure");
-	}
+    /**
+     * Returns the Java Unit that corresponds to the unit of measure.
+     * 
+     * @return a Java Unit (e.g., <code>SI.METER</code>).
+     */
+    public Unit<Length> getUnit() {
+        return unit;
+    }
 
-	/**
-	 * Returns the appropriate UOM mapping for a given Java Unit.
-	 * 
-	 * @param unit
-	 *            a Java Unit (e.g., <code>SI.METER</code>).
-	 * @return the corresponding UnitOfMeasure.
-	 * @throws IllegalArgumentException
-	 *             if the provided Unit is not part of the OGC SE specification.
-	 */
-	public static UomOgcMapping get(Unit<Length> unit)
-			throws IllegalArgumentException {
-		for (UomOgcMapping uom : UomOgcMapping.values()) {
-			if (uom.getUnit().equals(unit))
-				return uom;
-		}
-		throw new IllegalArgumentException("'" + unit
-				+ "' is not a valid OGC SE standard Unit of Measure");
-	}
+    /**
+     * Returns the appropriate UOM mapping for a given OGC SE standard string.
+     * 
+     * @param seString
+     *            a String that follows the OGC SE specification.
+     * @return the corresponding UnitOfMeasure.
+     * @throws IllegalArgumentException
+     *             if the provided String is not a valid OGC SE value.
+     */
+    public static UomOgcMapping get(String seString) throws IllegalArgumentException {
+        for (UomOgcMapping uom : UomOgcMapping.values()) {
+            if (uom.getSEString().equals(seString))
+                return uom;
+        }
+        throw new IllegalArgumentException("'" + seString
+                + "' is not a valid OGC SE standard Unit of Measure");
+    }
+
+    /**
+     * Returns the appropriate UOM mapping for a given Java Unit.
+     * 
+     * @param unit
+     *            a Java Unit (e.g., <code>SI.METER</code>).
+     * @return the corresponding UnitOfMeasure.
+     * @throws IllegalArgumentException
+     *             if the provided Unit is not part of the OGC SE specification.
+     */
+    public static UomOgcMapping get(Unit<Length> unit) throws IllegalArgumentException {
+        for (UomOgcMapping uom : UomOgcMapping.values()) {
+            if (uom.getUnit().equals(unit))
+                return uom;
+        }
+        throw new IllegalArgumentException("'" + unit
+                + "' is not a valid OGC SE standard Unit of Measure");
+    }
 }
diff --git a/modules/library/main/src/main/java/org/geotools/styling/visitor/DuplicatingStyleVisitor.java b/modules/library/main/src/main/java/org/geotools/styling/visitor/DuplicatingStyleVisitor.java
index ca65738..beeae6f 100644
--- a/modules/library/main/src/main/java/org/geotools/styling/visitor/DuplicatingStyleVisitor.java
+++ b/modules/library/main/src/main/java/org/geotools/styling/visitor/DuplicatingStyleVisitor.java
@@ -915,6 +915,11 @@ public class DuplicatingStyleVisitor implements StyleVisitor {
     public void visit(LinePlacement lp) {
         Expression offset = copy( lp.getPerpendicularOffset());
         LinePlacement copy = sf.createLinePlacement(offset);
+        copy.setAligned( lp.isAligned() );
+        copy.setGap( copy(lp.getGap()) );
+        copy.setGeneralized( lp.isGeneralizeLine() );
+        copy.setInitialGap( copy(lp.getInitialGap()) );
+        copy.setRepeated( lp.isRepeated() );
 
         if( STRICT && !copy.equals( lp )){
             throw new IllegalStateException("Was unable to duplicate provided LinePlacement:"+lp );
diff --git a/modules/library/main/src/main/java/org/geotools/styling/visitor/UomRescaleStyleVisitor.java b/modules/library/main/src/main/java/org/geotools/styling/visitor/UomRescaleStyleVisitor.java
new file mode 100644
index 0000000..7305dcf
--- /dev/null
+++ b/modules/library/main/src/main/java/org/geotools/styling/visitor/UomRescaleStyleVisitor.java
@@ -0,0 +1,255 @@
+/*
+ *    GeoTools - The Open Source Java GIS Toolkit
+ *    http://geotools.org
+ *
+ *    (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
+ *
+ *    This library is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU Lesser General Public
+ *    License as published by the Free Software Foundation;
+ *    version 2.1 of the License.
+ *
+ *    This library is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *    Lesser General Public License for more details.
+ */
+package org.geotools.styling.visitor;
+
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Length;
+import javax.measure.unit.NonSI;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+import org.geotools.filter.LiteralExpression;
+import org.geotools.styling.Displacement;
+import org.geotools.styling.Fill;
+import org.geotools.styling.Font;
+import org.geotools.styling.Graphic;
+import org.geotools.styling.LabelPlacement;
+import org.geotools.styling.LinePlacement;
+import org.geotools.styling.LineSymbolizer;
+import org.geotools.styling.PointPlacement;
+import org.geotools.styling.PointSymbolizer;
+import org.geotools.styling.PolygonSymbolizer;
+import org.geotools.styling.Stroke;
+import org.geotools.styling.TextSymbolizer;
+import org.opengis.filter.expression.Expression;
+
+/**
+ * Visitor used for rescaling a Style given a map scale (e.g., meters per pixel) and taking into
+ * consideration the Unit of Measure (UOM, e.g., SI.METER, NonSI.FOOT) of each symbolizer. The
+ * resulting Style's Symbolizer sizes will all be given in PIXELS, so that they can be directly used
+ * by a renderer that is unaware of units of measure or the current map scale. For example, points
+ * with size == 100 meters could be rescaled to 10 pixels for higher levels of zoom and 2 pixels for
+ * a lower level of zoom.
+ * <p>
+ * This visitor extends {@link DuplicatingStyleVisitor} and as such yields a copy of the original
+ * Style. Usage is simply to call the desired visit() method and then call getCopy() to retrieve the
+ * result.
+ * 
+ * @author milton
+ */
+public class UomRescaleStyleVisitor extends DuplicatingStyleVisitor {
+
+    private double mapScale = 1;
+
+    /**
+     * Constructor: requires the current mapScale to inform the window to viewport (world to screen)
+     * relation in order to correctly rescale sizes according to units of measure given in world
+     * units (e.g., SI.METER, NonSI.FOOT, etc).
+     * 
+     * @param mapScale
+     *            The specified map scale, given in pixels per meter.
+     */
+    public UomRescaleStyleVisitor(double mapScale) {
+        if (mapScale <= 0)
+            throw new IllegalArgumentException("The mapScale is out of range. Value is "
+                    + Double.toString(mapScale) + ". It must be positive.");
+
+        this.mapScale = mapScale;
+    }
+
+    /**
+     * Computes a rescaling multiplier to be applied to an unscaled value.
+     * 
+     * @param mapScale
+     *            the mapScale in pixels per meter.
+     * @param uom
+     *            the unit of measure that will be used to scale.
+     * @return the rescaling multiplier for the provided parameters.
+     */
+    protected double computeRescaleMultiplier(double mapScale, Unit<Length> uom) {
+        // no scaling to do if UOM is PIXEL (or null, which stands for PIXEL as well)
+        if (uom == null || uom.equals(NonSI.PIXEL))
+            return 1;
+
+        // converts value from meters to given UOM
+        UnitConverter converter = uom.getConverterTo(SI.METER);
+        return converter.convert(mapScale);
+    }
+
+    /**
+     * Used to rescale the provided unscaled value.
+     * 
+     * @param unscaled
+     *            the unscaled value.
+     * @param mapScale
+     *            the mapScale in pixels per meter.
+     * @param uom
+     *            the unit of measure that will be used to scale.
+     * @return the expression multiplied by the provided scale.
+     */
+    protected Expression rescale(Expression unscaled, double mapScale, Unit<Length> uom) {
+        if (unscaled == null || unscaled.equals(Expression.NIL))
+            return unscaled;
+
+        if (unscaled instanceof LiteralExpression) {
+            // if given Expression is a literal, we can return a literal
+            double rescaled = rescale(unscaled.evaluate(null, Double.class), mapScale, uom);
+            return ff.literal(rescaled);
+        } else {
+            // otherwise, we return a Multiply expression with the rescaling multiplier
+            double rescaleMultiplier = computeRescaleMultiplier(mapScale, uom);
+            return ff.multiply(unscaled, ff.literal(rescaleMultiplier));
+        }
+    }
+
+    /**
+     * Used to rescale the provided unscaled value.
+     * 
+     * @param unscaled
+     *            the unscaled value.
+     * @param mapScale
+     *            the mapScale in pixels per meter.
+     * @param uom
+     *            the unit of measure that will be used to scale.
+     * @return a scaled value.
+     */
+    protected double rescale(double unscaled, double mapScale, Unit<Length> uom) {
+        // computes the basic rescaled value
+        return unscaled * computeRescaleMultiplier(mapScale, uom);
+    }
+
+    /**
+     * Used to rescale the provided dash array.
+     * 
+     * @param dashArray
+     *            the unscaled dash array. If null, the method returns null.
+     * @param mapScale
+     *            the mapScale in pixels per meter.
+     * @param uom
+     *            the unit of measure that will be used to scale.
+     * @return the rescaled dash array
+     */
+    protected float[] rescale(float[] dashArray, double mapScale, Unit<Length> unitOfMeasure) {
+        if (dashArray == null)
+            return null;
+        if (unitOfMeasure == null || unitOfMeasure.equals(NonSI.PIXEL))
+            return dashArray;
+
+        float[] rescaledDashArray = new float[dashArray.length];
+
+        for (int i = 0; i < rescaledDashArray.length; i++) {
+            rescaledDashArray[i] = (float) rescale((double) dashArray[i], mapScale, unitOfMeasure);
+        }
+        return rescaledDashArray;
+    }
+
+    /**
+     * Used to rescale the provided stroke.
+     * 
+     * @param stroke
+     *            the unscaled stroke, which will be modified in-place.
+     * @param mapScale
+     *            the mapScale in pixels per meter.
+     * @param uom
+     *            the unit of measure that will be used to scale.
+     */
+    protected void rescaleStroke(Stroke stroke, double mapScale, Unit<Length> uom) {
+        if (stroke != null) {
+            stroke.setWidth(rescale(stroke.getWidth(), mapScale, uom));
+            stroke.setDashArray(rescale(stroke.getDashArray(), mapScale, uom));
+        }
+    }
+
+    @Override
+    public void visit(PointSymbolizer ps) {
+        super.visit(ps);
+        PointSymbolizer copy = (PointSymbolizer) pages.peek();
+
+        Graphic copyGraphic = copy.getGraphic();
+        copyGraphic.setSize(rescale(copyGraphic.getSize(), mapScale, copy.getUnitOfMeasure()));
+        copy.setUnitOfMeasure(NonSI.PIXEL);
+    }
+
+    @Override
+    public void visit(LineSymbolizer line) {
+        super.visit(line);
+        LineSymbolizer copy = (LineSymbolizer) pages.peek();
+
+        Stroke copyStroke = copy.getStroke();
+        rescaleStroke(copyStroke, mapScale, copy.getUnitOfMeasure());
+        copy.setUnitOfMeasure(NonSI.PIXEL);
+    }
+
+    @Override
+    public void visit(PolygonSymbolizer poly) {
+        super.visit(poly);
+        PolygonSymbolizer copy = (PolygonSymbolizer) pages.peek();
+
+        Stroke copyStroke = copy.getStroke();
+        rescaleStroke(copyStroke, mapScale, copy.getUnitOfMeasure());
+
+        // rescales the graphic fill, if available
+        Fill copyFill = copy.getFill();
+        if (copyFill != null) {
+            Graphic copyGraphic = copyFill.getGraphicFill();
+            if (copyGraphic != null) {
+                copyGraphic.setSize(rescale(copyGraphic.getSize(), mapScale, copy
+                        .getUnitOfMeasure()));
+                copyFill.setGraphicFill(copyGraphic);
+            }
+            copy.setFill(copyFill);
+        }
+        copy.setUnitOfMeasure(NonSI.PIXEL);
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public void visit(TextSymbolizer text) {
+        super.visit(text);
+        TextSymbolizer copy = (TextSymbolizer) pages.peek();
+
+        Unit<Length> uom = copy.getUnitOfMeasure();
+
+        // rescales fonts
+        Font[] fonts = copy.getFonts();
+        for (Font font : fonts)
+            font.setSize(rescale(font.getSize(), mapScale, uom));
+        copy.setFonts(fonts);
+
+        // rescales label placement
+        LabelPlacement placement = copy.getLabelPlacement();
+        if (placement instanceof PointPlacement) {
+            // rescales point label placement
+            PointPlacement pointPlacement = (PointPlacement) placement;
+            Displacement disp = pointPlacement.getDisplacement();
+            if (disp != null) {
+                disp.setDisplacementX(rescale(disp.getDisplacementX(), mapScale, uom));
+                disp.setDisplacementY(rescale(disp.getDisplacementY(), mapScale, uom));
+                pointPlacement.setDisplacement(disp);
+            }
+        } else if (placement instanceof LinePlacement) {
+            // rescales line label placement
+            LinePlacement linePlacement = (LinePlacement) placement;
+            linePlacement.setGap(rescale(linePlacement.getGap(), mapScale, uom));
+            linePlacement.setInitialGap(rescale(linePlacement.getInitialGap(), mapScale, uom));
+            linePlacement.setPerpendicularOffset(rescale(linePlacement.getPerpendicularOffset(),
+                    mapScale, uom));
+        }
+        copy.setLabelPlacement(placement);
+        copy.setUnitOfMeasure(NonSI.PIXEL);
+    }
+}
diff --git a/modules/library/main/src/test/java/org/geotools/styling/visitor/UomRescaleStyleVisitorTest.java b/modules/library/main/src/test/java/org/geotools/styling/visitor/UomRescaleStyleVisitorTest.java
new file mode 100644
index 0000000..758b6c9
--- /dev/null
+++ b/modules/library/main/src/test/java/org/geotools/styling/visitor/UomRescaleStyleVisitorTest.java
@@ -0,0 +1,578 @@
+/*
+ *    GeoTools - The Open Source Java GIS Toolkit
+ *    http://geotools.org
+ *
+ *    (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
+ *
+ *    This library is free software; you can redistribute it and/or
+ *    modify it under the terms of the GNU Lesser General Public
+ *    License as published by the Free Software Foundation;
+ *    version 2.1 of the License.
+ *
+ *    This library is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *    Lesser General Public License for more details.
+ */
+package org.geotools.styling.visitor;
+
+import java.awt.Color;
+
+import javax.measure.quantity.Length;
+import javax.measure.unit.NonSI;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.geotools.feature.simple.SimpleFeatureBuilder;
+import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
+import org.geotools.filter.FilterFactoryImpl;
+import org.geotools.referencing.crs.DefaultGeographicCRS;
+import org.geotools.styling.Fill;
+import org.geotools.styling.Font;
+import org.geotools.styling.LinePlacement;
+import org.geotools.styling.LineSymbolizerImpl;
+import org.geotools.styling.PointPlacement;
+import org.geotools.styling.PointSymbolizer;
+import org.geotools.styling.PointSymbolizerImpl;
+import org.geotools.styling.PolygonSymbolizerImpl;
+import org.geotools.styling.Stroke;
+import org.geotools.styling.StyleBuilder;
+import org.geotools.styling.TextSymbolizer;
+import org.geotools.styling.TextSymbolizerImpl;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+import org.opengis.filter.FilterFactory2;
+import org.opengis.filter.expression.Expression;
+import org.opengis.style.LineSymbolizer;
+import org.opengis.style.PolygonSymbolizer;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.GeometryFactory;
+import com.vividsolutions.jts.geom.LineString;
+
+
+/**
+ * @author milton
+ *
+ */
+public class UomRescaleStyleVisitorTest extends TestCase
+{
+    
+    public void testConstructorOK()
+    {
+        try
+        {
+            new UomRescaleStyleVisitor(1);
+        }
+        catch (Exception e2)
+        {
+            e2.printStackTrace();
+            Assert.fail(e2.getClass().getSimpleName() + " should not be thrown.");
+        }
+    }
+    
+    
+    public void testConstructorFail()
+    {
+    	try
+    	{
+    		new UomRescaleStyleVisitor(-1);
+    	}
+    	catch(IllegalArgumentException e)
+    	{
+    		return;
+    	}
+    	
+    	Assert.fail("Should throw IllegalArgumentException.");
+    }
+    
+    protected double computeExpectedRescaleSize(double size, double scaleMetersToPixel, Unit<Length> uom)
+    {
+        double expectedRescaledSize = size;
+        
+        // uom == null means pixels (rescalesize == size)
+        if (uom != null)
+        {
+            double scaleUomToMeters = 1;
+            if (uom.equals(NonSI.FOOT))
+                scaleUomToMeters *= 0.3048006096012;
+            if (!uom.equals(NonSI.PIXEL))
+                expectedRescaledSize *= scaleUomToMeters * scaleMetersToPixel;
+        }
+        
+        return expectedRescaledSize;
+    }
+    
+    
+    protected void visitPointSymbolizerTest(double scaleMetersToPixel, Unit<Length> uom)
+    {
+        try
+        {
+            UomRescaleStyleVisitor visitor = null;
+            double size = 100;
+            double expectedRescaledSize = computeExpectedRescaleSize(size, scaleMetersToPixel, uom);
+            
+            StyleBuilder styleBuilder = new StyleBuilder();
+
+            PointSymbolizerImpl pointSymb = (PointSymbolizerImpl) styleBuilder.createPointSymbolizer();
+            pointSymb.setUnitOfMeasure(uom);
+
+            FilterFactory2 filterFactory  = new FilterFactoryImpl();
+            pointSymb.getGraphic().setSize(filterFactory.literal(size));
+
+            visitor = new UomRescaleStyleVisitor(scaleMetersToPixel);
+
+            pointSymb.accept(visitor);
+            PointSymbolizer rescaledPointSymb = (PointSymbolizer) visitor.getCopy();
+            double rescaledSize = rescaledPointSymb.getGraphic().getSize().evaluate(null, Double.class);
+            
+            Assert.assertEquals(Math.round(expectedRescaledSize), Math.round(rescaledSize));
+            Assert.assertNotSame(rescaledPointSymb, pointSymb);
+        }
+        catch (Exception e2)
+        {
+            e2.printStackTrace();
+            Assert.fail(e2.getClass().getSimpleName() + " should not be thrown.");
+        }
+    }
+    
+    protected void visitLineSymbolizerTest(double scaleMetersToPixel, Unit<Length> uom)
+    {
+        try
+        {
+            UomRescaleStyleVisitor visitor = null;
+            double size = 100;
+            double expectedRescaledSize = computeExpectedRescaleSize(size, scaleMetersToPixel, uom);
+            
+            StyleBuilder styleBuilder = new StyleBuilder();
+
+            LineSymbolizerImpl lineSymb = (LineSymbolizerImpl) styleBuilder.createLineSymbolizer();
+            lineSymb.setUnitOfMeasure(uom);
+            
+            FilterFactory2 filterFactory  = new FilterFactoryImpl();
+            lineSymb.getStroke().setWidth(filterFactory.literal(size));
+
+            visitor = new UomRescaleStyleVisitor(scaleMetersToPixel);
+
+            lineSymb.accept(visitor);
+            LineSymbolizer rescaledLineSymb = (LineSymbolizer) visitor.getCopy();
+            double rescaledSize = rescaledLineSymb.getStroke().getWidth().evaluate(null, Double.class);
+            
+            Assert.assertEquals(Math.round(expectedRescaledSize), Math.round(rescaledSize));
+            Assert.assertNotSame(rescaledLineSymb, lineSymb);
+        }
+        catch (Exception e2)
+        {
+            e2.printStackTrace();
+            Assert.fail(e2.getClass().getSimpleName() + " should not be thrown.");
+        }
+    }
+    
+    protected void visitPolygonSymbolizerTest(double scaleMetersToPixel, Unit<Length> uom)
+    {
+        try
+        {
+            UomRescaleStyleVisitor visitor = null;
+            double size = 100;
+            double expectedRescaledSize = computeExpectedRescaleSize(size, scaleMetersToPixel, uom);
+            
+            StyleBuilder styleBuilder = new StyleBuilder();
+
+            PolygonSymbolizerImpl polySymb = (PolygonSymbolizerImpl) styleBuilder.createPolygonSymbolizer();
+            polySymb.setUnitOfMeasure(uom);
+            
+            FilterFactory2 filterFactory  = new FilterFactoryImpl();
+            polySymb.getStroke().setWidth(filterFactory.literal(size));
+
+            visitor = new UomRescaleStyleVisitor(scaleMetersToPixel);
+
+            polySymb.accept(visitor);
+            PolygonSymbolizer rescaledPolySymb = (PolygonSymbolizer) visitor.getCopy();
+            double rescaledSize = rescaledPolySymb.getStroke().getWidth().evaluate(null, Double.class);
+            
+            Assert.assertEquals(Math.round(expectedRescaledSize), Math.round(rescaledSize));
+            Assert.assertNotSame(rescaledPolySymb, polySymb);
+        }
+        catch (Exception e2)
+        {
+            e2.printStackTrace();
+            Assert.fail(e2.getClass().getSimpleName() + " should not be thrown.");
+        }
+    }
+    
+    protected void visitTextSymbolizerTest(double scaleMetersToPixel, Unit<Length> uom)
+    {
+        try
+        {
+            UomRescaleStyleVisitor visitor = null;
+            int fontSize = 100;
+            double displacementX = 13;
+            double displacementY = 17;
+            double expectedRescaledFontSize = computeExpectedRescaleSize(fontSize, scaleMetersToPixel, uom);
+            double expectedRescaledDisplacementXSize = computeExpectedRescaleSize(displacementX, scaleMetersToPixel, uom);
+            double expectedRescaledDisplacementYSize = computeExpectedRescaleSize(displacementY, scaleMetersToPixel, uom);
+            
+            StyleBuilder styleBuilder = new StyleBuilder();
+
+            TextSymbolizerImpl textSymb = (TextSymbolizerImpl) styleBuilder.createTextSymbolizer();
+            textSymb.setUnitOfMeasure(uom);
+            
+            Font font = styleBuilder.createFont(new java.awt.Font("Verdana",java.awt.Font.PLAIN,fontSize));
+            textSymb.setFont(font);
+            
+            PointPlacement placement = styleBuilder.createPointPlacement(0.3, 0.3, displacementX, displacementY, 10);
+            textSymb.setLabelPlacement(placement);
+
+            visitor = new UomRescaleStyleVisitor(scaleMetersToPixel);
+
+            textSymb.accept(visitor);
+            TextSymbolizer rescaledTextSymb = (TextSymbolizer) visitor.getCopy();
+            
+            double rescaledFontSize = rescaledTextSymb.getFont().getSize().evaluate(null, Double.class);
+            PointPlacement rescaledPlacement = (PointPlacement) rescaledTextSymb.getLabelPlacement();
+            double rescaledDisplacementXSize = rescaledPlacement.getDisplacement().getDisplacementX().evaluate(null, Double.class);
+            double rescaledDisplacementYSize = rescaledPlacement.getDisplacement().getDisplacementY().evaluate(null, Double.class);
+            
+            Assert.assertEquals(Math.round(expectedRescaledFontSize), Math.round(rescaledFontSize));
+            Assert.assertEquals(Math.round(expectedRescaledDisplacementXSize), Math.round(rescaledDisplacementXSize));
+            Assert.assertEquals(Math.round(expectedRescaledDisplacementYSize), Math.round(rescaledDisplacementYSize));
+            Assert.assertNotSame(rescaledTextSymb, textSymb);
+        }
+        catch (Exception e2)
+        {
+            e2.printStackTrace();
+            Assert.fail(e2.getClass().getSimpleName() + " should not be thrown.");
+        }
+    }
+    
+
+    // POINT SYMBOLIZER TESTS
+    
+    public void testVisitPointSymbolizer_ScalePixelNull()
+    {
+        visitPointSymbolizerTest(10, null);
+    }
+    
+   
+    public void testVisitPointSymbolizer_ScalePixelExplicit()
+    {
+        visitPointSymbolizerTest(10, NonSI.PIXEL);
+    }
+    
+    
+    public void testVisitPointSymbolizer_ScaleMeter1()
+    {
+        visitPointSymbolizerTest(1, SI.METER);
+    }
+    
+   
+    public void testVisitPointSymbolizer_ScaleMeter10()
+    {
+        visitPointSymbolizerTest(10, SI.METER);
+    }
+    
+    
+    public void testVisitPointSymbolizer_ScaleFoot1()
+    {
+        visitPointSymbolizerTest(1, NonSI.FOOT);
+    }
+    
+    
+    public void testVisitPointSymbolizer_ScaleFoot10()
+    {
+        visitPointSymbolizerTest(10, NonSI.FOOT);
+    }
+
+
+    // LINE SYMBOLIZER TESTS
+    
+    public void testVisitLineSymbolizer_ScalePixelNull()
+    {
+        visitLineSymbolizerTest(10, null);
+    }
+    
+    
+    public void testVisitLineSymbolizer_ScalePixelExplicit()
+    {
+        visitLineSymbolizerTest(10, NonSI.PIXEL);
+    }
+    
+    
+    public void testVisitLineSymbolizer_ScaleMeter1()
+    {
+        visitLineSymbolizerTest(1, SI.METER);
+    }
+    
+    
+    public void testVisitLineSymbolizer_ScaleMeter10()
+    {
+        visitLineSymbolizerTest(10, SI.METER);
+    }
+    
+    
+    public void testVisitLineSymbolizer_ScaleFoot1()
+    {
+        visitLineSymbolizerTest(1, NonSI.FOOT);
+    }
+    
+    
+    public void testVisitLineSymbolizer_ScaleFoot10()
+    {
+        visitLineSymbolizerTest(10, NonSI.FOOT);
+    }
+    
+    
+    // POLYGON SYMBOLIZER TESTS
+    
+    public void testVisitPolygonSymbolizer_ScalePixelNull()
+    {
+        visitPolygonSymbolizerTest(10, null);
+    }
+    
+    
+    public void testVisitPolygonSymbolizer_ScalePixelExplicit()
+    {
+        visitPolygonSymbolizerTest(10, NonSI.PIXEL);
+    }
+    
+    
+    public void testVisitPolygonSymbolizer_ScaleMeter1()
+    {
+        visitPolygonSymbolizerTest(1, SI.METER);
+    }
+    
+    
+    public void testVisitPolygonSymbolizer_ScaleMeter10()
+    {
+        visitPolygonSymbolizerTest(10, SI.METER);
+    }
+    
+    
+    public void testVisitPolygonSymbolizer_ScaleFoot1()
+    {
+        visitPolygonSymbolizerTest(1, NonSI.FOOT);
+    }
+    
+    
+    public void testVisitPolygonSymbolizer_ScaleFoot10()
+    {
+        visitPolygonSymbolizerTest(10, NonSI.FOOT);
+    }
+
+    
+    // TEXT SYMBOLIZER TESTS
+    
+    public void testVisitTextSymbolizer_ScalePixelNull()
+    {
+        visitTextSymbolizerTest(10, null);
+    }
+    
+    
+    public void testVisitTextSymbolizer_ScalePixelExplicit()
+    {
+        visitTextSymbolizerTest(10, NonSI.PIXEL);
+    }
+    
+    
+    public void testVisitTextSymbolizer_ScaleMeter1()
+    {
+        visitTextSymbolizerTest(1, SI.METER);
+    }
+    
+    
+    public void testVisitTextSymbolizer_ScaleMeter10()
+    {
+        visitTextSymbolizerTest(10, SI.METER);
+    }
+    
+    
+    public void testVisitTextSymbolizer_ScaleFoot1()
+    {
+        visitTextSymbolizerTest(1, NonSI.FOOT);
+    }
+    
+    
+    public void testVisitTextSymbolizer_ScaleFoot10()
+    {
+        visitTextSymbolizerTest(10, NonSI.FOOT);
+    }
+
+
+    // EXTRA TESTS
+    
+    public void testVisitLineSymbolizer_NullStroke()
+    {
+        try
+        {
+            UomRescaleStyleVisitor visitor = null;
+            
+            StyleBuilder styleBuilder = new StyleBuilder();
+
+            Stroke stroke = null;
+            LineSymbolizerImpl lineSymb = (LineSymbolizerImpl) styleBuilder.createLineSymbolizer(stroke);
+            lineSymb.setUnitOfMeasure(SI.METER);
+            
+            visitor = new UomRescaleStyleVisitor(10);
+
+            lineSymb.accept(visitor);
+            LineSymbolizer rescaledLineSymb = (LineSymbolizer) visitor.getCopy();
+            
+            Assert.assertNull(rescaledLineSymb.getStroke());
+            Assert.assertNotSame(rescaledLineSymb, lineSymb);
+        }
+        catch (Exception e2)
+        {
+            e2.printStackTrace();
+            Assert.fail(e2.getClass().getSimpleName() + " should not be thrown.");
+        }
+    }
+    
+    
+    public void testVisitPolygonSymbolizer_NullStroke()
+    {
+        try
+        {
+            UomRescaleStyleVisitor visitor = null;
+            
+            StyleBuilder styleBuilder = new StyleBuilder();
+
+            Fill fill = styleBuilder.createFill(Color.RED);
+            PolygonSymbolizerImpl polySymb = (PolygonSymbolizerImpl) styleBuilder.createPolygonSymbolizer(null, fill);
+            
+            visitor = new UomRescaleStyleVisitor(10);
+
+            polySymb.accept(visitor);
+            PolygonSymbolizer rescaledPolySymb = (PolygonSymbolizer) visitor.getCopy();
+            
+            Assert.assertEquals(polySymb.getFill(), rescaledPolySymb.getFill());
+            Assert.assertNull(rescaledPolySymb.getStroke());
+            Assert.assertNotSame(rescaledPolySymb, polySymb);
+        }
+        catch (Exception e2)
+        {
+            e2.printStackTrace();
+            Assert.fail(e2.getClass().getSimpleName() + " should not be thrown.");
+        }
+    }
+    
+    
+    public void testVisitTextSymbolizer_LinePlacement()
+    {
+        try
+        {
+            UomRescaleStyleVisitor visitor = null;
+            
+            Unit<Length> uom = SI.METER;
+            int fontSize = 100;
+            double perpOffset = 13;
+            double gap = 7;
+            double initialGap = 5;
+            double scaleMetersToPixel = 17;
+            double expectedRescaledFontSize = computeExpectedRescaleSize(fontSize, scaleMetersToPixel, uom);
+            double expectedRescaledPerpOffset = computeExpectedRescaleSize(perpOffset, scaleMetersToPixel, uom);
+            double expectedRescaledGap = computeExpectedRescaleSize(gap, scaleMetersToPixel, uom);
+            double expectedRescaledInitialGap = computeExpectedRescaleSize(initialGap, scaleMetersToPixel, uom);
+            
+            StyleBuilder styleBuilder = new StyleBuilder();
+
+            TextSymbolizerImpl textSymb = (TextSymbolizerImpl) styleBuilder.createTextSymbolizer();
+            textSymb.setUnitOfMeasure(uom);
+            
+            Font font = styleBuilder.createFont(new java.awt.Font("Verdana",java.awt.Font.PLAIN,fontSize));
+            textSymb.setFont(font);
+            
+            LinePlacement placement = styleBuilder.createLinePlacement(perpOffset);
+            placement.setGap(styleBuilder.literalExpression(gap));
+            placement.setInitialGap(styleBuilder.literalExpression(initialGap));
+            
+            textSymb.setLabelPlacement(placement);
+            
+            visitor = new UomRescaleStyleVisitor(scaleMetersToPixel);
+
+            textSymb.accept(visitor);
+            TextSymbolizer rescaledTextSymb = (TextSymbolizer) visitor.getCopy();
+            
+            double rescaledFontSize = rescaledTextSymb.getFont().getSize().evaluate(null, Double.class);
+            LinePlacement rescaledPlacement = (LinePlacement) rescaledTextSymb.getLabelPlacement();
+            double rescaledPerpOffset = rescaledPlacement.getPerpendicularOffset().evaluate(null, Double.class);
+            double rescaledGap = rescaledPlacement.getGap().evaluate(null, Double.class);
+            double rescaledInitialGap = rescaledPlacement.getInitialGap().evaluate(null, Double.class);
+            
+            Assert.assertEquals(Math.round(expectedRescaledFontSize), Math.round(rescaledFontSize));
+            Assert.assertEquals(Math.round(expectedRescaledPerpOffset), Math.round(rescaledPerpOffset));
+            Assert.assertEquals(Math.round(expectedRescaledGap), Math.round(rescaledGap));
+            Assert.assertEquals(Math.round(expectedRescaledInitialGap), Math.round(rescaledInitialGap));
+            Assert.assertNotSame(rescaledTextSymb, textSymb);
+        }
+        catch (Exception e2)
+        {
+            e2.printStackTrace();
+            Assert.fail(e2.getClass().getSimpleName() + " should not be thrown.");
+        }
+    }
+    
+    
+    public void testVisitLineSymbolizer_ExpressionWithFeatureAttribute()
+    {
+        try
+        {
+            double widthValue = 13;
+            double scaleMetersToPixel = 17;
+            Unit<Length> uom = SI.METER;
+        	
+            StyleBuilder styleBuilder = new StyleBuilder();
+            UomRescaleStyleVisitor visitor = null;
+
+            // creates the feature used for the test
+            SimpleFeatureTypeBuilder featureTypeBuilder = new SimpleFeatureTypeBuilder();
+            featureTypeBuilder.setName("TestType");
+            featureTypeBuilder.add("geom", LineString.class, DefaultGeographicCRS.WGS84);
+            featureTypeBuilder.add("width", Double.class);
+            SimpleFeatureType featureType = featureTypeBuilder.buildFeatureType();
+            
+            GeometryFactory geomFactory = new GeometryFactory();
+            Geometry geom = geomFactory.createLineString(new Coordinate[] { new Coordinate(1,1), new Coordinate(2,2) });
+            
+            SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
+            featureBuilder.set("geom", geom);
+            featureBuilder.set("width", widthValue);
+            SimpleFeature feature = featureBuilder.buildFeature("1");
+            
+
+            // creates the symbolizer for the test
+            Expression color = styleBuilder.colorExpression(Color.RED);
+            Expression width = styleBuilder.attributeExpression("width");
+            Stroke stroke = styleBuilder.createStroke(color, width);
+            LineSymbolizerImpl lineSymb = (LineSymbolizerImpl) styleBuilder.createLineSymbolizer(stroke);
+            lineSymb.setUnitOfMeasure(uom);
+
+            
+            // rescales symbolizer
+            visitor = new UomRescaleStyleVisitor(scaleMetersToPixel);
+
+            lineSymb.accept(visitor);
+            LineSymbolizer rescaledLineSymb = (LineSymbolizer) visitor.getCopy();
+
+            
+            // tests results
+            org.opengis.style.Stroke rescaledStroke = rescaledLineSymb.getStroke();
+            Expression rescaledWidth = rescaledStroke.getWidth();
+            double rescaledWidthValue = rescaledWidth.evaluate(feature, Double.class);
+            double expectedRescaledWidthValue = computeExpectedRescaleSize(widthValue, scaleMetersToPixel, uom); 
+            
+            Assert.assertEquals(stroke.getColor(), rescaledStroke.getColor());
+            Assert.assertEquals(expectedRescaledWidthValue, rescaledWidthValue);
+            Assert.assertNotSame(SI.METER, rescaledLineSymb.getUnitOfMeasure());
+            Assert.assertNotSame(rescaledLineSymb, lineSymb);
+        }
+        catch (Exception e2)
+        {
+            e2.printStackTrace();
+            Assert.fail(e2.getClass().getSimpleName() + " should not be thrown.");
+        }
+    }
+}
diff --git a/modules/library/render/src/main/java/org/geotools/renderer/lite/RendererUtilities.java b/modules/library/render/src/main/java/org/geotools/renderer/lite/RendererUtilities.java
index efb14aa..a03637a 100644
--- a/modules/library/render/src/main/java/org/geotools/renderer/lite/RendererUtilities.java
+++ b/modules/library/render/src/main/java/org/geotools/renderer/lite/RendererUtilities.java
@@ -389,6 +389,26 @@ public final class RendererUtilities {
     
     final static double OGC_DEGREE_TO_METERS = 6378137.0 * 2.0 * Math.PI / 360;
     
+    
+	/**
+	 * Calculates the pixels per meter ratio based on a scale denominator.
+	 * 
+	 * @param scaleDenominator
+	 *            The scale denominator value.
+	 * @param hints
+	 *            The hints used in calculation. if "dpi" key is present, it
+	 *            uses it's Integer value as the dpi of the current device. if
+	 *            not it uses 90 that is the OGC default value.
+	 * @return The pixels per meter ratio for the given scale denominator.
+	 */
+	public static double calculatePixelsPerMeterRatio(double scaleDenominator, Map hints) {
+		if (scaleDenominator <= 0.0)
+			throw new IllegalArgumentException("The scale denominator must be positive.");
+		double scale = 1.0 / scaleDenominator;
+		return scale * (getDpi(hints) / 0.0254);
+	}
+    
+    
     /**
      * This method performs the computation using the methods suggested by the OGC SLD specification, page 26.
      * @param envelope
diff --git a/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java b/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java
index 338ca35..0b86cbb 100644
--- a/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java
+++ b/modules/library/render/src/main/java/org/geotools/renderer/lite/StreamingRenderer.java
@@ -49,7 +49,6 @@ import org.geotools.coverage.grid.GridGeometry2D;
 import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
 import org.geotools.coverage.grid.io.AbstractGridFormat;
 import org.geotools.data.DataUtilities;
-import org.geotools.data.DefaultQuery;
 import org.geotools.data.FeatureSource;
 import org.geotools.data.Query;
 import org.geotools.data.crs.ForceCoordinateSystemFeatureResults;
@@ -59,7 +58,6 @@ import org.geotools.factory.CommonFactoryFinder;
 import org.geotools.factory.Hints;
 import org.geotools.feature.FeatureCollection;
 import org.geotools.feature.FeatureTypes;
-import org.geotools.feature.IllegalAttributeException;
 import org.geotools.filter.IllegalFilterException;
 import org.geotools.filter.function.GeometryTransformationVisitor;
 import org.geotools.filter.visitor.SimplifyingFilterVisitor;
@@ -90,6 +88,7 @@ import org.geotools.styling.Rule;
 import org.geotools.styling.StyleAttributeExtractor;
 import org.geotools.styling.Symbolizer;
 import org.geotools.styling.TextSymbolizer;
+import org.geotools.styling.visitor.UomRescaleStyleVisitor;
 import org.geotools.util.NumberRange;
 import org.geotools.util.Range;
 import org.opengis.coverage.grid.GridCoverage;
@@ -759,19 +758,19 @@ public final class StreamingRenderer implements GTRenderer {
     //TODO: Implement filtering for bbox and read in only the need attributes 
     Collection queryLayer(MapLayer currLayer, CollectionSource source) {
         //REVISIT: this method does not make sense. Always compares
-        //new DefaultQuery(DefaultQuery.ALL) for reference equality with Query.All. GR.
+        //new Query(Query.ALL) for reference equality with Query.All. GR.
 
         Collection results = null;
-        DefaultQuery query = new DefaultQuery(DefaultQuery.ALL);
+        Query query = new Query(Query.ALL);
         Query definitionQuery;
 
         definitionQuery = currLayer.getQuery();
 
         if (definitionQuery != Query.ALL) {
             if (query == Query.ALL) {
-                query = new DefaultQuery(definitionQuery);
+                query = new Query(definitionQuery);
             } else {
-                query = new DefaultQuery(DataUtilities.mixQueries(definitionQuery, query, "liteRenderer"));
+                query = new Query(DataUtilities.mixQueries(definitionQuery, query, "liteRenderer"));
             }
         }
 
@@ -829,7 +828,6 @@ public final class StreamingRenderer implements GTRenderer {
      * @throws IllegalFilterException
      *             if something goes wrong constructing the bbox filter
      * @throws IOException
-     * @throws IllegalAttributeException
      * @see MapLayer#setQuery(org.geotools.data.Query)
      */
     /*
@@ -842,10 +840,9 @@ public final class StreamingRenderer implements GTRenderer {
             CoordinateReferenceSystem featCrs, Rectangle screenSize,
             GeometryDescriptor geometryAttribute,
             AffineTransform worldToScreenTransform)
-            throws IllegalFilterException, IOException,
-            IllegalAttributeException {
+            throws IllegalFilterException, IOException {
         FeatureCollection<SimpleFeatureType, SimpleFeature> results = null;
-        DefaultQuery query = new DefaultQuery(DefaultQuery.ALL);
+        Query query = new Query(Query.ALL);
         Query definitionQuery;
         final int length;
         Filter filter = null;
@@ -902,7 +899,7 @@ public final class StreamingRenderer implements GTRenderer {
 
                 // now build the query using only the attributes and the
                 // bounding box needed
-                query = new DefaultQuery(schema.getTypeName());
+                query = new Query(schema.getTypeName());
                 query.setFilter(filter);
                 query.setPropertyNames(attributes);
                 processRuleForQuery(styles, query);
@@ -910,7 +907,7 @@ public final class StreamingRenderer implements GTRenderer {
             } catch (Exception e) {
                 fireErrorEvent(new Exception("Error transforming bbox", e));
                 canTransform = false;
-                query = new DefaultQuery(schema.getTypeName());
+                query = new Query(schema.getTypeName());
                 query.setPropertyNames(attributes);
                 Envelope bounds = source.getBounds();
                 if (bounds != null && envelope.intersects(bounds)) {
@@ -937,9 +934,9 @@ public final class StreamingRenderer implements GTRenderer {
 
         if (definitionQuery != Query.ALL) {
             if (query == Query.ALL) {
-                query = new DefaultQuery(definitionQuery);
+                query = new Query(definitionQuery);
             } else {
-                query = new DefaultQuery(DataUtilities.mixQueries(
+                query = new Query(DataUtilities.mixQueries(
                         definitionQuery, query, "liteRenderer"));
             }
         }
@@ -1101,8 +1098,7 @@ public final class StreamingRenderer implements GTRenderer {
      * @param q
      */
 
-    private void processRuleForQuery(LiteFeatureTypeStyle[] styles,
-            DefaultQuery q) {
+    private void processRuleForQuery(LiteFeatureTypeStyle[] styles, Query q) {
         try {
 
             // first we check to see if there are >
@@ -1550,6 +1546,8 @@ public final class StreamingRenderer implements GTRenderer {
         return result;
     }
 
+
+
     private boolean isFeatureTypeStyleActive(SimpleFeatureType ftype, FeatureTypeStyle fts) {
         return ((ftype.getTypeName() != null)
                 && (ftype.getTypeName().equalsIgnoreCase(fts.getFeatureTypeName()) || 
@@ -1716,14 +1714,12 @@ public final class StreamingRenderer implements GTRenderer {
      * @param screenSize
      * @param layerId 
      * @throws IOException
-     * @throws IllegalAttributeException
      * @throws IllegalFilterException
      */
     final private void processStylers(final Graphics2D graphics,
             MapLayer currLayer, AffineTransform at,
             CoordinateReferenceSystem destinationCrs, Envelope mapArea,
-            Rectangle screenSize, String layerId) throws IllegalFilterException, IOException,
-            IllegalAttributeException {
+            Rectangle screenSize, String layerId) throws IllegalFilterException, IOException {
 
         /*
          * DJB: changed this a wee bit so that it now does the layer query AFTER
@@ -1745,7 +1741,7 @@ public final class StreamingRenderer implements GTRenderer {
 
         final CoordinateReferenceSystem sourceCrs;
         final NumberRange scaleRange = new NumberRange(scaleDenominator,scaleDenominator);
-        final ArrayList lfts ;
+        final ArrayList<LiteFeatureTypeStyle> lfts ;
 
         if ( featureSource != null ) {
             final SimpleFeatureType schema = featureSource.getSchema();
@@ -1762,6 +1758,8 @@ public final class StreamingRenderer implements GTRenderer {
             lfts = createLiteFeatureTypeStyles(featureStylers,schema, graphics);
             if(lfts.size() == 0)
                 return;
+            
+            applyUnitRescale(lfts);
 
             LiteFeatureTypeStyle[] featureTypeStyleArray = (LiteFeatureTypeStyle[]) lfts.toArray(new LiteFeatureTypeStyle[lfts.size()]);
             // /////////////////////////////////////////////////////////////////////
@@ -1786,18 +1784,42 @@ public final class StreamingRenderer implements GTRenderer {
 
             sourceCrs = null;
             lfts = createLiteFeatureTypeStyles( featureStylers, source.describe(), graphics );
+            applyUnitRescale(lfts);
         }
 
         if (lfts.size() == 0) return; // nothing to do
 
-
-        if(isOptimizedFTSRenderingEnabled())
+        // finally, perform rendering
+        if(isOptimizedFTSRenderingEnabled()) {
             drawOptimized(graphics, currLayer, at, destinationCrs, layerId, collection, features,
                     scaleRange, lfts);
-        else
+        } else {
             drawPlain(graphics, currLayer, at, destinationCrs, layerId, collection, features,
                     scaleRange, lfts);
+        }
+    }
 
+    /**
+     * Applies Unit Of Measure rescaling against all symbolizers, the result will be symbolizers
+     * that operate purely in pixels
+     * @param lfts
+     */
+    void applyUnitRescale(final ArrayList<LiteFeatureTypeStyle> lfts) {
+        // apply UOM rescaling
+        double pixelsPerMeters = RendererUtilities.calculatePixelsPerMeterRatio(scaleDenominator, rendererHints);
+        UomRescaleStyleVisitor rescaleVisitor = new UomRescaleStyleVisitor(pixelsPerMeters);
+        for(LiteFeatureTypeStyle fts : lfts) {
+            for (int i = 0; i < fts.ruleList.length; i++) {
+                rescaleVisitor.visit(fts.ruleList[i]);
+                fts.ruleList[i] = (Rule) rescaleVisitor.getCopy();
+            }
+            if(fts.elseRules != null) {
+                for (int i = 0; i < fts.elseRules.length; i++) {
+                    rescaleVisitor.visit(fts.elseRules[i]);
+                    fts.elseRules[i] = (Rule) rescaleVisitor.getCopy();
+                }
+            }
+        }
     }
 
     /**
diff --git a/modules/library/render/src/main/java/org/geotools/renderer/lite/StyledShapePainter.java b/modules/library/render/src/main/java/org/geotools/renderer/lite/StyledShapePainter.java
index 1055131..da7f655 100644
--- a/modules/library/render/src/main/java/org/geotools/renderer/lite/StyledShapePainter.java
+++ b/modules/library/render/src/main/java/org/geotools/renderer/lite/StyledShapePainter.java
@@ -202,7 +202,12 @@ public final class StyledShapePainter {
 					fillLiteShape(graphics, shape);
 				}
 				if (ps2d.getGraphicFill() != null) {
+				    Shape oldClip = graphics.getClip();
+				    try {
 					paintGraphicFill(graphics, shape, ps2d.getGraphicFill(), scale);
+				    } finally {
+				        graphics.setClip(oldClip);
+				    }
 				}
 			}
 
@@ -546,11 +551,30 @@ public final class StyledShapePainter {
         g.clip(shape);
         // retrieves the full clip region
         Shape clipShape = g.getClip();
+        Rectangle2D boundsClip = clipShape.getBounds2D();
+        
+        // adjust the iteration indexes to avoid iterating a lot over areas that we won't be rendering
+        int fromX = 0;
+        if(boundsClip.getMinX() > boundsShape.getMinX()) {
+            fromX = (int) Math.floor((boundsClip.getMinX() - boundsShape.getMinX()) / stippleSize.getWidth());
+        }
+        if(boundsClip.getMaxX() < boundsShape.getMaxX()) {
+            nStippleX -= (int) Math.floor((boundsShape.getMaxX() - boundsClip.getMaxX()) / stippleSize.getWidth());
+        }
+        
+        // adjust the iteration indexes to avoid iterating a lot over areas that we won't be rendering
+        int fromY = 0;
+        if(boundsClip.getMinY() > boundsShape.getMinY()) {
+            fromY = (int) Math.floor((boundsClip.getMinY() - boundsShape.getMinY()) / stippleSize.getHeight());
+        }
+        if(boundsClip.getMaxY() < boundsShape.getMaxY()) {
+            nStippleY -= (int) Math.floor((boundsShape.getMaxY() - boundsClip.getMaxY()) / stippleSize.getHeight());
+        }
         
         // paints graphic fill as a stipple
-        for (int i = 0; i < nStippleX; i++)
+        for (int i = fromX; i < nStippleX; i++)
         {
-            for (int j = 0; j < nStippleY; j++)
+            for (int j = fromY; j < nStippleY; j++)
             {
             	// computes this stipple's shift in the X and Y directions
             	double translateX = boundsShape.getMinX() + i * stippleSize.getWidth();
diff --git a/modules/library/render/src/main/java/org/geotools/renderer/style/RescaledIcon.java b/modules/library/render/src/main/java/org/geotools/renderer/style/RescaledIcon.java
new file mode 100644
index 0000000..f9feff2
--- /dev/null
+++ b/modules/library/render/src/main/java/org/geotools/renderer/style/RescaledIcon.java
@@ -0,0 +1,48 @@
+package org.geotools.renderer.style;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+
+import javax.swing.Icon;
+
+class RescaledIcon implements Icon {
+    double scale;
+    Icon icon;
+    
+    public RescaledIcon(Icon icon, double scale) {
+        this.icon = icon;
+        this.scale = scale;
+    }
+
+    public int getIconHeight() {
+        return (int) Math.round(icon.getIconHeight() * scale);
+    }
+
+    public int getIconWidth() {
+        return (int) Math.round(icon.getIconWidth() * scale);
+    }
+
+    public void paintIcon(Component c, Graphics g, int x, int y) {
+        Graphics2D g2d = (Graphics2D) g;
+        AffineTransform tmp = g2d.getTransform();
+        Object oldInterpolation = g2d.getRenderingHint(RenderingHints.KEY_INTERPOLATION);
+        if(oldInterpolation == null) {
+            oldInterpolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
+        }
+        try {
+            AffineTransform at = new AffineTransform(tmp);
+            at.translate(x, y);
+            at.scale(scale, scale);
+            g2d.setTransform(at);
+            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+            icon.paintIcon(c, g2d, 0, 0);
+        } finally {
+            g2d.setTransform(tmp);
+            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, oldInterpolation);
+        }
+    }
+
+}
diff --git a/modules/library/render/src/main/java/org/geotools/renderer/style/SLDStyleFactory.java b/modules/library/render/src/main/java/org/geotools/renderer/style/SLDStyleFactory.java
index 13c3b03..d61f0a0 100644
--- a/modules/library/render/src/main/java/org/geotools/renderer/style/SLDStyleFactory.java
+++ b/modules/library/render/src/main/java/org/geotools/renderer/style/SLDStyleFactory.java
@@ -122,6 +122,11 @@ This change could affect the j2d renderer as it appears to use the
 public class SLDStyleFactory {
     /** The logger for the rendering module. */
     private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.rendering");
+    
+    /**
+     * The threshold at which we switch from pre-rasterized icons to dynamically painted ones (to avoid OOM) 
+     */
+    private static final int MAX_RASTERIZATION_SIZE = 512; 
 
     /** Holds a lookup bewteen SLD names and java constants. */
     private static final java.util.Map joinLookup = new java.util.HashMap();
@@ -181,8 +186,8 @@ public class SLDStyleFactory {
     /**
      * Holds value of property mapScaleDenominator.
      */
-    private double mapScaleDenominator = Double.NaN;;
-
+    private double mapScaleDenominator = Double.NaN;
+    
     /**
      * The factory builds a fair number of buffered images to deal with
      * external graphics that need resizing and the like. This hints will
@@ -383,16 +388,19 @@ public class SLDStyleFactory {
         if (fill == null)
         	return;
         
-        // sets Style2D fill
-        if (fill.getGraphicFill() != null && isVectorRenderingEnabled()) {
-        	// sets graphic fill if available and vector rendering is enabled
-        	Style2D style2DFill = createPointStyle(feature, fill.getGraphicFill(), scaleRange);
-        	style.setGraphicFill(style2DFill);
-        } else {
-            //otherwise, sets regular fill using Java raster-based Paint objects
-            style.setFill(getPaint(symbolizer.getFill(), feature));
-            style.setFillComposite(getComposite(symbolizer.getFill(), feature));
-        }
+        // sets Style2D fill making sure we don't use too much memory for the rasterization
+        if (fill.getGraphicFill() != null) {
+            double size = evalToDouble(fill.getGraphicFill().getSize(), feature, 0);
+            if(isVectorRenderingEnabled() || size > MAX_RASTERIZATION_SIZE) {
+             // sets graphic fill if available and vector rendering is enabled
+                Style2D style2DFill = createPointStyle(feature, fill.getGraphicFill(), scaleRange);
+                style.setGraphicFill(style2DFill);
+                return ;
+            }
+        } 
+        //otherwise, sets regular fill using Java raster-based Paint objects
+        style.setFill(getPaint(symbolizer.getFill(), feature));
+        style.setFillComposite(getComposite(symbolizer.getFill(), feature));
     }
 
     Style2D createDynamicPolygonStyle(SimpleFeature feature, PolygonSymbolizer symbolizer,
@@ -511,17 +519,23 @@ public class SLDStyleFactory {
                 }
                 eg = (ExternalGraphic) symbol;
                 
-                if(vectorRenderingEnabled) {
-                    Icon icon = getIcon(eg, feature, (int) size);
+                // if the icon size becomes too big we switch to vector rendering too, since
+                // pre-rasterizing and caching the result will use too much memory
+                if(vectorRenderingEnabled || size > MAX_RASTERIZATION_SIZE) {
+                    Icon icon = getIcon(eg, feature, -1);
                     if(icon == null) {
                         // no icon -> no image either, there is no raster fallback
                         continue;
                     } else {
+                        if(icon.getIconHeight() != size) {
+                            double scale = ((double) size) / icon.getIconHeight(); 
+                            icon = new RescaledIcon(icon, scale);
+                        }
                         retval = new IconStyle2D(icon, feature, displacementX, displacementY, rotation, composite);
                         break;
                     }
                 } else {
-    	            img = getImage(eg, (Feature) feature, (int) size);
+    	            img = getImage(eg, (Feature) feature, size);
                     if (img == null) {
                         continue;
                     } else {
@@ -579,6 +593,21 @@ public class SLDStyleFactory {
         return retval;
     }
 
+    /**
+     * Turns a floating point style into a integer size useful to specify the size of a
+     * BufferedImage. Will return 1 between 0 and 1 (0 excluded), will otherwise round the
+     * size to integer.
+     * @param size
+     * @return
+     */
+    int toImageSize(double size) {
+        if(size > 0 && size < 0.5d) {
+            return 1;
+        } else {
+            return (int) Math.round(size);
+        }
+    }
+
     Style2D createTextStyle(Object feature, TextSymbolizer symbolizer, Range scaleRange) {
         TextStyle2D ts2d = new TextStyle2D();
         setScaleRange(ts2d, scaleRange);
@@ -935,7 +964,7 @@ public class SLDStyleFactory {
      */
     public TexturePaint getTexturePaint(org.geotools.styling.Graphic gr, Object feature) {
         // -1 to have the image use its natural size if none was provided by the user
-        int graphicSize = evalToInt(gr.getSize(), feature, -1);
+        double graphicSize = evalToDouble(gr.getSize(), feature, -1);
         BufferedImage image = getImage(gr, feature, graphicSize);
 
         int iSizeX; 
@@ -1025,7 +1054,7 @@ public class SLDStyleFactory {
      * @param size
      * @return
      */
-    private BufferedImage getImage(Graphic graphic, Object feature, int size) {
+    private BufferedImage getImage(Graphic graphic, Object feature, double size) {
         if(graphic == null)
             return null;
         
@@ -1049,8 +1078,8 @@ public class SLDStyleFactory {
      * @param size
      * @return the image, or null if the external graphics could not be interpreted
      */
-    private BufferedImage getImage(ExternalGraphic eg, Object feature, int size) {
-        Icon icon = getIcon(eg, feature, size);
+    private BufferedImage getImage(ExternalGraphic eg, Object feature, double size) {
+        Icon icon = getIcon(eg, feature, toImageSize(size));
         if(icon != null)
             return rasterizeIcon(icon);
         
@@ -1064,7 +1093,7 @@ public class SLDStyleFactory {
      * @param size
      * @return the image, or null if the external graphics could not be interpreted
      */
-    private Icon getIcon(ExternalGraphic eg, Object feature, int size) {
+    private Icon getIcon(ExternalGraphic eg, Object feature, double size) {
         if(eg == null)
             return null;
         
@@ -1092,7 +1121,7 @@ public class SLDStyleFactory {
         Iterator<ExternalGraphicFactory> it  = DynamicSymbolFactoryFinder.getExternalGraphicFactories();
         while(it.hasNext()) {
             try {
-                Icon icon = it.next().getIcon((Feature) feature, location, eg.getFormat(), size);
+                Icon icon = it.next().getIcon((Feature) feature, location, eg.getFormat(), toImageSize(size));
                 if(icon != null) {
                     return icon;
                 }
diff --git a/modules/unsupported/shapefile-renderer/src/main/java/org/geotools/renderer/shape/ShapefileRenderer.java b/modules/unsupported/shapefile-renderer/src/main/java/org/geotools/renderer/shape/ShapefileRenderer.java
index 22922a4..9b994cc 100644
--- a/modules/unsupported/shapefile-renderer/src/main/java/org/geotools/renderer/shape/ShapefileRenderer.java
+++ b/modules/unsupported/shapefile-renderer/src/main/java/org/geotools/renderer/shape/ShapefileRenderer.java
@@ -85,6 +85,7 @@ import org.geotools.renderer.RenderListener;
 import org.geotools.renderer.label.LabelCacheImpl;
 import org.geotools.renderer.lite.LabelCache;
 import org.geotools.renderer.lite.LabelCacheDefault;
+import org.geotools.renderer.lite.LiteFeatureTypeStyle;
 import org.geotools.renderer.lite.RendererUtilities;
 import org.geotools.renderer.lite.StreamingRenderer;
 import org.geotools.renderer.style.SLDStyleFactory;
@@ -99,6 +100,7 @@ import org.geotools.styling.StyleAttributeExtractor;
 import org.geotools.styling.Symbolizer;
 import org.geotools.styling.TextSymbolizer;
 import org.geotools.styling.visitor.DuplicatingStyleVisitor;
+import org.geotools.styling.visitor.UomRescaleStyleVisitor;
 import org.geotools.util.NumberRange;
 import org.opengis.feature.simple.SimpleFeature;
 import org.opengis.feature.simple.SimpleFeatureType;
@@ -325,8 +327,8 @@ public class ShapefileRenderer implements GTRenderer {
                     || typeName .equalsIgnoreCase(fts.getFeatureTypeName()))) {
                 // get applicable rules at the current scale
                 Rule[] rules = fts.getRules();
-                List ruleList = new ArrayList();
-                List elseRuleList = new ArrayList();
+                List<Rule> ruleList = new ArrayList<Rule>();
+                List<Rule> elseRuleList = new ArrayList<Rule>();
                 
                 // TODO process filter for geometry expressions and restrict bbox further based on 
                 // the result
@@ -363,6 +365,18 @@ public class ShapefileRenderer implements GTRenderer {
                     }
                 }
 
+                // apply uom rescaling
+                double pixelsPerMeters = RendererUtilities.calculatePixelsPerMeterRatio(scaleDenominator, rendererHints);
+                UomRescaleStyleVisitor rescaleVisitor = new UomRescaleStyleVisitor(pixelsPerMeters);
+                for (int j = 0; j < ruleList.size(); j++) {
+                    rescaleVisitor.visit(ruleList.get(j));
+                    ruleList.set(j, (Rule) rescaleVisitor.getCopy());
+                }
+                for (int j = 0; j < elseRuleList.size(); j++) {
+                    rescaleVisitor.visit(elseRuleList.get(j));
+                    elseRuleList.set(j, (Rule) rescaleVisitor.getCopy());
+                }
+
                 // process the features according to the rules
                 // TODO: find a better way to declare the scale ranges so that
                 // we
