Ticket #13275: cache_Area_intersection_v2.patch

File cache_Area_intersection_v2.patch, 24.2 KB (added by GerdP, 10 years ago)

includes 13275.patch

  • src/org/openstreetmap/josm/data/osm/MultipolygonBuilder.java

     
    55
    66import java.awt.Rectangle;
    77import java.awt.geom.Area;
    8 import java.io.IOException;
    9 import java.io.ObjectInputStream;
    10 import java.io.ObjectOutputStream;
    118import java.util.ArrayList;
    129import java.util.Collection;
    1310import java.util.Collections;
    1411import java.util.HashSet;
    1512import java.util.List;
     13import java.util.Objects;
    1614import java.util.Set;
    17 import java.util.concurrent.ForkJoinPool;
    18 import java.util.concurrent.ForkJoinTask;
    19 import java.util.concurrent.RecursiveTask;
    2015
    2116import org.openstreetmap.josm.Main;
    2217import org.openstreetmap.josm.tools.Geometry;
     
    2318import org.openstreetmap.josm.tools.Geometry.PolygonIntersection;
    2419import org.openstreetmap.josm.tools.MultiMap;
    2520import org.openstreetmap.josm.tools.Pair;
    26 import org.openstreetmap.josm.tools.Utils;
    2721
    2822/**
    2923 * Helper class to build multipolygons from multiple ways.
     
    3327 */
    3428public class MultipolygonBuilder {
    3529
    36     private static final ForkJoinPool THREAD_POOL =
    37             Utils.newForkJoinPool("multipolygon_creation.numberOfThreads", "multipolygon-builder-%d", Thread.NORM_PRIORITY);
     30    private static class ResultCache {
     31        Geometry.PolygonIntersection[] results;
     32        private final int dim;
     33        private long countCheck;
     34        private long countMiss;
    3835
     36        public ResultCache(Collection<JoinedPolygon> polygons) {
     37            int id = 0;
     38            for (JoinedPolygon p : polygons)
     39                p.setCacheId(id++);
     40
     41            this.dim = id;
     42            results = new Geometry.PolygonIntersection[dim*dim];
     43        }
     44
     45
     46        private synchronized PolygonIntersection getCachedResult(JoinedPolygon pa, JoinedPolygon pb){
     47            if (pa.id < 0 || pa.id >= dim ){
     48                throw new JoinedPolygonCreationException(tr("Internal error: unexpected id in 1st polygon", pa.id));
     49            }
     50            if (pb.id < 0 || pb.id >= dim ){
     51                throw new JoinedPolygonCreationException(tr("Internal error: unexpected id in 2nd polygon", pb.id));
     52            }
     53            countCheck++;
     54            int posAB = pa.id * dim + pb.id;
     55            if (results[posAB] == null){
     56                countMiss++;
     57                PolygonIntersection intersection = Geometry.polygonIntersection(pa.area, pb.area);
     58                results[posAB] = intersection;
     59                // set the results for exchanged parameters (a is outer b also means b is outer a etc.)
     60                int posBA = pb.id * dim + pa.id;
     61                if (intersection == PolygonIntersection.OUTSIDE || intersection == PolygonIntersection.CROSSING){
     62                    results[posBA] = intersection;
     63                } else if (intersection == PolygonIntersection.FIRST_INSIDE_SECOND){
     64                    results[posBA] = PolygonIntersection.SECOND_INSIDE_FIRST;
     65                } else if (intersection == PolygonIntersection.SECOND_INSIDE_FIRST)
     66                    results[posBA] = PolygonIntersection.FIRST_INSIDE_SECOND;
     67
     68            }
     69            return results[posAB];
     70        }
     71
     72        @Override
     73        public String toString() {
     74            return "Tests: " + countCheck + " hit/miss " + (countCheck - countMiss) + "/" + countMiss;
     75        }
     76    }
     77
    3978    /**
    4079     * Represents one polygon that consists of multiple ways.
    4180     */
     
    4584        public final List<Node> nodes;
    4685        public final Area area;
    4786        public final Rectangle bounds;
     87        private int id;
    4888
    4989        /**
    5090         * Constructs a new {@code JoinedPolygon} from given list of ways.
     
    5797            this.nodes = this.getNodes();
    5898            this.area = Geometry.getArea(nodes);
    5999            this.bounds = area.getBounds();
     100            this.id = -1;
    60101        }
    61102
    62103        /**
     
    91132
    92133            return nodes;
    93134        }
     135
     136        /**
     137         * Set id that is used in ResultCache
     138         * @param id
     139         */
     140        public void setCacheId(int id) {
     141            this.id = id;
     142        }
    94143    }
    95144
    96145    /**
     
    271320        return null;
    272321    }
    273322
    274     private static Pair<Boolean, List<JoinedPolygon>> findInnerWaysCandidates(JoinedPolygon outerWay, Collection<JoinedPolygon> boundaryWays) {
     323    private static Pair<Boolean, List<JoinedPolygon>> findInnerWaysCandidates(ResultCache cache, JoinedPolygon outerWay, Collection<JoinedPolygon> boundaryWays) {
    275324        boolean outerGood = true;
    276325        List<JoinedPolygon> innerCandidates = new ArrayList<>();
    277326
     
    283332            // Preliminary computation on bounds. If bounds do not intersect, no need to do a costly area intersection
    284333            if (outerWay.bounds.intersects(innerWay.bounds)) {
    285334                // Bounds intersection, let's see in detail
    286                 PolygonIntersection intersection = Geometry.polygonIntersection(outerWay.area, innerWay.area);
     335                PolygonIntersection intersection = cache.getCachedResult(outerWay, innerWay);
     336//                PolygonIntersection intersection = Geometry.polygonIntersection(outerWay.area, innerWay.area);
    287337
    288338                if (intersection == PolygonIntersection.FIRST_INSIDE_SECOND) {
    289339                    outerGood = false;  // outer is inside another polygon
     
    306356     * @return the outermostWay, or {@code null} if intersection found.
    307357     */
    308358    private static List<PolygonLevel> findOuterWaysMultiThread(List<JoinedPolygon> boundaryWays) {
    309         return THREAD_POOL.invoke(new Worker(boundaryWays, 0, boundaryWays.size(), new ArrayList<PolygonLevel>(),
    310                 Math.max(32, boundaryWays.size() / THREAD_POOL.getParallelism() / 3)));
     359        ResultCache cache = new ResultCache(boundaryWays);
     360        final List<PolygonLevel> output = new ArrayList<>();
     361        List<PolygonLevel> res = boundaryWays.parallelStream()
     362                .map(way -> Worker.processOuterWay(0, cache, boundaryWays, output, way))
     363                .allMatch(Objects::nonNull) ? output : null;
     364        if (!boundaryWays.isEmpty())
     365            Main.debug("mp cache: " + cache.toString());
     366        return res;
    311367    }
    312368
    313     private static class Worker extends RecursiveTask<List<PolygonLevel>> {
     369    private static class Worker {
    314370
    315         // Needed for Findbugs / Coverity because parent class is serializable
    316         private static final long serialVersionUID = 1L;
    317 
    318         private final transient List<JoinedPolygon> input;
    319         private final int from;
    320         private final int to;
    321         private final transient List<PolygonLevel> output;
    322         private final int directExecutionTaskSize;
    323 
    324         Worker(List<JoinedPolygon> input, int from, int to, List<PolygonLevel> output, int directExecutionTaskSize) {
    325             this.input = input;
    326             this.from = from;
    327             this.to = to;
    328             this.output = output;
    329             this.directExecutionTaskSize = directExecutionTaskSize;
    330         }
    331 
    332371        /**
    333372         * Collects outer way and corresponding inner ways from all boundaries.
    334373         * @param level nesting level
     374         * @param cache cache that tracks previously calculated results
    335375         * @param boundaryWays boundary ways
    336376         * @return the outermostWay, or {@code null} if intersection found.
    337377         */
    338         private static List<PolygonLevel> findOuterWaysRecursive(int level, List<JoinedPolygon> boundaryWays) {
     378        private static List<PolygonLevel> findOuterWaysRecursive(int level, ResultCache cache, List<JoinedPolygon> boundaryWays) {
    339379
    340380            final List<PolygonLevel> result = new ArrayList<>();
    341381
    342382            for (JoinedPolygon outerWay : boundaryWays) {
    343                 if (processOuterWay(level, boundaryWays, result, outerWay) == null) {
     383                if (processOuterWay(level, cache, boundaryWays, result, outerWay) == null) {
    344384                    return null;
    345385                }
    346386            }
     
    348388            return result;
    349389        }
    350390
    351         private static List<PolygonLevel> processOuterWay(int level, List<JoinedPolygon> boundaryWays,
     391        private static List<PolygonLevel> processOuterWay(int level, ResultCache cache, List<JoinedPolygon> boundaryWays,
    352392                final List<PolygonLevel> result, JoinedPolygon outerWay) {
    353             Pair<Boolean, List<JoinedPolygon>> p = findInnerWaysCandidates(outerWay, boundaryWays);
     393            Pair<Boolean, List<JoinedPolygon>> p = findInnerWaysCandidates(cache, outerWay, boundaryWays);
    354394            if (p == null) {
    355395                // ways intersect
    356396                return null;
     
    362402
    363403                //process inner ways
    364404                if (!p.b.isEmpty()) {
    365                     List<PolygonLevel> innerList = findOuterWaysRecursive(level + 1, p.b);
     405                    List<PolygonLevel> innerList = findOuterWaysRecursive(level + 1, cache, p.b);
    366406                    if (innerList == null) {
    367407                        return null; //intersection found
    368408                    }
     
    380420            }
    381421            return result;
    382422        }
    383 
    384         @Override
    385         protected List<PolygonLevel> compute() {
    386             if (to - from <= directExecutionTaskSize) {
    387                 return computeDirectly();
    388             } else {
    389                 final Collection<ForkJoinTask<List<PolygonLevel>>> tasks = new ArrayList<>();
    390                 for (int fromIndex = from; fromIndex < to; fromIndex += directExecutionTaskSize) {
    391                     tasks.add(new Worker(input, fromIndex, Math.min(fromIndex + directExecutionTaskSize, to),
    392                             new ArrayList<PolygonLevel>(), directExecutionTaskSize));
    393                 }
    394                 for (ForkJoinTask<List<PolygonLevel>> task : ForkJoinTask.invokeAll(tasks)) {
    395                     List<PolygonLevel> res = task.join();
    396                     if (res == null) {
    397                         return null;
    398                     }
    399                     output.addAll(res);
    400                 }
    401                 return output;
    402             }
    403         }
    404 
    405         List<PolygonLevel> computeDirectly() {
    406             for (int i = from; i < to; i++) {
    407                 if (processOuterWay(0, input, output, input.get(i)) == null) {
    408                     return null;
    409                 }
    410             }
    411             return output;
    412         }
    413 
    414         private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
    415             // Needed for Findbugs / Coverity because parent class is serializable
    416             ois.defaultReadObject();
    417         }
    418 
    419         private void writeObject(ObjectOutputStream oos) throws IOException {
    420             // Needed for Findbugs / Coverity because parent class is serializable
    421             oos.defaultWriteObject();
    422         }
    423423    }
    424424}
  • src/org/openstreetmap/josm/data/osm/visitor/paint/RenderBenchmarkCollector.java

     
    22package org.openstreetmap.josm.data.osm.visitor.paint;
    33
    44import java.io.PrintStream;
    5 import java.util.List;
     5import java.util.Collection;
    66import java.util.function.Supplier;
    77
    88import org.openstreetmap.josm.Main;
     
    3939     * @param allStyleElems All the elements that are painted.
    4040     * @return <code>true</code> if the renderer should continue to render
    4141     */
    42     public boolean renderDraw(List<StyleRecord> allStyleElems) {
     42    public boolean renderDraw(Collection<StyleRecord> allStyleElems) {
    4343        // nop
    4444        return true;
    4545    }
     
    7474        }
    7575
    7676        @Override
    77         public boolean renderDraw(List<StyleRecord> allStyleElems) {
     77        public boolean renderDraw(Collection<StyleRecord> allStyleElems) {
    7878            timeSortingDone = System.currentTimeMillis();
    7979            return super.renderDraw(allStyleElems);
    8080        }
     
    126126        }
    127127
    128128        @Override
    129         public boolean renderDraw(List<StyleRecord> allStyleElems) {
     129        public boolean renderDraw(Collection<StyleRecord> allStyleElems) {
    130130            boolean res = super.renderDraw(allStyleElems);
    131131            outStream.print("phase 1 (calculate styles): " + Utils.getDurationString(timeSortingDone - timeStart));
    132132            return res;
  • src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java

     
    2727import java.awt.geom.Rectangle2D;
    2828import java.util.ArrayList;
    2929import java.util.Collection;
    30 import java.util.Collections;
    3130import java.util.HashMap;
    3231import java.util.Iterator;
    3332import java.util.List;
    3433import java.util.Map;
    3534import java.util.NoSuchElementException;
     35import java.util.TreeSet;
    3636import java.util.concurrent.ForkJoinPool;
    37 import java.util.concurrent.ForkJoinTask;
    38 import java.util.concurrent.RecursiveTask;
    3937import java.util.function.Supplier;
     38import java.util.stream.Collectors;
     39import java.util.stream.Stream;
    4040
    4141import javax.swing.AbstractButton;
    4242import javax.swing.FocusManager;
     
    4545import org.openstreetmap.josm.data.Bounds;
    4646import org.openstreetmap.josm.data.coor.EastNorth;
    4747import org.openstreetmap.josm.data.osm.BBox;
    48 import org.openstreetmap.josm.data.osm.Changeset;
    4948import org.openstreetmap.josm.data.osm.DataSet;
    5049import org.openstreetmap.josm.data.osm.Node;
    5150import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    5453import org.openstreetmap.josm.data.osm.RelationMember;
    5554import org.openstreetmap.josm.data.osm.Way;
    5655import org.openstreetmap.josm.data.osm.WaySegment;
    57 import org.openstreetmap.josm.data.osm.visitor.Visitor;
    5856import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
    5957import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData;
    6058import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
     
    6159import org.openstreetmap.josm.gui.NavigatableComponent;
    6260import org.openstreetmap.josm.gui.mappaint.ElemStyles;
    6361import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
    64 import org.openstreetmap.josm.gui.mappaint.StyleElementList;
    6562import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
    6663import org.openstreetmap.josm.gui.mappaint.styleelement.AreaElement;
    6764import org.openstreetmap.josm.gui.mappaint.styleelement.BoxTextElement;
     
    7370import org.openstreetmap.josm.gui.mappaint.styleelement.RepeatImageElement.LineImageAlignment;
    7471import org.openstreetmap.josm.gui.mappaint.styleelement.StyleElement;
    7572import org.openstreetmap.josm.gui.mappaint.styleelement.TextLabel;
    76 import org.openstreetmap.josm.tools.CompositeList;
    7773import org.openstreetmap.josm.tools.Geometry;
    7874import org.openstreetmap.josm.tools.Geometry.AreaAndPerimeter;
    7975import org.openstreetmap.josm.tools.ImageProvider;
     76import org.openstreetmap.josm.tools.StreamUtils;
    8077import org.openstreetmap.josm.tools.Utils;
    8178
    8279/**
     
    17791776        }
    17801777    }
    17811778
    1782     private class ComputeStyleListWorker extends RecursiveTask<List<StyleRecord>> implements Visitor {
    1783         private final transient List<? extends OsmPrimitive> input;
    1784         private final transient List<StyleRecord> output;
    1785 
     1779    private class ComputeStyleListWorker {
    17861780        private final transient ElemStyles styles = MapPaintStyles.getStyles();
    1787         private final int directExecutionTaskSize;
    1788 
    17891781        private final boolean drawArea = circum <= Main.pref.getInteger("mappaint.fillareas", 10000000);
    17901782        private final boolean drawMultipolygon = drawArea && Main.pref.getBoolean("mappaint.multipolygon", true);
    17911783        private final boolean drawRestriction = Main.pref.getBoolean("mappaint.restriction", true);
     
    17921784
    17931785        /**
    17941786         * Constructs a new {@code ComputeStyleListWorker}.
    1795          * @param input the primitives to process
    1796          * @param output the list of styles to which styles will be added
    1797          * @param directExecutionTaskSize the threshold deciding whether to subdivide the tasks
    17981787         */
    1799         ComputeStyleListWorker(final List<? extends OsmPrimitive> input, List<StyleRecord> output, int directExecutionTaskSize) {
    1800             this.input = input;
    1801             this.output = output;
    1802             this.directExecutionTaskSize = directExecutionTaskSize;
     1788        ComputeStyleListWorker() {
    18031789            this.styles.setDrawMultipolygon(drawMultipolygon);
    18041790        }
    18051791
    1806         @Override
    1807         protected List<StyleRecord> compute() {
    1808             if (input.size() <= directExecutionTaskSize) {
    1809                 return computeDirectly();
    1810             } else {
    1811                 final Collection<ForkJoinTask<List<StyleRecord>>> tasks = new ArrayList<>();
    1812                 for (int fromIndex = 0; fromIndex < input.size(); fromIndex += directExecutionTaskSize) {
    1813                     final int toIndex = Math.min(fromIndex + directExecutionTaskSize, input.size());
    1814                     final List<StyleRecord> output = new ArrayList<>(directExecutionTaskSize);
    1815                     tasks.add(new ComputeStyleListWorker(input.subList(fromIndex, toIndex), output, directExecutionTaskSize).fork());
    1816                 }
    1817                 for (ForkJoinTask<List<StyleRecord>> task : tasks) {
    1818                     output.addAll(task.join());
    1819                 }
    1820                 return output;
    1821             }
     1792        Stream<StyleRecord> computeNodeStyle(Node osm) {
     1793            final int flags = computeFlags(osm, false);
     1794            return StreamUtils.toStream(styles.get(osm, circum, nc))
     1795                    .map(s -> new StyleRecord(s, osm, flags));
    18221796        }
    18231797
    1824         public List<StyleRecord> computeDirectly() {
    1825             MapCSSStyleSource.STYLE_SOURCE_LOCK.readLock().lock();
    1826             try {
    1827                 for (final OsmPrimitive osm : input) {
    1828                     if (osm.isDrawable()) {
    1829                         osm.accept(this);
    1830                     }
    1831                 }
    1832                 return output;
    1833             } finally {
    1834                 MapCSSStyleSource.STYLE_SOURCE_LOCK.readLock().unlock();
    1835             }
     1798        Stream<StyleRecord> computeRelationStyle(Relation osm) {
     1799            final int flags = computeFlags(osm, true);
     1800            return StreamUtils.toStream(styles.get(osm, circum, nc))
     1801                    .filter(s ->
     1802                            drawMultipolygon && drawArea && s instanceof AreaElement && (flags & FLAG_DISABLED) == 0
     1803                            || drawRestriction && s instanceof NodeElement
     1804                    )
     1805                    .map(s -> new StyleRecord(s, osm, flags));
    18361806        }
    18371807
    1838         @Override
    1839         public void visit(Node n) {
    1840             add(n, computeFlags(n, false));
     1808        Stream<StyleRecord> computeWayStyle(Way osm) {
     1809            final int flags = computeFlags(osm, true);
     1810            return StreamUtils.toStream(styles.get(osm, circum, nc))
     1811                    .filter(s -> !(!(drawArea && (flags & FLAG_DISABLED) == 0) && s instanceof AreaElement))
     1812                    .map(s -> new StyleRecord(s, osm, flags));
    18411813        }
    1842 
    1843         @Override
    1844         public void visit(Way w) {
    1845             add(w, computeFlags(w, true));
    1846         }
    1847 
    1848         @Override
    1849         public void visit(Relation r) {
    1850             add(r, computeFlags(r, true));
    1851         }
    1852 
    1853         @Override
    1854         public void visit(Changeset cs) {
    1855             throw new UnsupportedOperationException();
    1856         }
    1857 
    1858         public void add(Node osm, int flags) {
    1859             StyleElementList sl = styles.get(osm, circum, nc);
    1860             for (StyleElement s : sl) {
    1861                 output.add(new StyleRecord(s, osm, flags));
    1862             }
    1863         }
    1864 
    1865         public void add(Relation osm, int flags) {
    1866             StyleElementList sl = styles.get(osm, circum, nc);
    1867             for (StyleElement s : sl) {
    1868                 if (drawMultipolygon && drawArea && s instanceof AreaElement && (flags & FLAG_DISABLED) == 0) {
    1869                     output.add(new StyleRecord(s, osm, flags));
    1870                 } else if (drawRestriction && s instanceof NodeElement) {
    1871                     output.add(new StyleRecord(s, osm, flags));
    1872                 }
    1873             }
    1874         }
    1875 
    1876         public void add(Way osm, int flags) {
    1877             StyleElementList sl = styles.get(osm, circum, nc);
    1878             for (StyleElement s : sl) {
    1879                 if (!(drawArea && (flags & FLAG_DISABLED) == 0) && s instanceof AreaElement) {
    1880                     continue;
    1881                 }
    1882                 output.add(new StyleRecord(s, osm, flags));
    1883             }
    1884         }
    18851814    }
    18861815
    18871816    /**
     
    19091838            List<Way> ways = data.searchWays(bbox);
    19101839            List<Relation> relations = data.searchRelations(bbox);
    19111840
    1912             final List<StyleRecord> allStyleElems = new ArrayList<>(nodes.size()+ways.size()+relations.size());
     1841            final Collection<StyleRecord> allStyleElems;
    19131842
    19141843            // Need to process all relations first.
    19151844            // Reason: Make sure, ElemStyles.getStyleCacheWithRange is
     
    19161845            // not called for the same primitive in parallel threads.
    19171846            // (Could be synchronized, but try to avoid this for
    19181847            // performance reasons.)
    1919             THREAD_POOL.invoke(new ComputeStyleListWorker(relations, allStyleElems,
    1920                     Math.max(20, relations.size() / THREAD_POOL.getParallelism() / 3)));
    1921             THREAD_POOL.invoke(new ComputeStyleListWorker(new CompositeList<>(nodes, ways), allStyleElems,
    1922                     Math.max(100, (nodes.size() + ways.size()) / THREAD_POOL.getParallelism() / 3)));
     1848            MapCSSStyleSource.STYLE_SOURCE_LOCK.readLock().lock();
     1849            try {
     1850                final ComputeStyleListWorker worker = new ComputeStyleListWorker();
     1851                // run parallel stream in THREAD_POOL, see https://stackoverflow.com/a/22269778/205629
     1852                allStyleElems = THREAD_POOL.submit(() ->
     1853                        relations.parallelStream().filter(OsmPrimitive::isDrawable).flatMap(worker::computeRelationStyle)
     1854                                .collect(Collectors.toCollection(TreeSet::new))).get();
     1855                allStyleElems.addAll(THREAD_POOL.submit(() -> Stream.concat(
     1856                        nodes.parallelStream().filter(OsmPrimitive::isDrawable).flatMap(worker::computeNodeStyle),
     1857                        ways.parallelStream().filter(OsmPrimitive::isDrawable).flatMap(worker::computeWayStyle)
     1858                                ).collect(Collectors.toList())).get());
     1859            } catch (Exception ex) {
     1860                throw new RuntimeException(ex);
     1861            } finally {
     1862                MapCSSStyleSource.STYLE_SOURCE_LOCK.readLock().unlock();
     1863            }
    19231864
    19241865            if (!benchmark.renderSort()) {
    19251866                return;
    19261867            }
    19271868
    1928             Collections.sort(allStyleElems); // TODO: try parallel sort when switching to Java 8
    1929 
    19301869            if (!benchmark.renderDraw(allStyleElems)) {
    19311870                return;
    19321871            }
  • test/performance/org/openstreetmap/josm/gui/mappaint/MapRendererPerformanceTest.java

     
    88import java.io.IOException;
    99import java.io.InputStream;
    1010import java.util.ArrayList;
     11import java.util.Collection;
    1112import java.util.Collections;
    1213import java.util.EnumMap;
    1314import java.util.HashMap;
     
    331332
    332333    public static class BenchmarkData extends CapturingBenchmark {
    333334
    334         private List<StyleRecord> allStyleElems;
     335        private Collection<StyleRecord> allStyleElems;
    335336
    336337        @Override
    337         public boolean renderDraw(List<StyleRecord> allStyleElems) {
     338        public boolean renderDraw(Collection<StyleRecord> allStyleElems) {
    338339            this.allStyleElems = allStyleElems;
    339340            return super.renderDraw(allStyleElems);
    340341        }