Changeset 7054 in josm for trunk/src/org/openstreetmap


Ignore:
Timestamp:
2014-05-03T01:07:19+02:00 (11 years ago)
Author:
bastiK
Message:

mapcss: major performance improvement for style creation, "rendering phase 1" (see #9691)

Location:
trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java

    r7033 r7054  
    1919import org.openstreetmap.josm.data.osm.Node;
    2020import org.openstreetmap.josm.data.osm.OsmPrimitive;
     21import org.openstreetmap.josm.data.osm.Relation;
     22import org.openstreetmap.josm.data.osm.Way;
    2123import org.openstreetmap.josm.gui.mappaint.Cascade;
    2224import org.openstreetmap.josm.gui.mappaint.Environment;
     
    2426import org.openstreetmap.josm.gui.mappaint.Range;
    2527import org.openstreetmap.josm.gui.mappaint.StyleSource;
     28import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
    2629import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.GeneralSelector;
     30import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.OptimizedGeneralSelector;
    2731import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser;
    2832import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.ParseException;
     
    4246    public static final String MAPCSS_STYLE_MIME_TYPES = "text/x-mapcss, text/mapcss, text/css; q=0.9, text/plain; q=0.8, application/zip, application/octet-stream; q=0.5";
    4347
    44     public final List<MapCSSRule> rules;
     48    // all rules
     49    public final List<MapCSSRule> rules = new ArrayList<>();
     50    // rules filtered by primitive type
     51    public final List<MapCSSRule> nodeRules = new ArrayList<>();
     52    public final List<MapCSSRule> wayRules = new ArrayList<>();
     53    public final List<MapCSSRule> relationRules = new ArrayList<>();
     54    public final List<MapCSSRule> multipolygonRules = new ArrayList<>();
     55   
    4556    private Color backgroundColorOverride;
    4657    private String css = null;
     
    4960    public MapCSSStyleSource(String url, String name, String shortdescription) {
    5061        super(url, name, shortdescription);
    51         rules = new ArrayList<>();
    5262    }
    5363
    5464    public MapCSSStyleSource(SourceEntry entry) {
    5565        super(entry);
    56         rules = new ArrayList<>();
    5766    }
    5867
     
    6877        CheckParameterUtil.ensureParameterNotNull(css);
    6978        this.css = css;
    70         rules = new ArrayList<>();
    7179    }
    7280
     
    7583        init();
    7684        rules.clear();
     85        nodeRules.clear();
     86        wayRules.clear();
     87        relationRules.clear();
     88        multipolygonRules.clear();
    7789        try (InputStream in = getSourceInputStream()) {
    7890            try {
     
    104116            logError(new ParseException(e.getMessage())); // allow e to be garbage collected, it links to the entire token stream
    105117        }
    106     }
    107 
     118        // optimization: filter rules for different primitive types
     119        for (MapCSSRule r: rules) {
     120            List<Selector> nodeSel = new ArrayList<>();
     121            List<Selector> waySel = new ArrayList<>();
     122            List<Selector> relationSel = new ArrayList<>();
     123            List<Selector> multipolygonSel = new ArrayList<>();
     124            for (Selector sel : r.selectors) {
     125                // find the rightmost selector, this must be a GeneralSelector
     126                Selector selRightmost = sel;
     127                while (selRightmost instanceof ChildOrParentSelector) {
     128                    selRightmost = ((ChildOrParentSelector) selRightmost).right;
     129                }
     130                Selector optimizedSel = sel.optimizedBaseCheck();
     131                switch (((GeneralSelector) selRightmost).getBase()) {
     132                    case "node":
     133                        nodeSel.add(optimizedSel);
     134                        break;
     135                    case "way":
     136                        waySel.add(optimizedSel);
     137                        break;
     138                    case "area":
     139                        waySel.add(optimizedSel);
     140                        multipolygonSel.add(optimizedSel);
     141                        break;
     142                    case "relation":
     143                        relationSel.add(optimizedSel);
     144                        multipolygonSel.add(optimizedSel);
     145                        break;
     146                    case "*":
     147                        nodeSel.add(optimizedSel);
     148                        waySel.add(optimizedSel);
     149                        relationSel.add(optimizedSel);
     150                        multipolygonSel.add(optimizedSel);
     151                        break;
     152                }
     153            }
     154            nodeRules.add(new MapCSSRule(nodeSel, r.declaration));
     155            wayRules.add(new MapCSSRule(waySel, r.declaration));
     156            relationRules.add(new MapCSSRule(relationSel, r.declaration));
     157            multipolygonRules.add(new MapCSSRule(multipolygonSel, r.declaration));
     158        }
     159        rules.clear();
     160    }
     161   
    108162    @Override
    109163    public InputStream getSourceInputStream() throws IOException {
     
    188242    public void apply(MultiCascade mc, OsmPrimitive osm, double scale, OsmPrimitive multipolyOuterWay, boolean pretendWayIsClosed) {
    189243        Environment env = new Environment(osm, mc, null, this);
    190         RULE: for (MapCSSRule r : rules) {
     244        List<MapCSSRule> matchingRules;
     245        if (osm instanceof Node) {
     246            matchingRules = nodeRules;
     247        } else if (osm instanceof Way) {
     248            matchingRules = wayRules;
     249        } else {
     250            if (((Relation) osm).isMultipolygon()) {
     251                matchingRules = multipolygonRules;
     252            } else {
     253                matchingRules = relationRules;
     254            }
     255        }
     256        RULE: for (MapCSSRule r : matchingRules) {
    191257            for (Selector s : r.selectors) {
    192258                env.clearSelectorMatchingInformation();
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java

    r6990 r7054  
    2222import org.openstreetmap.josm.tools.Utils;
    2323
     24/**
     25 * MapCSS selector.
     26 *
     27 * A rule has two parts, a selector and a declaration block
     28 * e.g.
     29 * <pre>
     30 * way[highway=residential]   
     31 * { width: 10; color: blue; }
     32 * </pre>
     33 *
     34 * The selector decides, if the declaration block gets applied or not.
     35 *
     36 * Currently all implementing classes of Selector are immutable.
     37 */
    2438public interface Selector {
    2539
     
    3246     * @return true, if the selector applies
    3347     */
    34     public boolean matches(Environment env);
    35 
    36     public String getSubpart();
    37 
    38     public Range getRange();
     48    boolean matches(Environment env);
     49   
     50    String getSubpart();
     51
     52    Range getRange();
     53   
     54    /**
     55     * Create an "optimized" copy of this selector that omits the base check.
     56     *
     57     * For the style source, the list of rules is preprocessed, such that
     58     * there is a separate list of rules for nodes, ways, ...
     59     *
     60     * This means that the base check does not have to be performed
     61     * for each rule, but only once for each primitive.
     62     *
     63     * @return a selector that is identical to this object, except the base of the
     64     * "rightmost" selector is not checked
     65     */
     66    Selector optimizedBaseCheck();
    3967
    4068    public static enum ChildOrParentSelectorType {
     
    319347            return right.getRange();
    320348        }
     349       
     350        @Override
     351        public Selector optimizedBaseCheck() {
     352            return new ChildOrParentSelector(left, link, right.optimizedBaseCheck(), type);
     353        }
    321354
    322355        @Override
     
    348381         * @return {@code true} if all conditions apply, false otherwise.
    349382         */
    350         public final boolean matchesConditions(Environment env) {
     383        public boolean matches(Environment env) {
    351384            if (conds == null) return true;
    352385            for (Condition c : conds) {
     
    378411        public boolean matches(Environment env) {
    379412            Utils.ensure(env.isLinkContext(), "Requires LINK context in environment, got ''{0}''", env.getContext());
    380             return matchesConditions(env);
     413            return super.matches(env);
    381414        }
    382415
     
    392425
    393426        @Override
     427        public Selector optimizedBaseCheck() {
     428            throw new UnsupportedOperationException();
     429        }
     430
     431        @Override
    394432        public String toString() {
    395433            return "LinkSelector{" + "conditions=" + conds + '}';
     
    397435    }
    398436
    399     public static class GeneralSelector extends AbstractSelector {
     437    public static class GeneralSelector extends OptimizedGeneralSelector {
     438
     439        public GeneralSelector(String base, Pair<Integer, Integer> zoom, List<Condition> conds, String subpart) {
     440            super(base, zoom, conds, subpart);
     441        }
     442       
     443        public boolean matchesBase(OsmPrimitiveType type) {
     444            if ("*".equals(base)) {
     445                return true;
     446            } else if (OsmPrimitiveType.NODE.equals(type)) {
     447                return "node".equals(base);
     448            } else if (OsmPrimitiveType.WAY.equals(type)) {
     449                return "way".equals(base) || "area".equals(base);
     450            } else if (OsmPrimitiveType.RELATION.equals(type)) {
     451                return "area".equals(base) || "relation".equals(base) || "canvas".equals(base);
     452            }
     453            return false;
     454        }
     455
     456        public boolean matchesBase(OsmPrimitive p) {
     457            if (!matchesBase(p.getType())) {
     458                return false;
     459            } else {
     460                if (p instanceof Relation) {
     461                    if ("area".equals(base)) {
     462                        return ((Relation) p).isMultipolygon();
     463                    } else if ("canvas".equals(base)) {
     464                        return p.get("#canvas") != null;
     465                    }
     466                }
     467                return true;
     468            }
     469        }
     470
     471        public boolean matchesBase(Environment e) {
     472            return matchesBase(e.osm);
     473        }
     474       
     475        public boolean matchesConditions(Environment e) {
     476            return super.matches(e);
     477        }
     478
     479        @Override
     480        public Selector optimizedBaseCheck() {
     481            return new OptimizedGeneralSelector(this);
     482        }
     483
     484        @Override
     485        public boolean matches(Environment e) {
     486            return matchesBase(e) && super.matches(e);
     487        }
     488    }
     489   
     490    public static class OptimizedGeneralSelector extends AbstractSelector {
    400491        public final String base;
    401492        public final Range range;
    402493        public final String subpart;
    403494
    404         public GeneralSelector(String base, Pair<Integer, Integer> zoom, List<Condition> conds, String subpart) {
     495        public OptimizedGeneralSelector(String base, Pair<Integer, Integer> zoom, List<Condition> conds, String subpart) {
    405496            super(conds);
    406497            this.base = base;
     
    418509            this.subpart = subpart;
    419510        }
     511       
     512        public OptimizedGeneralSelector(String base, Range range, List<Condition> conds, String subpart) {
     513            super(conds);
     514            this.base = base;
     515            this.range = range;
     516            this.subpart = subpart;
     517        }
     518       
     519        public OptimizedGeneralSelector(GeneralSelector s) {
     520            this(s.base, s.range, s.conds, s.subpart);
     521        }
    420522
    421523        @Override
     
    428530        }
    429531
    430         public boolean matchesBase(OsmPrimitiveType type) {
    431             if ("*".equals(base)) {
    432                 return true;
    433             } else if (OsmPrimitiveType.NODE.equals(type)) {
    434                 return "node".equals(base);
    435             } else if (OsmPrimitiveType.WAY.equals(type)) {
    436                 return "way".equals(base) || "area".equals(base);
    437             } else if (OsmPrimitiveType.RELATION.equals(type)) {
    438                 return "area".equals(base) || "relation".equals(base) || "canvas".equals(base);
    439             }
    440             return false;
    441         }
    442 
    443         public boolean matchesBase(OsmPrimitive p) {
    444             if (!matchesBase(p.getType())) {
    445                 return false;
    446             } else {
    447                 if (p instanceof Relation) {
    448                     if ("area".equals(base)) {
    449                         return ((Relation) p).isMultipolygon();
    450                     } else if ("canvas".equals(base)) {
    451                         return p.get("#canvas") != null;
    452                     }
    453                 }
    454                 return true;
    455             }
    456         }
    457 
    458         public boolean matchesBase(Environment e) {
    459             return matchesBase(e.osm);
    460         }
    461 
    462         @Override
    463         public boolean matches(Environment e) {
    464             return matchesBase(e) && matchesConditions(e);
    465         }
    466 
    467532        public String getBase() {
    468533            return base;
    469534        }
    470535
     536        @Override
     537        public Selector optimizedBaseCheck() {
     538            throw new UnsupportedOperationException();
     539        }
     540       
    471541        public static Range fromLevel(int a, int b) {
    472542            if (a > b)
Note: See TracChangeset for help on using the changeset viewer.