- extract interface of RenderTheme

- pass MapElement to RenderTheme
- refactor: join duplicated code for node and way matching
This commit is contained in:
Hannes Janetzek 2013-04-22 02:19:32 +02:00
parent 7d767ec2e4
commit bcb529906a
6 changed files with 216 additions and 265 deletions

View File

@ -35,7 +35,7 @@ import org.oscim.renderer.layer.LineTexLayer;
import org.oscim.renderer.layer.PolygonLayer; import org.oscim.renderer.layer.PolygonLayer;
import org.oscim.renderer.layer.TextItem; import org.oscim.renderer.layer.TextItem;
import org.oscim.theme.IRenderCallback; import org.oscim.theme.IRenderCallback;
import org.oscim.theme.RenderTheme; import org.oscim.theme.IRenderTheme;
import org.oscim.theme.renderinstruction.Area; import org.oscim.theme.renderinstruction.Area;
import org.oscim.theme.renderinstruction.Circle; import org.oscim.theme.renderinstruction.Circle;
import org.oscim.theme.renderinstruction.Line; import org.oscim.theme.renderinstruction.Line;
@ -80,7 +80,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
private static DebugSettings debug; private static DebugSettings debug;
private RenderTheme renderTheme; private IRenderTheme renderTheme;
private int renderLevels; private int renderLevels;
// current MapDatabase used by this TileGenerator // current MapDatabase used by this TileGenerator
@ -106,7 +106,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
private final LineClipper mClipper; private final LineClipper mClipper;
public void setRenderTheme(RenderTheme theme) { public void setRenderTheme(IRenderTheme theme) {
renderTheme = theme; renderTheme = theme;
renderLevels = theme.getLevels(); renderLevels = theme.getLevels();
} }
@ -182,20 +182,20 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
return false; return false;
} }
if (debug.drawTileFrames) { // if (debug.drawTileFrames) {
// draw tile coordinate // // draw tile coordinate
mTagName = new Tag("name", mTile.toString(), false); // mTagName = new Tag("name", mTile.toString(), false);
mElement = mDebugPoint; // mElement = mDebugPoint;
RenderInstruction[] ri; // RenderInstruction[] ri;
ri = renderTheme.matchNode(debugTagWay, (byte) 0); // ri = renderTheme.matchNode(debugTagWay, (byte) 0);
renderNode(ri); // renderNode(ri);
//
// draw tile box // // draw tile box
mElement = mDebugWay; // mElement = mDebugWay;
mDrawingLayer = 100 * renderLevels; // mDrawingLayer = 100 * renderLevels;
ri = renderTheme.matchWay(mDebugWay.tags, (byte) 0, false); // ri = renderTheme.matchWay(mDebugWay.tags, (byte) 0, false);
renderWay(ri); // renderWay(ri);
} // }
mTile = null; mTile = null;
return true; return true;
@ -281,7 +281,8 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
filterTags(element.tags); filterTags(element.tags);
// get render instructions // get render instructions
RenderInstruction[] ri = renderTheme.matchNode(element.tags, mTile.zoomLevel); //RenderInstruction[] ri = renderTheme.matchNode(element.tags, mTile.zoomLevel);
RenderInstruction[] ri = renderTheme.matchElement(element, mTile.zoomLevel);
if (ri != null) if (ri != null)
renderNode(ri); renderNode(ri);
@ -297,8 +298,10 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
mDrawingLayer = getValidLayer(element.layer) * renderLevels; mDrawingLayer = getValidLayer(element.layer) * renderLevels;
// get render instructions // get render instructions
RenderInstruction[] ri = renderTheme.matchWay(element.tags, // RenderInstruction[] ri = renderTheme.matchWay(element.tags,
(byte) (mTile.zoomLevel + 0), closed); // (byte) (mTile.zoomLevel + 0), closed);
RenderInstruction[] ri = renderTheme.matchElement(element, mTile.zoomLevel);
renderWay(ri); renderWay(ri);
@ -314,15 +317,15 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
private void debugUnmatched(boolean closed, Tag[] tags) { private void debugUnmatched(boolean closed, Tag[] tags) {
Log.d(TAG, "DBG way not matched: " + closed + " " Log.d(TAG, "DBG way not matched: " + closed + " "
+ Arrays.deepToString(tags)); + Arrays.deepToString(tags));
mElement = null;
mTagName = new Tag("name", tags[0].key + ":" // mTagName = new Tag("name", tags[0].key + ":"
+ tags[0].value, false); // + tags[0].value, false);
//
RenderInstruction[] ri; // RenderInstruction[] ri;
ri = renderTheme.matchWay(closed ? debugTagArea : debugTagWay, // ri = renderTheme.matchWay(closed ? debugTagArea : debugTagWay,
(byte) 0, true); // (byte) 0, true);
//
renderWay(ri); // renderWay(ri);
} }
private void renderWay(RenderInstruction[] ri) { private void renderWay(RenderInstruction[] ri) {

View File

@ -32,8 +32,8 @@ import org.oscim.database.MapOptions;
import org.oscim.layers.Layer; import org.oscim.layers.Layer;
import org.oscim.renderer.GLRenderer; import org.oscim.renderer.GLRenderer;
import org.oscim.theme.ExternalRenderTheme; import org.oscim.theme.ExternalRenderTheme;
import org.oscim.theme.IRenderTheme;
import org.oscim.theme.InternalRenderTheme; import org.oscim.theme.InternalRenderTheme;
import org.oscim.theme.RenderTheme;
import org.oscim.theme.RenderThemeHandler; import org.oscim.theme.RenderThemeHandler;
import org.oscim.theme.Theme; import org.oscim.theme.Theme;
import org.oscim.view.MapView; import org.oscim.view.MapView;
@ -263,7 +263,7 @@ public class TileLayer extends Layer {
InputStream inputStream = null; InputStream inputStream = null;
try { try {
inputStream = theme.getRenderThemeAsStream(); inputStream = theme.getRenderThemeAsStream();
RenderTheme t = RenderThemeHandler.getRenderTheme(inputStream); IRenderTheme t = RenderThemeHandler.getRenderTheme(inputStream);
t.scaleTextSize(1 + (MapView.dpi / 240 - 1) * 0.5f); t.scaleTextSize(1 + (MapView.dpi / 240 - 1) * 0.5f);
// FIXME !!! // FIXME !!!

View File

@ -32,7 +32,7 @@ import org.oscim.core.Tile;
import org.oscim.layers.tile.MapTile; import org.oscim.layers.tile.MapTile;
import org.oscim.renderer.layer.Layers; import org.oscim.renderer.layer.Layers;
import org.oscim.renderer.overlays.RenderOverlay; import org.oscim.renderer.overlays.RenderOverlay;
import org.oscim.theme.RenderTheme; import org.oscim.theme.IRenderTheme;
import org.oscim.utils.GlUtils; import org.oscim.utils.GlUtils;
import org.oscim.utils.Matrix4; import org.oscim.utils.Matrix4;
import org.oscim.view.MapView; import org.oscim.view.MapView;
@ -124,7 +124,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mFillCoords[7] = min; mFillCoords[7] = min;
} }
public static void setRenderTheme(RenderTheme t) { public static void setRenderTheme(IRenderTheme t) {
mClearColor = GlUtils.colorToFloat(t.getMapBackground()); mClearColor = GlUtils.colorToFloat(t.getMapBackground());
mUpdateColor = true; mUpdateColor = true;
} }

View File

@ -0,0 +1,66 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2013 Hannes Janetzek
*
* This program 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, either version 3 of the License, or (at your option) any later version.
*
* This program 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.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.theme;
import org.oscim.core.MapElement;
import org.oscim.theme.renderinstruction.RenderInstruction;
public interface IRenderTheme {
/**
* Matches a MapElement with the given parameters against this RenderTheme.
*
* @param zoomLevel
* the zoom level at which the way should be matched.
* @return matching render instructions
*/
public abstract RenderInstruction[] matchElement(MapElement element, int zoomLevel);
/**
* Must be called when this RenderTheme gets destroyed to clean up and free
* resources.
*/
public abstract void destroy();
/**
* @return the number of distinct drawing levels required by this
* RenderTheme.
*/
public abstract int getLevels();
/**
* @return the map background color of this RenderTheme.
*/
public abstract int getMapBackground();
/**
* Scales the stroke width of this RenderTheme by the given factor.
*
* @param scaleFactor
* the factor by which the stroke width should be scaled.
*/
public abstract void scaleStrokeWidth(float scaleFactor);
/**
* Scales the text size of this RenderTheme by the given factor.
*
* @param scaleFactor
* the factor by which the text size should be scaled.
*/
public abstract void scaleTextSize(float scaleFactor);
}

View File

@ -14,10 +14,13 @@
*/ */
package org.oscim.theme; package org.oscim.theme;
import static org.oscim.core.MapElement.GEOM_LINE;
import static org.oscim.core.MapElement.GEOM_POLY;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.oscim.core.Tag; import org.oscim.core.MapElement;
import org.oscim.theme.renderinstruction.RenderInstruction; import org.oscim.theme.renderinstruction.RenderInstruction;
import org.oscim.theme.rule.Closed; import org.oscim.theme.rule.Closed;
import org.oscim.theme.rule.Rule; import org.oscim.theme.rule.Rule;
@ -25,12 +28,13 @@ import org.oscim.utils.LRUCache;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import android.graphics.Color; import android.graphics.Color;
import android.util.Log;
/** /**
* A RenderTheme defines how ways and nodes are drawn. * A RenderTheme defines how map elements are drawn.
*/ */
public class RenderTheme { public class RenderTheme implements IRenderTheme {
//private final static String TAG = RenderTheme.class.getName(); private final static String TAG = RenderTheme.class.getName();
private static final int MATCHING_CACHE_SIZE = 512; private static final int MATCHING_CACHE_SIZE = 512;
private static final int RENDER_THEME_VERSION = 1; private static final int RENDER_THEME_VERSION = 1;
@ -82,25 +86,26 @@ public class RenderTheme {
private final float mBaseStrokeWidth; private final float mBaseStrokeWidth;
private final float mBaseTextSize; private final float mBaseTextSize;
private int mLevels;
private final int mMapBackground; private final int mMapBackground;
private final ArrayList<Rule> mRulesList;
private final LRUCache<MatchingCacheKey, RenderInstructionItem> mNodesCache; private int mLevels;
private final LRUCache<MatchingCacheKey, RenderInstructionItem> mWayCache; private Rule[] mRules;
private final LRUCache<MatchingCacheKey, RenderInstructionItem> mAreaCache;
private final MatchingCacheKey mAreaCacheKey; class ElementCache {
private final MatchingCacheKey mWayCacheKey; final LRUCache<MatchingCacheKey, RenderInstructionItem> cache;
private final MatchingCacheKey mNodeCacheKey; final MatchingCacheKey cacheKey;
private final ArrayList<RenderInstruction> mWayInstructionList; /* temporary matching instructions list */
private final ArrayList<RenderInstruction> mAreaInstructionList; final ArrayList<RenderInstruction> instructionList;
private final ArrayList<RenderInstruction> mNodeInstructionList;
private RenderInstructionItem mPrevAreaItem; RenderInstructionItem prevItem;
private RenderInstructionItem mPrevWayItem;
private RenderInstructionItem mPrevNodeItem; public ElementCache() {
cache = new LRUCache<MatchingCacheKey, RenderInstructionItem>(MATCHING_CACHE_SIZE);
instructionList = new ArrayList<RenderInstruction>(4);
cacheKey = new MatchingCacheKey();
}
}
class RenderInstructionItem { class RenderInstructionItem {
RenderInstructionItem next; RenderInstructionItem next;
@ -109,65 +114,60 @@ public class RenderTheme {
MatchingCacheKey key; MatchingCacheKey key;
} }
private final ElementCache[] mElementCache;
RenderTheme(int mapBackground, float baseStrokeWidth, float baseTextSize) { RenderTheme(int mapBackground, float baseStrokeWidth, float baseTextSize) {
mMapBackground = mapBackground; mMapBackground = mapBackground;
mBaseStrokeWidth = baseStrokeWidth; mBaseStrokeWidth = baseStrokeWidth;
mBaseTextSize = baseTextSize; mBaseTextSize = baseTextSize;
mRulesList = new ArrayList<Rule>();
mNodesCache = new LRUCache<MatchingCacheKey, RenderInstructionItem>(MATCHING_CACHE_SIZE); mElementCache = new ElementCache[3];
mWayCache = new LRUCache<MatchingCacheKey, RenderInstructionItem>(MATCHING_CACHE_SIZE); for (int i = 0; i < 3; i++)
mAreaCache = new LRUCache<MatchingCacheKey, RenderInstructionItem>(MATCHING_CACHE_SIZE); mElementCache[i] = new ElementCache();
mWayInstructionList = new ArrayList<RenderInstruction>(4);
mAreaInstructionList = new ArrayList<RenderInstruction>(4);
mNodeInstructionList = new ArrayList<RenderInstruction>(4);
mAreaCacheKey = new MatchingCacheKey();
mWayCacheKey = new MatchingCacheKey();
mNodeCacheKey = new MatchingCacheKey();
} }
/** /*
* Must be called when this RenderTheme gets destroyed to clean up and free * (non-Javadoc)
* resources. * @see org.oscim.theme.IRenderTheme#destroy()
*/ */
@Override
public void destroy() { public void destroy() {
mNodesCache.clear();
mAreaCache.clear();
mWayCache.clear();
for (int i = 0, n = mRulesList.size(); i < n; ++i) { for (int i = 0; i < 3; i++)
mRulesList.get(i).onDestroy(); mElementCache[i].cache.clear();
if (mRules != null) {
for (int i = 0, n = mRules.length; i < n; i++)
mRules[i].onDestroy();
} }
} }
/** /*
* @return the number of distinct drawing levels required by this * (non-Javadoc)
* RenderTheme. * @see org.oscim.theme.IRenderTheme#getLevels()
*/ */
@Override
public int getLevels() { public int getLevels() {
return mLevels; return mLevels;
} }
/** /*
* @return the map background color of this RenderTheme. * (non-Javadoc)
* @see Color * @see org.oscim.theme.IRenderTheme#getMapBackground()
*/ */
@Override
public int getMapBackground() { public int getMapBackground() {
return mMapBackground; return mMapBackground;
} }
/** /*
* ... * (non-Javadoc)
* * @see org.oscim.theme.IRenderTheme#matchWay(org.oscim.core.Tag[], byte,
* @param tags * boolean)
* ...
* @param zoomLevel
* ...
* @return ...
*/ */
public RenderInstruction[] matchNode(Tag[] tags, byte zoomLevel) { @Override
public RenderInstruction[] matchElement(MapElement element, int zoomLevel) {
// list of renderinsctruction items in cache // list of renderinsctruction items in cache
RenderInstructionItem ris = null; RenderInstructionItem ris = null;
@ -175,157 +175,32 @@ public class RenderTheme {
// the item matching tags and zoomlevel // the item matching tags and zoomlevel
RenderInstructionItem ri = null; RenderInstructionItem ri = null;
synchronized (mNodesCache) { int type = element.geometryType;
if (type < 1 || type > 3) {
Log.d(TAG, "invalid geometry type for RenderTheme " + type);
return null;
}
ElementCache cache = mElementCache[type - 1];
// NOTE: maximum zoom level supported is 32
int zoomMask = 1 << zoomLevel; int zoomMask = 1 << zoomLevel;
MatchingCacheKey cacheKey = mNodeCacheKey; synchronized (cache) {
if (mPrevNodeItem == null || (mPrevNodeItem.zoom & zoomMask) == 0) {
if (cache.prevItem == null || (cache.prevItem.zoom & zoomMask) == 0) {
// previous instructions zoom does not match // previous instructions zoom does not match
cacheKey.set(tags, null); cache.cacheKey.set(element.tags, null);
} else { } else {
// compare if tags match previous instructions // compare if tags match previous instructions
if (cacheKey.set(tags, mPrevNodeItem.key)) if (cache.cacheKey.set(element.tags, cache.prevItem.key)) {
ri = mPrevNodeItem;
}
if (ri == null) {
boolean found = mNodesCache.containsKey(cacheKey);
if (found) {
ris = mNodesCache.get(cacheKey);
for (ri = ris; ri != null; ri = ri.next)
if ((ri.zoom & zoomMask) != 0)
// cache hit
break;
}
}
if (ri == null) {
// cache miss
List<RenderInstruction> matches = mNodeInstructionList;
matches.clear();
for (int i = 0, n = mRulesList.size(); i < n; ++i)
mRulesList.get(i).matchNode(tags, zoomLevel, matches);
int size = matches.size();
// check if same instructions are used in another level
for (ri = ris; ri != null; ri = ri.next) {
if (size == 0) {
if (ri.list != null)
continue;
// both matchinglists are empty
break;
}
if (ri.list == null)
continue;
if (ri.list.length != size)
continue;
int i = 0;
for (RenderInstruction r : ri.list) {
if (r != matches.get(i))
break;
i++;
}
if (i == size)
// both matching lists contain the same items
break;
}
if (ri != null) {
// we found a same matchting list on another zoomlevel
ri.zoom |= zoomMask;
} else {
ri = new RenderInstructionItem();
ri.zoom = zoomMask;
if (size > 0) {
ri.list = new RenderInstruction[size];
matches.toArray(ri.list);
}
// attach this list to the one found for MatchingKey
if (ris != null) {
ri.next = ris.next;
ri.key = ris.key;
ris.next = ri;
} else {
ri.key = new MatchingCacheKey(cacheKey);
mNodesCache.put(ri.key, ri);
}
}
}
}
mPrevNodeItem = ri;
return ri.list;
}
/**
* Matches a way with the given parameters against this RenderTheme.
*
* @param tags
* the tags of the way.
* @param zoomLevel
* the zoom level at which the way should be matched.
* @param closed
* way is Closed
* @return currently processed render instructions
*/
public RenderInstruction[] matchWay(Tag[] tags, byte zoomLevel, boolean closed) {
// list of renderinsctruction items in cache
RenderInstructionItem ris = null;
RenderInstructionItem prevInstructions = null;
// the item matching tags and zoomlevel
RenderInstructionItem ri = null;
// temporary matching instructions list
List<RenderInstruction> matches;
LRUCache<MatchingCacheKey, RenderInstructionItem> matchingCache;
MatchingCacheKey cacheKey;
if (closed)
matchingCache = mAreaCache;
else
matchingCache = mWayCache;
int zoomMask = 1 << zoomLevel;
synchronized (matchingCache) {
if (closed) {
cacheKey = mAreaCacheKey;
matches = mAreaInstructionList;
prevInstructions = mPrevAreaItem;
} else {
cacheKey = mWayCacheKey;
matches = mWayInstructionList;
prevInstructions = mPrevWayItem;
}
if (prevInstructions == null || (prevInstructions.zoom & zoomMask) == 0) {
// previous instructions zoom does not match
cacheKey.set(tags, null);
} else {
// compare if tags match previous instructions
if (cacheKey.set(tags, prevInstructions.key)) {
//Log.d(TAG, "same as previous " + Arrays.deepToString(tags)); //Log.d(TAG, "same as previous " + Arrays.deepToString(tags));
ri = prevInstructions; ri = cache.prevItem;
} }
} }
if (ri == null) { if (ri == null) {
ris = matchingCache.get(cacheKey); ris = cache.cache.get(cache.cacheKey);
for (ri = ris; ri != null; ri = ri.next) for (ri = ris; ri != null; ri = ri.next)
if ((ri.zoom & zoomMask) != 0) if ((ri.zoom & zoomMask) != 0)
@ -337,12 +212,22 @@ public class RenderTheme {
// cache miss // cache miss
//Log.d(TAG, missCnt++ + " / " + hitCnt + " Cache Miss"); //Log.d(TAG, missCnt++ + " / " + hitCnt + " Cache Miss");
int c = (closed ? Closed.YES : Closed.NO); List<RenderInstruction> matches = cache.instructionList;
//List<RenderInstruction> matches = mMatchingList;
matches.clear(); matches.clear();
for (int i = 0, n = mRulesList.size(); i < n; ++i) if (type == GEOM_LINE) {
mRulesList.get(i).matchWay(tags, zoomLevel, c, matches); for (int i = 0, n = mRules.length; i < n; i++)
mRules[i].matchWay(element.tags,
(byte) zoomLevel, Closed.NO, matches);
} else if (type == GEOM_POLY) {
for (int i = 0, n = mRules.length; i < n; i++)
mRules[i].matchWay(element.tags,
(byte) zoomLevel, Closed.YES, matches);
} else {
for (int i = 0, n = mRules.length; i < n; i++)
mRules[i].matchNode(element.tags,
(byte) zoomLevel, matches);
}
int size = matches.size(); int size = matches.size();
// check if same instructions are used in another level // check if same instructions are used in another level
@ -373,12 +258,13 @@ public class RenderTheme {
} }
if (ri != null) { if (ri != null) {
// we found a same matchting list on another zoomlevel // we found a same matchting list on another zoomlevel add
// this zoom level to the existing RenderInstructionItem.
ri.zoom |= zoomMask; ri.zoom |= zoomMask;
//Log.d(TAG, //Log.d(TAG,
// zoomLevel + " same instructions " + size + " " // zoomLevel + " same instructions " + size + " "
// + Arrays.deepToString(tags)); // + Arrays.deepToString(tags));
} else { } else {
//Log.d(TAG, //Log.d(TAG,
// zoomLevel + " new instructions " + size + " " // zoomLevel + " new instructions " + size + " "
@ -398,56 +284,49 @@ public class RenderTheme {
ri.key = ris.key; ri.key = ris.key;
ris.next = ri; ris.next = ri;
} else { } else {
ri.key = new MatchingCacheKey(cacheKey); ri.key = new MatchingCacheKey(cache.cacheKey);
matchingCache.put(ri.key, ri); cache.cache.put(ri.key, ri);
} }
} }
} }
if (closed)
mPrevAreaItem = ri; cache.prevItem = ri;
else
mPrevWayItem = ri;
} }
return ri.list; return ri.list;
} }
void addRule(Rule rule) {
mRulesList.add(rule);
}
void complete() { void complete(List<Rule> rulesList, int levels) {
mRulesList.trimToSize();
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
mRulesList.get(i).onComplete();
}
}
void setLevels(int levels) {
mLevels = levels; mLevels = levels;
mRules = new Rule[rulesList.size()];
rulesList.toArray(mRules);
for (int i = 0, n = mRules.length; i < n; i++) {
mRules[i].onComplete();
}
} }
/** /*
* Scales the stroke width of this RenderTheme by the given factor. * (non-Javadoc)
* * @see org.oscim.theme.IRenderTheme#scaleStrokeWidth(float)
* @param scaleFactor
* the factor by which the stroke width should be scaled.
*/ */
@Override
public void scaleStrokeWidth(float scaleFactor) { public void scaleStrokeWidth(float scaleFactor) {
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
mRulesList.get(i).scaleStrokeWidth(scaleFactor * mBaseStrokeWidth); for (int i = 0, n = mRules.length; i < n; i++)
} mRules[i].scaleStrokeWidth(scaleFactor * mBaseStrokeWidth);
} }
/** /*
* Scales the text size of this RenderTheme by the given factor. * (non-Javadoc)
* * @see org.oscim.theme.IRenderTheme#scaleTextSize(float)
* @param scaleFactor
* the factor by which the text size should be scaled.
*/ */
@Override
public void scaleTextSize(float scaleFactor) { public void scaleTextSize(float scaleFactor) {
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
mRulesList.get(i).scaleTextSize(scaleFactor * mBaseTextSize); for (int i = 0, n = mRules.length; i < n; i++)
} mRules[i].scaleTextSize(scaleFactor * mBaseTextSize);
} }
} }

View File

@ -17,6 +17,7 @@ package org.oscim.theme;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Stack; import java.util.Stack;
@ -75,7 +76,7 @@ public class RenderThemeHandler extends DefaultHandler {
* @throws IOException * @throws IOException
* if an I/O error occurs while reading from the input stream. * if an I/O error occurs while reading from the input stream.
*/ */
public static RenderTheme getRenderTheme(InputStream inputStream) public static IRenderTheme getRenderTheme(InputStream inputStream)
throws SAXException, throws SAXException,
ParserConfigurationException, IOException { ParserConfigurationException, IOException {
RenderThemeHandler renderThemeHandler = new RenderThemeHandler(); RenderThemeHandler renderThemeHandler = new RenderThemeHandler();
@ -112,7 +113,9 @@ public class RenderThemeHandler extends DefaultHandler {
Log.d(TAG, stringBuilder.toString()); Log.d(TAG, stringBuilder.toString());
} }
private final ArrayList<Rule> mRulesList = new ArrayList<Rule>();
private Rule mCurrentRule; private Rule mCurrentRule;
private final Stack<Element> mElementStack = new Stack<Element>(); private final Stack<Element> mElementStack = new Stack<Element>();
private int mLevel; private int mLevel;
private RenderTheme mRenderTheme; private RenderTheme mRenderTheme;
@ -126,8 +129,8 @@ public class RenderThemeHandler extends DefaultHandler {
throw new IllegalArgumentException("missing element: rules"); throw new IllegalArgumentException("missing element: rules");
} }
mRenderTheme.setLevels(mLevel); mRenderTheme.complete(mRulesList, mLevel);
mRenderTheme.complete(); mRulesList.clear();
tmpStyleHash.clear(); tmpStyleHash.clear();
} }
@ -138,7 +141,7 @@ public class RenderThemeHandler extends DefaultHandler {
if (ELEMENT_NAME_RULE.equals(localName)) { if (ELEMENT_NAME_RULE.equals(localName)) {
mRuleStack.pop(); mRuleStack.pop();
if (mRuleStack.empty()) { if (mRuleStack.empty()) {
mRenderTheme.addRule(mCurrentRule); mRulesList.add(mCurrentRule);
} else { } else {
mCurrentRule = mRuleStack.peek(); mCurrentRule = mRuleStack.peek();
} }