Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 46 additions & 31 deletions library/src/main/java/com/pixplicity/sharp/Sharp.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
Expand All @@ -63,7 +64,9 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -1110,41 +1113,36 @@ public void inherit(Gradient parent) {
}
}

private static class StyleSet {
HashMap<String, String> styleMap = new HashMap<>();

private StyleSet(String string) {
String[] styles = string.split(";");
for (String s : styles) {
String[] style = s.split(":");
if (style.length == 2) {
styleMap.put(style[0], style[1]);
}
}
}

public String getStyle(String name) {
return styleMap.get(name);
}
}

private static class Properties {

StyleSet mStyles = null;
Attributes mAttrs;
private final String elementName;

private Properties(Attributes attrs) {
private Properties(Attributes attrs, String elementName, StyleSet globalStyleSet) {
mAttrs = attrs;
String styleAttr = getStringAttr("style", attrs);
if (styleAttr != null) {
mStyles = new StyleSet(styleAttr);
}

mStyles = new StyleSet.Builder()
.setAttributeValue(styleAttr)
.applyStyleSet(globalStyleSet)
.build();

this.elementName = elementName;
}

public String getAttr(String name) {
String v = null;
if (mStyles != null) {
v = mStyles.getStyle(name);

String classAttributeValue = getStringAttr("class", mAttrs);

List<String> elementClassesList = null;
if (!TextUtils.isEmpty(classAttributeValue)) {
elementClassesList = Arrays.asList(TextUtils.split(classAttributeValue, "\\s+"));
}

v = mStyles.getStyle(name, elementName, elementClassesList);
}
if (v == null) {
v = getStringAttr(name, mAttrs);
Expand Down Expand Up @@ -1274,6 +1272,9 @@ private void onSvgEnd() {
mSharp.onSvgEnd(mCanvas, mBounds);
}

private boolean recordStyleElementContent = false;
private StringBuffer styleElementContent = null;

private <T> T onSvgElement(@Nullable String id,
@NonNull T element,
@Nullable RectF elementBounds,
Expand Down Expand Up @@ -1612,6 +1613,8 @@ private void doColor(Properties atts, Integer color, boolean fillMode, Paint pai
private int hiddenLevel = 0;
private boolean boundsMode = false;

private StyleSet globalStyleSet;

private void doLimits(float x, float y) {
if (x < mLimits.left) {
mLimits.left = x;
Expand Down Expand Up @@ -1726,6 +1729,9 @@ public void startElement(String namespaceURI, String localName, String qName, At
(int) Math.ceil(mBounds.height()));
//Log.d(TAG, "canvas size: " + mCanvas.getWidth() + "x" + mCanvas.getHeight());
onSvgStart();
} else if (localName.equals("style")) {
recordStyleElementContent = true;
styleElementContent = new StringBuffer();
} else if (localName.equals("defs")) {
mReadingDefs = true;
} else if (localName.equals("linearGradient")) {
Expand All @@ -1734,7 +1740,7 @@ public void startElement(String namespaceURI, String localName, String qName, At
mGradient = doGradient(false, atts);
} else if (localName.equals("stop")) {
if (mGradient != null) {
Properties props = new Properties(atts);
Properties props = new Properties(atts, localName, globalStyleSet);
float offset = props.getFloat("offset", 0);
int color = props.getColor("stop-color");
float alpha = props.getFloat("stop-opacity", 1);
Expand All @@ -1744,7 +1750,7 @@ public void startElement(String namespaceURI, String localName, String qName, At
mGradient.mColors.add(color);
}
} else if (localName.equals("g")) {
Properties props = new Properties(atts);
Properties props = new Properties(atts, localName, globalStyleSet);
// Check to see if this is the "bounds" layer
if ("bounds".equalsIgnoreCase(id)) {
boundsMode = true;
Expand Down Expand Up @@ -1827,7 +1833,7 @@ public void startElement(String namespaceURI, String localName, String qName, At
ry = height / 2;
}
pushTransform(atts);
Properties props = new Properties(atts);
Properties props = new Properties(atts, localName, globalStyleSet);
mRect.set(x, y, x + width, y + height);
if (doFill(props, mRect)) {
mRect = onSvgElement(id, mRect, mRect, mFillPaint);
Expand All @@ -1851,7 +1857,7 @@ public void startElement(String namespaceURI, String localName, String qName, At
Float x2 = getFloatAttr("x2", atts);
Float y1 = getFloatAttr("y1", atts);
Float y2 = getFloatAttr("y2", atts);
Properties props = new Properties(atts);
Properties props = new Properties(atts, localName, globalStyleSet);
if (doStroke(props, mRect)) {
pushTransform(atts);
mLine.set(x1, y1, x2, y2);
Expand All @@ -1877,7 +1883,7 @@ public void startElement(String namespaceURI, String localName, String qName, At
}
if (centerX != null && centerY != null && radiusX != null && radiusY != null) {
pushTransform(atts);
Properties props = new Properties(atts);
Properties props = new Properties(atts, localName, globalStyleSet);
mRect.set(centerX - radiusX, centerY - radiusY, centerX + radiusX, centerY + radiusY);
if (doFill(props, mRect)) {
mRect = onSvgElement(id, mRect, mRect, mFillPaint);
Expand All @@ -1903,7 +1909,7 @@ public void startElement(String namespaceURI, String localName, String qName, At
Path p = new Path();
if (points.size() > 1) {
pushTransform(atts);
Properties props = new Properties(atts);
Properties props = new Properties(atts, localName, globalStyleSet);
p.moveTo(points.get(0), points.get(1));
for (int i = 2; i < points.size(); i += 2) {
float x = points.get(i);
Expand Down Expand Up @@ -1954,7 +1960,7 @@ public void startElement(String namespaceURI, String localName, String qName, At
}
Path p = doPath(d);
pushTransform(atts);
Properties props = new Properties(atts);
Properties props = new Properties(atts, localName, globalStyleSet);
p.computeBounds(mRect, false);
if (doFill(props, mRect)) {
p = onSvgElement(id, p, mRect, mFillPaint);
Expand Down Expand Up @@ -1996,6 +2002,10 @@ public void characters(char ch[], int start, int length) {
if (!mTextStack.isEmpty()) {
mTextStack.peek().setText(ch, start, length);
}

if (recordStyleElementContent) {
styleElementContent.append(ch, start, length);
}
}

@Override
Expand All @@ -2011,6 +2021,11 @@ public void endElement(String namespaceURI, String localName, String qName)
onSvgEnd();
mPicture.endRecording();
break;
case "style":
recordStyleElementContent = false;
globalStyleSet = new StyleSet.Builder()
.setStyleTagValue(styleElementContent.toString())
.build();
case "text":
case "tspan":
if (!mTextStack.isEmpty()) {
Expand Down Expand Up @@ -2112,7 +2127,7 @@ public SvgText(Attributes atts, SvgText parentText) {
y = getFloatAttr("y", atts, parentText != null ? parentText.y : 0f);
text = null;

Properties props = new Properties(atts);
Properties props = new Properties(atts, "text", globalStyleSet);
if (doFill(props, null)) {
fill = new TextPaint(parentText != null && parentText.fill != null
? parentText.fill
Expand Down
122 changes: 122 additions & 0 deletions library/src/main/java/com/pixplicity/sharp/StyleSet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package com.pixplicity.sharp;

import android.text.TextUtils;

import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class StyleSet {
private HashMap<String, String> attributeStyleMap = new HashMap<>();
private HashMap<String, HashMap<String, String>> elementStyleMap = new HashMap<>();
private HashMap<String, HashMap<String, String>> classHashMap = new HashMap<>();

private StyleSet extraStyleSet;

String getStyle(String styleAttributeName, String elementType, List<String> elementClasses) {

// returns value that is defined in the style attribute of the element
if (attributeStyleMap.containsKey(styleAttributeName)) {
return attributeStyleMap.get(styleAttributeName);
}

// returns value that is defined in the class of the element
if (elementClasses != null && elementClasses.size() > 0) {
for(String className: elementClasses) {
if (classHashMap != null && classHashMap.containsKey(className) && classHashMap.get(className).containsKey(styleAttributeName)) {
return classHashMap.get(className).get(styleAttributeName);
}
}
}

if (elementStyleMap != null && elementStyleMap.containsKey(elementType) && elementStyleMap.get(elementType).containsKey(styleAttributeName)) {
return elementStyleMap.get(elementType).get(styleAttributeName);
}

if (extraStyleSet != null) {
return extraStyleSet.getStyle(styleAttributeName, elementType, elementClasses);
}

return null;
}

private StyleSet() { }

private void addStyleAttributesToMap(String attributeValue, HashMap<String, String> attributeStyleMap) {
String[] styles = attributeValue.split(";");
for (String s : styles) {
String[] style = s.split(":");
if (style.length == 2) {
attributeStyleMap.put(style[0], style[1]);
}
}
}

private void parseStyleTag(String styleTagValue) {

if (TextUtils.isEmpty(styleTagValue)) {
return;
}
// Split into separate elements

Pattern regex = Pattern.compile("([^\\{]+)\\s*\\{\\s*([^\\}]+)\\s*\\}");
Matcher matcher = regex.matcher(styleTagValue);

while (matcher.find()) {
if (matcher.groupCount() == 2) {
HashMap<String, String> attrMap = new HashMap<>();
addStyleAttributesToMap(matcher.group(2), attrMap);
if (matcher.group(1).startsWith(".")) {
// Add to the map. Remove the dot in the class name
classHashMap.put(TextUtils.substring(matcher.group(1), 1, matcher.group(1).length()), attrMap);
} else {;
elementStyleMap.put(matcher.group(1), attrMap);
}
}
}
}

private void mergeStyleSet(StyleSet styleSet) {
extraStyleSet = styleSet;
}

static class Builder {
private String attributeValue;
private String styleTagValue;
private StyleSet mergeStyleSet;

protected Builder setAttributeValue(String attributeValue) {
this.attributeValue = attributeValue;
return this;
}

protected Builder setStyleTagValue(String styleTagValue) {
this.styleTagValue = styleTagValue;
return this;
}

protected Builder applyStyleSet(StyleSet styleSet) {
this.mergeStyleSet = styleSet;
return this;
}

protected StyleSet build() {
StyleSet styleSet = new StyleSet();

if (!TextUtils.isEmpty(attributeValue)) {
styleSet.addStyleAttributesToMap(attributeValue, styleSet.attributeStyleMap);
}

if (mergeStyleSet != null) {
styleSet.mergeStyleSet(mergeStyleSet);
}

if (!TextUtils.isEmpty(styleTagValue)) {
styleSet.parseStyleTag(styleTagValue);
}

return styleSet;
}
}
}