├── TPSVG ├── .gitignore ├── res │ └── values │ │ └── strings.xml ├── .settings │ └── org.eclipse.jdt.core.prefs ├── AndroidManifest.xml ├── .classpath ├── project.properties ├── proguard-project.txt ├── .project ├── src │ └── com │ │ └── trevorpage │ │ └── tpsvg │ │ ├── internal │ │ ├── Util.java │ │ ├── Gradient.java │ │ ├── ParsedAttributes.java │ │ ├── PatternFill.java │ │ └── SVGPath.java │ │ ├── ITPSVGDrawable.java │ │ ├── SVGPatternShader.java │ │ ├── SVGFlyweightFactory.java │ │ ├── ITpsvgController.java │ │ ├── SVGDrawable.java │ │ ├── SVGView.java │ │ └── SVGParserRenderer.java └── LICENSE └── README.md /TPSVG/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | gen 3 | -------------------------------------------------------------------------------- /TPSVG/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /TPSVG/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 3 | org.eclipse.jdt.core.compiler.compliance=1.5 4 | org.eclipse.jdt.core.compiler.source=1.5 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TPSVG 2 | ===== 3 | 4 | SVG image parser for Android. Converts image to list of native android.graphics objects which can then be speedily rendered on Canvas, and provides callbacks to allow image elements to be manipulated programmatically. -------------------------------------------------------------------------------- /TPSVG/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TPSVG/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /TPSVG/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-8 15 | android.library=true 16 | -------------------------------------------------------------------------------- /TPSVG/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /TPSVG/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | TPSVG 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /TPSVG/src/com/trevorpage/tpsvg/internal/Util.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013 Trevor Page 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | 17 | package com.trevorpage.tpsvg.internal; 18 | 19 | import android.graphics.Paint; 20 | 21 | public class Util { 22 | 23 | public static float bestFitValueTextSize(float width, float height, String string) { 24 | Paint paint = new Paint(); 25 | paint.setTextSize(height); 26 | while (paint.measureText(string) > width) { 27 | height -= 0.5f; 28 | paint.setTextSize(height); 29 | } 30 | return height; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /TPSVG/src/com/trevorpage/tpsvg/ITPSVGDrawable.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013 Trevor Page 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | 17 | package com.trevorpage.tpsvg; 18 | 19 | import android.graphics.Canvas; 20 | import android.graphics.ColorFilter; 21 | import android.graphics.drawable.Drawable; 22 | 23 | /** 24 | * Interface representing a parsed SVG image that has been converted to a series of native 25 | * Android Graphics objects which can be drawn to a Canvas. 26 | * 27 | */ 28 | public class ITPSVGDrawable extends Drawable { 29 | 30 | @Override 31 | public void draw(Canvas arg0) { 32 | // TODO Auto-generated method stub 33 | 34 | } 35 | 36 | @Override 37 | public int getOpacity() { 38 | // TODO Auto-generated method stub 39 | return 0; 40 | } 41 | 42 | @Override 43 | public void setAlpha(int arg0) { 44 | // TODO Auto-generated method stub 45 | 46 | } 47 | 48 | @Override 49 | public void setColorFilter(ColorFilter arg0) { 50 | // TODO Auto-generated method stub 51 | 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /TPSVG/src/com/trevorpage/tpsvg/SVGPatternShader.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013 Trevor Page 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | 17 | package com.trevorpage.tpsvg; 18 | 19 | import android.graphics.Bitmap; 20 | import android.graphics.BitmapShader; 21 | import android.graphics.Canvas; 22 | import android.graphics.Shader; 23 | 24 | public class SVGPatternShader extends BitmapShader { 25 | 26 | public SVGPatternShader(SVGParserRenderer image, String subtreeId, 27 | float viewBoxX, float viewBoxY, float viewBoxW, float viewBoxH) { 28 | super(createBitmap(image, subtreeId, viewBoxX, viewBoxY, viewBoxW, viewBoxH), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); 29 | } 30 | 31 | private static Bitmap createBitmap(SVGParserRenderer image, String subtreeId, 32 | float viewBoxX, float viewBoxY, float viewBoxW, float viewBoxH) { 33 | Bitmap bitmap = Bitmap.createBitmap((int)viewBoxW, (int)viewBoxH, Bitmap.Config.ARGB_8888); 34 | Canvas canvas = new Canvas(bitmap); 35 | canvas.save(); 36 | canvas.translate(-viewBoxX, -viewBoxY); 37 | image.paintImage(canvas, subtreeId, 0, 0, 0, null, true); 38 | canvas.restore(); 39 | return bitmap; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /TPSVG/src/com/trevorpage/tpsvg/internal/Gradient.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013 Trevor Page 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | 17 | package com.trevorpage.tpsvg.internal; 18 | 19 | import java.util.ArrayList; 20 | 21 | import android.graphics.Matrix; 22 | import android.graphics.Shader; 23 | 24 | /** 25 | * Class to encapsulate a gradient. 26 | * A Gradient object is made up in several stages: initially a Gradient is created 27 | * and used to store any information from attributes within the or 28 | * start tag. We may then have child elements such as which add 29 | * further information like stop colours to the current gradient. 30 | */ 31 | public class Gradient { 32 | 33 | public boolean isRadial = false; 34 | public Shader shader; 35 | public Matrix matrix; 36 | public String id; 37 | public float x1; 38 | public float y1; 39 | public float x2; 40 | public float y2; 41 | public float cx; 42 | public float cy; 43 | public float radius; 44 | public float fx; 45 | public float fy; 46 | public String href = null; 47 | 48 | public ArrayList stopColors = new ArrayList(); 49 | 50 | public void setCoordinates(float x1, float y1, float x2, float y2){ 51 | this.x1 = x1; 52 | this.y1 = y1; 53 | this.x2 = x2; 54 | this.y2 = y2; 55 | } 56 | 57 | public static class StopColor { 58 | public int color; 59 | public float offset; 60 | 61 | public StopColor(int color, float offset) { 62 | this.color = color; 63 | this.offset = offset; 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /TPSVG/src/com/trevorpage/tpsvg/internal/ParsedAttributes.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013 Trevor Page 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | 17 | package com.trevorpage.tpsvg.internal; 18 | 19 | import java.util.ArrayList; 20 | 21 | import com.trevorpage.tpsvg.SVGParserRenderer.SvgStyle; 22 | 23 | public class ParsedAttributes { 24 | 25 | public float x; 26 | public float y; 27 | 28 | public float x1; 29 | public float y1; 30 | public float x2; 31 | public float y2; 32 | public float cx; 33 | public float cy; 34 | public float fx; 35 | public float fy; 36 | public float rx; 37 | public float ry; 38 | 39 | public float radius; 40 | public float width; 41 | public float height; 42 | 43 | public String pathData; 44 | public String transformData; 45 | public String styleData; 46 | public String pointsData; 47 | public SvgStyle svgStyle; 48 | 49 | public String id; 50 | public String xlink_href; 51 | 52 | public String viewBox; 53 | 54 | public boolean anchorRight; 55 | public boolean anchorBottom; 56 | 57 | public boolean stretchToRemainderWidth; 58 | public boolean stretchToRemainderHeight; 59 | public String offset; 60 | 61 | public ArrayList rotations; 62 | 63 | public float textLength; 64 | public boolean textLengthAdjustSize; 65 | 66 | public ParsedAttributes() { 67 | transformData = null; 68 | styleData = null; 69 | id = ""; 70 | anchorRight = false; 71 | anchorBottom = false; 72 | stretchToRemainderWidth = false; 73 | stretchToRemainderHeight = false; 74 | rotations = new ArrayList(); 75 | } 76 | } -------------------------------------------------------------------------------- /TPSVG/src/com/trevorpage/tpsvg/SVGFlyweightFactory.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013 Trevor Page 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | 17 | package com.trevorpage.tpsvg; 18 | 19 | import java.io.File; 20 | import java.io.FileNotFoundException; 21 | import java.io.InputStream; 22 | import java.util.TreeMap; 23 | 24 | import android.content.Context; 25 | 26 | public class SVGFlyweightFactory { 27 | 28 | private static SVGFlyweightFactory instance = new SVGFlyweightFactory(); 29 | 30 | public static synchronized SVGFlyweightFactory getInstance(){ 31 | return instance; 32 | } 33 | 34 | private SVGFlyweightFactory(){ 35 | 36 | } 37 | 38 | TreeMap images = new TreeMap(); 39 | 40 | /** 41 | * 42 | */ 43 | public SVGParserRenderer get(int resourceID, Context context) { 44 | SVGParserRenderer image; 45 | if (images.containsKey("resource" + resourceID)) { 46 | image = images.get("resource" + resourceID); 47 | } 48 | else { 49 | image = new SVGParserRenderer(context, resourceID); 50 | images.put("resource" + resourceID, image); 51 | } 52 | return image; 53 | } 54 | 55 | /** 56 | * 57 | */ 58 | public SVGParserRenderer get(File sourceFile, Context context) throws FileNotFoundException { 59 | SVGParserRenderer image; 60 | if (images.containsKey(sourceFile.getName())) { 61 | image = images.get(sourceFile.getName()); 62 | } 63 | else { 64 | image = new SVGParserRenderer(context, sourceFile); 65 | images.put(sourceFile.getName(), image); 66 | } 67 | return image; 68 | } 69 | 70 | /** 71 | * 72 | */ 73 | public SVGParserRenderer get(InputStream sourceStream, String name, Context context) throws FileNotFoundException { 74 | SVGParserRenderer image; 75 | if (images.containsKey(name)) { 76 | image = images.get(name); 77 | } 78 | else { 79 | image = new SVGParserRenderer(context, sourceStream); 80 | images.put(name, image); 81 | } 82 | return image; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /TPSVG/src/com/trevorpage/tpsvg/ITpsvgController.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013 Trevor Page 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | 17 | package com.trevorpage.tpsvg; 18 | 19 | import android.graphics.Matrix; 20 | import android.graphics.Paint; 21 | import android.graphics.Path; 22 | import android.graphics.RectF; 23 | 24 | import com.trevorpage.tpsvg.SVGParserRenderer.Textstring; 25 | 26 | public interface ITpsvgController { 27 | 28 | /** 29 | * 30 | * @param id 31 | * @param matrix 32 | * @param style 33 | * @param iteration 34 | * This parameter is zero the first time this method is called 35 | * for a given SVG element to animate. If the return value is 36 | * true to tell the parser to do a repeat iteration on this path, 37 | * this number is incremented each time. 38 | * 39 | * @return Returning true indicates that the callback method should be 40 | * immediately called back again. Doing this will cause another 41 | * iteration of the same path to be drawn. This can be done as many 42 | * times as required and it allows a single path to be drawn 43 | * multiple times, with different styling and / or transformation on 44 | * each iteration. A good example use is where the SVG file defines 45 | * the graphics for a gauge, which includes just a single tick mark. 46 | * At run-time, the tick mark can be replicated and placed at the 47 | * required degree angles programmatically, thus allowing the scale 48 | * of the gauge to be manipulated at run-time. 49 | */ 50 | boolean animElement(String id, int iteration, Path path, Matrix matrix, 51 | Paint sroke, Paint fill); 52 | 53 | /** 54 | * Inform the controller of remainder width or height. 55 | * 56 | * @param remainderWidth 57 | * @param remainderHeight 58 | */ 59 | void setRemainderWidthOrHeight(float remainderWidth, float remainderHeight); 60 | 61 | /** 62 | * 63 | * @param id 64 | * @param iteration 65 | * @param matrix 66 | * @param style 67 | * @param text 68 | * @return 69 | */ 70 | 71 | boolean animTextElement(String id, int iteration, Matrix matrix, 72 | Paint strokePaint, Paint fillPaint, Textstring text, float x, 73 | float y); 74 | 75 | boolean arcParams(String id, Path path, float startAngle, float sweepAngle, 76 | RectF bounds); 77 | 78 | void setSourceDocumentWidth(int width); 79 | 80 | void setSourceDocumentHeight(int height); 81 | 82 | void onSVGPrivateData(String key, String value); 83 | 84 | } 85 | -------------------------------------------------------------------------------- /TPSVG/src/com/trevorpage/tpsvg/SVGDrawable.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013 Trevor Page 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | 17 | package com.trevorpage.tpsvg; 18 | 19 | import android.graphics.Bitmap; 20 | import android.graphics.Canvas; 21 | import android.graphics.ColorFilter; 22 | import android.graphics.Rect; 23 | import android.graphics.drawable.Drawable; 24 | 25 | public class SVGDrawable extends Drawable { 26 | private SVGParserRenderer mRenderer; 27 | private final float mIntrinsicHeight; 28 | private final float mIntrinsicWidth; 29 | private Bitmap mCacheBitmap = null; 30 | 31 | /** 32 | * Create a new SVGDrawable using the supplied renderer. This drawable's intrinsic width 33 | * and height will be the width and height specified in the SVG image document. 34 | * @param renderer 35 | */ 36 | public SVGDrawable(SVGParserRenderer renderer) { 37 | mRenderer = renderer; 38 | mIntrinsicWidth = mRenderer.getDocumentWidth(); 39 | mIntrinsicHeight = mRenderer.getDocumentHeight(); 40 | } 41 | 42 | /** 43 | * Create a new SVGDrawable using the supplied renderer. This drawable's intrinsic width 44 | * and height will be according to the values supplied, rather than taken from the 45 | * SVG image document. 46 | * @param renderer 47 | * @param intrinsicWidth 48 | * @param intrinsicHeight 49 | */ 50 | public SVGDrawable(SVGParserRenderer renderer, int intrinsicWidth, int intrinsicHeight) { 51 | mRenderer = renderer; 52 | mIntrinsicWidth = intrinsicWidth; 53 | mIntrinsicHeight = intrinsicHeight; 54 | } 55 | 56 | @Override 57 | public void draw(Canvas canvas) { 58 | Rect bounds = getBounds(); 59 | int height = bounds.height(); 60 | int width = bounds.width(); 61 | 62 | float scaleX = (float) width / mRenderer.getDocumentWidth(); 63 | float scaleY = (float) height / mRenderer.getDocumentHeight(); 64 | 65 | if (mCacheBitmap == null) { 66 | mCacheBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 67 | Canvas cacheCanvas = new Canvas(mCacheBitmap); 68 | cacheCanvas.scale(scaleX, scaleY); 69 | mRenderer.paintImage(cacheCanvas, null, 0, 0, 0, null, false); 70 | } 71 | 72 | canvas.drawBitmap(mCacheBitmap, 0, 0, null); 73 | } 74 | 75 | @Override 76 | public void setBounds (int left, int top, int right, int bottom) { 77 | super.setBounds(left, top, right, bottom); 78 | mCacheBitmap = null; 79 | } 80 | 81 | @Override 82 | public void setBounds (Rect bounds) { 83 | super.setBounds(bounds); 84 | mCacheBitmap = null; 85 | } 86 | 87 | @Override 88 | public int getIntrinsicHeight() { 89 | return (int)mIntrinsicHeight; 90 | } 91 | 92 | @Override 93 | public int getIntrinsicWidth() { 94 | return (int)mIntrinsicWidth; 95 | } 96 | 97 | @Override 98 | public int getOpacity() { 99 | return 255; 100 | } 101 | 102 | @Override 103 | public void setAlpha(int alpha) { 104 | } 105 | 106 | @Override 107 | public void setColorFilter(ColorFilter cf) { 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /TPSVG/src/com/trevorpage/tpsvg/internal/PatternFill.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013 Trevor Page 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | 17 | package com.trevorpage.tpsvg.internal; 18 | 19 | import com.trevorpage.tpsvg.SVGParserRenderer; 20 | import com.trevorpage.tpsvg.SVGPatternShader; 21 | 22 | import android.graphics.Shader; 23 | 24 | /** 25 | * Encapsulates specifics relating to a pattern fill, which is defined within the SVG file as 26 | * a <pattern> element. During parsing, this object is constructed for each <pattern> 27 | * This object is used to retain information about a pattern fill during parsing of the SVG file. 28 | * A Shader object can only be generated based on this information once SVG file parsing has finished, 29 | * because only at that point can the parsed data be used to render the pattern tile. 30 | * Similarly, if the pattern uses a xlink:href to another pattern, the href should be resolved 31 | * to a linked pattern after SVG parsing in case of forward references. 32 | */ 33 | public class PatternFill { 34 | 35 | private String mSubtreeId; 36 | private SVGPatternShader mShader; 37 | private float x; 38 | private float y; 39 | private float width; 40 | private float height; 41 | private String mXLinkReferenceId; 42 | private PatternFill mXLinkReferencePatternFill; 43 | 44 | /** 45 | * Where the pattern is defined as a series of vector paths within the SVG file, 46 | * set the ID string of the element that contains all the vector data. This is the 47 | * ID of the <pattern> element itself. 48 | * @param subtreeId 49 | */ 50 | public void setPatternSubtree(String subtreeId) { 51 | mSubtreeId = subtreeId; 52 | } 53 | 54 | /** 55 | * Set the actual area that represents the valid pattern tile. 56 | * @param x 57 | * @param y 58 | * @param width 59 | * @param height 60 | */ 61 | public void setPatternViewBox(float x, float y, float width, float height) { 62 | this.x = x; 63 | this.y = y; 64 | this.width = width; 65 | this.height = height; 66 | } 67 | 68 | /** 69 | * Obtain the Shader representing this pattern that can be directly set to a Paint (using 70 | * Paint.setShader()). Internally, an SVGPatternShader will create a bitmap tile based 71 | * on the subtree of the parsed SVG file that represents the pattern tile (assuming 72 | * it's a vector pattern). 73 | * This method must be called only once parsing of the SVG file has completely finished. 74 | * @return 75 | */ 76 | public Shader createPatternShader(SVGParserRenderer svgParserRenderer) { 77 | if (mShader == null) { 78 | if (mSubtreeId != null) { 79 | mShader = new SVGPatternShader(svgParserRenderer, mSubtreeId, x, y, width, height); 80 | } 81 | else if (mXLinkReferencePatternFill != null) { 82 | mShader = (SVGPatternShader) mXLinkReferencePatternFill.createPatternShader(svgParserRenderer); 83 | } 84 | } 85 | return mShader; 86 | } 87 | 88 | public void setXLinkReferenceId(String xLinkReferenceId) { 89 | mXLinkReferenceId = xLinkReferenceId; 90 | } 91 | 92 | public String getXLinkReferenceId() { 93 | return mXLinkReferenceId; 94 | } 95 | 96 | public void setXLinkReferencePatternFill(PatternFill xLinkReferencePatternFill) { 97 | mXLinkReferencePatternFill = xLinkReferencePatternFill; 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /TPSVG/src/com/trevorpage/tpsvg/internal/SVGPath.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013 Trevor Page 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | 17 | package com.trevorpage.tpsvg.internal; 18 | 19 | import java.util.ArrayList; 20 | 21 | import android.graphics.Matrix; 22 | import android.graphics.Path; 23 | 24 | /** 25 | * A subclass of android.graphics.Path that allows for some custom properties. 26 | * 27 | */ 28 | public class SVGPath extends Path { 29 | 30 | private boolean mAnchorRight; 31 | private boolean mAnchorBottom; 32 | private boolean mStretchToRemainderWidth; 33 | private boolean mStretchToRemainderHeight; 34 | protected ArrayList mVisibleOnRotations; 35 | 36 | public SVGPath() { 37 | super(); 38 | init(); 39 | } 40 | 41 | public SVGPath (Path src) { 42 | super(src); 43 | init(); 44 | } 45 | 46 | private void init() { 47 | mAnchorRight = false; 48 | mAnchorBottom = false; 49 | mStretchToRemainderWidth = false; 50 | mStretchToRemainderHeight = false; 51 | mVisibleOnRotations = null; 52 | } 53 | 54 | public void rewind() { 55 | super.rewind(); 56 | init(); 57 | } 58 | 59 | public void reset() { 60 | super.reset(); 61 | init(); 62 | } 63 | 64 | public void addPath(Path src) { 65 | super.addPath(src); 66 | copyCustomAttributes(src); 67 | } 68 | 69 | public void addPath(Path src, Matrix matrix) { 70 | super.addPath(src); 71 | copyCustomAttributes(src); 72 | } 73 | 74 | public void addPath(Path src, float dx, float dy) { 75 | super.addPath(src, dx, dy); 76 | copyCustomAttributes(src); 77 | } 78 | 79 | public void setAnchorRight(boolean anchor) { 80 | mAnchorRight = anchor; 81 | } 82 | 83 | public boolean getAnchorRight() { 84 | return mAnchorRight; 85 | } 86 | 87 | public void setAnchorBottom(boolean anchor) { 88 | mAnchorBottom = anchor; 89 | } 90 | 91 | public boolean getAnchorBottom() { 92 | return mAnchorBottom; 93 | } 94 | 95 | public boolean usesRemainderWidthOrHeight() { 96 | return mAnchorBottom || mAnchorRight || mStretchToRemainderWidth || mStretchToRemainderHeight; 97 | } 98 | 99 | public void setStretchToRemainderWidth(boolean stretch) { 100 | mStretchToRemainderWidth = stretch; 101 | } 102 | 103 | public boolean getStretchToRemainderWidth() { 104 | return mStretchToRemainderWidth; 105 | } 106 | 107 | public void setStretchToRemainderHeight(boolean stretch) { 108 | mStretchToRemainderHeight = stretch; 109 | } 110 | 111 | public boolean getStretchToRemainderHeight() { 112 | return mStretchToRemainderHeight; 113 | } 114 | 115 | private void copyCustomAttributes(Path src) { 116 | if (src instanceof SVGPath) { 117 | if (((SVGPath)src).getAnchorBottom()) { 118 | setAnchorBottom(true); 119 | } 120 | if (((SVGPath)src).getAnchorRight()) { 121 | setAnchorRight(true); 122 | } 123 | if (((SVGPath)src).getStretchToRemainderWidth()) { 124 | setStretchToRemainderWidth(true); 125 | } 126 | if (((SVGPath)src).getStretchToRemainderHeight()) { 127 | setStretchToRemainderHeight(true); 128 | } 129 | if (((SVGPath)src).mVisibleOnRotations != null) { 130 | addVisibleOnRotations(((SVGPath)src).mVisibleOnRotations); 131 | } 132 | } 133 | } 134 | 135 | public void addVisibleOnRotations(ArrayList rotations) { 136 | if (rotations != null && rotations.size() > 0) { 137 | if (mVisibleOnRotations == null) { 138 | mVisibleOnRotations = new ArrayList(); 139 | } 140 | mVisibleOnRotations.addAll(rotations); 141 | } 142 | } 143 | 144 | public boolean getVisibleOnRotation(int rotation) { 145 | return mVisibleOnRotations == null ? true : mVisibleOnRotations.contains(rotation); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /TPSVG/src/com/trevorpage/tpsvg/SVGView.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013 Trevor Page 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | 17 | package com.trevorpage.tpsvg; 18 | 19 | import android.content.Context; 20 | import android.graphics.Bitmap; 21 | import android.graphics.Canvas; 22 | import android.graphics.Paint; 23 | import android.util.AttributeSet; 24 | import android.view.View; 25 | 26 | public class SVGView extends View { 27 | 28 | @SuppressWarnings("unused") 29 | private static final String LOGTAG = SVGView.class.getSimpleName(); 30 | private Paint mDrawPaint = new Paint(); 31 | private SVGParserRenderer mSvgImage; 32 | private ITpsvgController mController; 33 | Bitmap mRenderBitmap = null; 34 | boolean mEntireRedrawNeeded = false; 35 | String subtree = null; 36 | private int mRotation = 0; 37 | Canvas mCanvas; 38 | private boolean mFill = false; 39 | 40 | // Tried using WeakReference to avoid View-Bitmap memory leak 41 | // issues, but this seems 42 | // to lead to very frequent GC of the bitmaps, leading to terrible 43 | // performance penalty. 44 | // WeakReference bm; 45 | 46 | public SVGView(Context context) { 47 | super(context); 48 | init(context); 49 | } 50 | 51 | public SVGView(Context context, AttributeSet attrs) { 52 | super(context, attrs); 53 | init(context); 54 | } 55 | 56 | public SVGView(Context context, AttributeSet attrs, int defStyle) { 57 | super(context, attrs, defStyle); 58 | init(context); 59 | } 60 | 61 | /** 62 | * Set fill mode. 63 | * 64 | * @param fill 65 | * fill mode 66 | */ 67 | public void setFill(boolean fill) { 68 | mFill = fill; 69 | } 70 | 71 | /** 72 | * Get fill mode. 73 | * 74 | * @return fill mode 75 | */ 76 | public boolean getFill() { 77 | return mFill; 78 | } 79 | 80 | /** 81 | * Set the orientation value in degrees to be applied during SVG rendering. 82 | * The supplied orientation should be only a multiple of 90 degrees (0, 90, 83 | * 180, or 270). This is implemented despite existing View 84 | * getRotation/setRotation methods because at present the SVG renderer 85 | * automatically sets the rotation pivot point and, importantly, also 86 | * correctly manipulates the remainder width / remainder height so that 87 | * special anchor and stretch attributes still work, but can only presently 88 | * do this at 90 degree multiples. At a later stage it might be adapted to 89 | * cope with all rotations and therefore the existing View float rotation 90 | * methods can be used. 91 | * 92 | * @param rotation 93 | * in degrees 94 | */ 95 | public void setOrientation(int rotation) { 96 | mRotation = rotation; 97 | } 98 | 99 | /** 100 | * Get the orientation value in degrees. Refer to {@link setOrientation}. 101 | * 102 | * @return rotation in degrees 103 | */ 104 | public int getOrientation() { 105 | return mRotation; 106 | } 107 | 108 | // ------------- Initial canvas size setup and scaling --------------------- 109 | 110 | @Override 111 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 112 | 113 | int widthMode = MeasureSpec.getMode(widthMeasureSpec); 114 | int widthSize = MeasureSpec.getSize(widthMeasureSpec); 115 | 116 | int heightMode = MeasureSpec.getMode(heightMeasureSpec); 117 | int heightSize = MeasureSpec.getSize(heightMeasureSpec); 118 | 119 | int chosenWidth; 120 | int chosenHeight; 121 | 122 | if (heightMode == MeasureSpec.AT_MOST 123 | && widthMode == MeasureSpec.EXACTLY) { 124 | // Usually the case if height is MATCH_PARENT and the width is 125 | // WRAP_CONTENT 126 | chosenWidth = widthSize; 127 | chosenHeight = (int) (mSvgImage.getDocumentHeight() * ((float) widthSize / (float) mSvgImage 128 | .getDocumentWidth())); 129 | } 130 | 131 | else if (heightMode == MeasureSpec.EXACTLY 132 | && widthMode == MeasureSpec.AT_MOST) { 133 | // Usually the case if width is MATCH_PARENT and the height is 134 | // WRAP_CONTENT 135 | chosenHeight = heightSize; 136 | chosenWidth = (int) (mSvgImage.getDocumentWidth() * ((float) heightSize / (float) mSvgImage 137 | .getDocumentHeight())); 138 | } 139 | 140 | else if (heightMode == MeasureSpec.AT_MOST 141 | && widthMode == MeasureSpec.AT_MOST) { 142 | float uniformScaleFactor; 143 | uniformScaleFactor = Math.min( 144 | (float) widthSize / (float) mSvgImage.getDocumentWidth(), 145 | (float) heightSize / (float) mSvgImage.getDocumentHeight()); 146 | chosenHeight = (int) (mSvgImage.getDocumentWidth() * uniformScaleFactor); 147 | chosenWidth = (int) (mSvgImage.getDocumentHeight() * uniformScaleFactor); 148 | } 149 | 150 | else if ((heightMode == MeasureSpec.UNSPECIFIED) != (widthMode == MeasureSpec.UNSPECIFIED)) { 151 | // One of them is UNSPECIFIED and the other is either AT_MOST or 152 | // EXACTLY 153 | if (heightMode == MeasureSpec.UNSPECIFIED) { 154 | chosenWidth = widthSize; 155 | chosenHeight = (int) (mSvgImage.getDocumentHeight() * ((float) widthSize / (float) mSvgImage 156 | .getDocumentWidth())); 157 | } else { 158 | chosenHeight = heightSize; 159 | chosenWidth = (int) (mSvgImage.getDocumentWidth() * ((float) heightSize / (float) mSvgImage 160 | .getDocumentHeight())); 161 | } 162 | } 163 | 164 | else { 165 | chosenWidth = chooseDimension(widthMode, widthSize, 166 | mSvgImage.getDocumentWidth()); 167 | chosenHeight = chooseDimension(heightMode, heightSize, 168 | mSvgImage.getDocumentHeight()); 169 | } 170 | 171 | setMeasuredDimension(chosenWidth, chosenHeight); 172 | } 173 | 174 | private int chooseDimension(int mode, int size, int documentSize) { 175 | if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) { 176 | return size; 177 | } else { // (mode == MeasureSpec.UNSPECIFIED) 178 | return documentSize; 179 | } 180 | } 181 | 182 | // in case there is no size specified 183 | private int getPreferredSize() { 184 | return 270; 185 | } 186 | 187 | private void init(Context context) { 188 | setDrawingCacheEnabled(false); 189 | mDrawPaint.setAntiAlias(false); 190 | mDrawPaint.setFilterBitmap(true); 191 | mDrawPaint.setDither(false); 192 | mRotation = context.getResources().getConfiguration().orientation; 193 | } 194 | 195 | public void setSVGRenderer(SVGParserRenderer image, String subtreeTagName) { 196 | mSvgImage = image; 197 | setSubtree(subtreeTagName); 198 | } 199 | 200 | public void bindController(ITpsvgController controller) { 201 | if (mSvgImage == null) { 202 | throw new IllegalStateException( 203 | "The parsed SVG image object needs to be specified first."); 204 | } 205 | mController = controller; 206 | // TODO: This is potentially going to be done multiple times, once for 207 | // each child SVGView of the 208 | // widget. I question at the moment if / why the controller should be 209 | // bound to the individual SVGViews 210 | // and not directly to the SVGParserRenderer. 211 | mController.setSourceDocumentHeight(mSvgImage.getDocumentHeight()); 212 | mController.setSourceDocumentWidth(mSvgImage.getDocumentWidth()); 213 | mSvgImage.obtainSVGPrivateData(mController); 214 | } 215 | 216 | /** 217 | * Specify the particular subtree (or 'node') of the original SVG XML file 218 | * that this view shall render. The default is null, which results in the 219 | * entire SVG image being rendered. 220 | * 221 | * @param nodeId 222 | */ 223 | public void setSubtree(String subtreeId) { 224 | subtree = subtreeId; 225 | } 226 | 227 | @Override 228 | protected void onDraw(Canvas canvas) { 229 | 230 | if (mRenderBitmap == null) { 231 | mRenderBitmap = Bitmap.createBitmap(getMeasuredWidth(), 232 | getMeasuredHeight(), Bitmap.Config.ARGB_8888); 233 | mEntireRedrawNeeded = true; 234 | mCanvas = new Canvas(mRenderBitmap); 235 | } 236 | 237 | if (mEntireRedrawNeeded) { 238 | mEntireRedrawNeeded = false; 239 | mRenderBitmap.eraseColor(android.graphics.Color.TRANSPARENT); 240 | Canvas c = new Canvas(mRenderBitmap); 241 | mSvgImage.paintImage(c, subtree, getWidth(), getHeight(), 242 | mController, mFill, mRotation); 243 | } 244 | 245 | canvas.drawBitmap(mRenderBitmap, 0f, 0f, mDrawPaint); 246 | } 247 | 248 | /** 249 | * This could be called from non-UI thread. 250 | */ 251 | public void invalidateBitmap() { 252 | mEntireRedrawNeeded = true; 253 | super.postInvalidate(); 254 | } 255 | 256 | @Override 257 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 258 | mRenderBitmap = null; 259 | super.onSizeChanged(w, h, oldw, oldh); 260 | } 261 | 262 | } 263 | -------------------------------------------------------------------------------- /TPSVG/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /TPSVG/src/com/trevorpage/tpsvg/SVGParserRenderer.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013 Trevor Page 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | 17 | package com.trevorpage.tpsvg; 18 | 19 | import java.io.File; 20 | import java.io.FileInputStream; 21 | import java.io.FileNotFoundException; 22 | import java.io.InputStream; 23 | import java.util.ArrayList; 24 | import java.util.HashMap; 25 | import java.util.Iterator; 26 | import java.util.Map; 27 | import java.util.Stack; 28 | import java.util.regex.Matcher; 29 | import java.util.regex.Pattern; 30 | 31 | import javax.xml.parsers.SAXParser; 32 | import javax.xml.parsers.SAXParserFactory; 33 | 34 | import org.xml.sax.Attributes; 35 | import org.xml.sax.InputSource; 36 | import org.xml.sax.SAXException; 37 | import org.xml.sax.XMLReader; 38 | import org.xml.sax.helpers.AttributesImpl; 39 | import org.xml.sax.helpers.DefaultHandler; 40 | 41 | import android.content.Context; 42 | import android.content.res.Resources; 43 | import android.graphics.Canvas; 44 | import android.graphics.LinearGradient; 45 | import android.graphics.Matrix; 46 | import android.graphics.Paint; 47 | import android.graphics.Path; 48 | import android.graphics.Path.Direction; 49 | import android.graphics.RadialGradient; 50 | import android.graphics.RectF; 51 | import android.graphics.Shader; 52 | import android.graphics.Typeface; 53 | import android.util.Log; 54 | import android.view.View; 55 | 56 | import com.trevorpage.tpsvg.internal.Gradient; 57 | import com.trevorpage.tpsvg.internal.ParsedAttributes; 58 | import com.trevorpage.tpsvg.internal.PatternFill; 59 | import com.trevorpage.tpsvg.internal.SVGPath; 60 | import com.trevorpage.tpsvg.internal.Util; 61 | 62 | public class SVGParserRenderer extends DefaultHandler { 63 | 64 | private static final String LOGTAG = "SVGParserRenderer"; 65 | private static final String ASSETS_FONTS_ROOT_DIRECTORY = "fonts"; 66 | 67 | private static final String CUSTOM_ATTRIBUTE_NAMESPACE = "tpsvg:"; 68 | private String mPrivateDataNamespace = "msdroid:"; 69 | 70 | // Bytecode instruction set 71 | private static final byte INST_END = 0; 72 | private static final byte INST_PATH = 1; 73 | private static final byte INST_MATRIX = 2; 74 | private static final byte INST_BEGINGROUP = 3; 75 | private static final byte INST_ENDGROUP = 4; 76 | private static final byte INST_STYLE = 5; 77 | private static final byte INST_TEXTSTRING = 6; 78 | private static final byte INST_IDSTRING = 7; 79 | private static final byte INST_ARC = 8; 80 | private static final byte INST_BEGIN_PATTERN = 9; 81 | private static final byte INST_END_PATTERN = 10; 82 | 83 | // XML tags 84 | private static final String STARTTAG_SVG = "svg"; 85 | private static final String STARTTAG_G = "g"; 86 | private static final String STARTTAG_PATH = "path"; 87 | private static final String STARTTAG_RECT = "rect"; 88 | private static final String STARTTAG_LINE = "line"; 89 | private static final String STARTTAG_POLYGON = "polygon"; 90 | private static final String STARTTAG_CIRCLE = "circle"; 91 | private static final String STARTTAG_TEXT = "text"; 92 | private static final String STARTTAG_TSPAN = "tspan"; 93 | // private static final String STARTTAG_TEXTPATH = "textPath"; 94 | private static final String STARTTAG_RADIALGRADIENT = "radialGradient"; 95 | private static final String STARTTAG_LINEARGRADIENT = "linearGradient"; 96 | private static final String STARTTAG_STOP = "stop"; 97 | private static final String STARTTAG_DEFS = "defs"; 98 | private static final String STARTTAG_PATTERN = "pattern"; 99 | 100 | private static final String SPECIAL_ID_PREFIX_ANIM = "_anim"; 101 | 102 | // private static final String SPECIAL_ID_PREFIX_META = "_meta"; 103 | // private static final String SPECIAL_ID_PREFIX_ARCPARAMS = "_arcparams"; 104 | 105 | /** Supported standard SVG attributes */ 106 | private enum StandardAttributes { 107 | x, y, x1, y1, x2, y2, cx, cy, fx, fy, r, rx, ry, height, width, d, transform, gradientTransform, style, href, id, opacity, fill, fill_opacity, font_size, font_family, stroke, stroke_fill, stroke_opacity, stroke_width, text_align, text_anchor, offset, points, viewBox, novalue, lengthAdjust, textLength; 108 | 109 | public static StandardAttributes toAttr(String str) { 110 | try { 111 | return valueOf(str.replace('-', '_')); 112 | } catch (Exception e) { 113 | return novalue; 114 | } 115 | } 116 | } 117 | 118 | /** 119 | * Custom attributes that are special to this SVG library. Some elements can 120 | * use these to access special functionality that this library provides. 121 | * When used they are prefixed with CUSTOM_ATTRIBUTE_NAMESPACE 122 | */ 123 | private enum CustomAttributes { 124 | anchor, stretch_to_remainder, visible_on_rotation, lengthAdjust, novalue; 125 | 126 | public static CustomAttributes toAttr(String str) { 127 | try { 128 | return valueOf(str.replace('-', '_')); 129 | } catch (Exception e) { 130 | return novalue; 131 | } 132 | } 133 | } 134 | 135 | private ParsedAttributes mParsedAttributes; 136 | private float mRootSvgHeight = 100; 137 | private float mRootSvgWidth = 100; 138 | 139 | // Lists and stacks for executable code 140 | ArrayList matrixList = new ArrayList(); 141 | ArrayList pathList = new ArrayList(); 142 | ArrayList paintStack = new ArrayList(); 143 | ArrayList styleList = new ArrayList(); 144 | ArrayList gradientList = new ArrayList(); 145 | ArrayList textstringList = new ArrayList(); 146 | HashMap subtreeJumpMap = new HashMap(); 147 | ArrayList idstringList = new ArrayList(); 148 | ArrayList arcsList = new ArrayList(); 149 | 150 | // Data structures used during parsing 151 | private int tagDepth; 152 | private String mCurrentElement; 153 | private Gradient currentGradient = new Gradient(); 154 | private int codePtr; 155 | private ArrayList bytecodeList; // Expandable list used for initial 156 | // creation of bytecode from 157 | // parsing. 158 | private byte[] bytecodeArr; // Holds the complete bytecode for an SVG image 159 | // once parsed. 160 | private Stack matrixEvStack = new Stack(); // Used for 161 | // chaining 162 | // transformations 163 | // on nested 164 | // nodes. 165 | private boolean[] matrixExistsAtDepth = new boolean[20]; 166 | private Stack mStyleParseStack = new Stack(); 167 | 168 | private float mCurrentX; 169 | private float mCurrentY; 170 | private float mLastControlPointX = 0; 171 | private float mLastControlPointY = 0; 172 | 173 | private Context mContext; 174 | private HashMap mPrivateDataMap; 175 | private String mPrivateDataCurrentKey; 176 | 177 | private HashMap mPatternMap = new HashMap(); 178 | 179 | public SVGParserRenderer() { 180 | mPrivateDataMap = new HashMap(); 181 | } 182 | 183 | public SVGParserRenderer(Context context, int resourceID) { 184 | mPrivateDataMap = new HashMap(); 185 | parseImageFile(context, resourceID); 186 | } 187 | 188 | public SVGParserRenderer(Context context, File sourceFile) 189 | throws FileNotFoundException { 190 | mPrivateDataMap = new HashMap(); 191 | parseImageFile(context, sourceFile); 192 | } 193 | 194 | public SVGParserRenderer(Context context, InputStream sourceStream) { 195 | mPrivateDataMap = new HashMap(); 196 | parseImageFile(context, sourceStream); 197 | } 198 | 199 | public void setPrivateDataNamespace(String namespace) { 200 | mPrivateDataNamespace = namespace; 201 | } 202 | 203 | public String getPrivateDataValue(String key) { 204 | return mPrivateDataMap.get(key); 205 | } 206 | 207 | public void obtainSVGPrivateData(ITpsvgController controller) { 208 | Iterator> it = mPrivateDataMap.entrySet() 209 | .iterator(); 210 | while (it.hasNext()) { 211 | Map.Entry pairs = (Map.Entry) it 212 | .next(); 213 | controller.onSVGPrivateData(pairs.getKey(), pairs.getValue()); 214 | } 215 | } 216 | 217 | public void parseImageFile(Context context, File sourceFile) 218 | throws FileNotFoundException { 219 | InputStream inStream = new FileInputStream(sourceFile); 220 | parseImageFile(context, inStream); 221 | } 222 | 223 | public void parseImageFile(Context context, int resourceID) { 224 | Resources res = context.getResources(); 225 | InputStream inStream = res.openRawResource(resourceID); 226 | parseImageFile(context, inStream); 227 | } 228 | 229 | public void parseImageFile(Context context, InputStream inStream) { 230 | mContext = context; 231 | tagDepth = 0; 232 | codePtr = 0; 233 | mParsedAttributes = new ParsedAttributes(); 234 | 235 | this.gradientList.clear(); 236 | this.matrixList.clear(); 237 | matrixEvStack.clear(); 238 | this.paintStack.clear(); 239 | this.pathList.clear(); 240 | this.styleList.clear(); 241 | this.arcsList.clear(); 242 | 243 | bytecodeList = new ArrayList(); 244 | 245 | SvgStyle s = new SvgStyle(); 246 | 247 | mStyleParseStack.add(s); 248 | 249 | SAXParserFactory spf = SAXParserFactory.newInstance(); 250 | try { 251 | SAXParser sp = spf.newSAXParser(); 252 | XMLReader xr = sp.getXMLReader(); 253 | xr.setContentHandler(this); 254 | xr.parse(new InputSource(inStream)); 255 | } catch (Exception e) { 256 | } 257 | 258 | addInstruction(INST_END); 259 | 260 | bytecodeArr = new byte[bytecodeList.size()]; 261 | for (int i = 0; i < bytecodeList.size(); i++) { 262 | bytecodeArr[i] = bytecodeList.get(i); 263 | } 264 | 265 | for (SvgStyle style : styleList) { 266 | if (style.mFillPattern != null) { 267 | if (style.mFillPattern.getXLinkReferenceId() != null) { 268 | style.mFillPattern.setXLinkReferencePatternFill(mPatternMap 269 | .get(style.mFillPattern.getXLinkReferenceId())); 270 | } 271 | style.fillPaint.setShader(style.mFillPattern 272 | .createPatternShader(this)); 273 | style.mFillPattern = null; 274 | } 275 | } 276 | 277 | mContext = null; 278 | } 279 | 280 | @Override 281 | public void characters(char[] ch, int start, int length) 282 | throws SAXException { 283 | super.characters(ch, start, length); 284 | 285 | if (mCurrentElement.equalsIgnoreCase(STARTTAG_TEXT)) { 286 | text_characters(ch, start, length); 287 | } else if (mCurrentElement.equalsIgnoreCase(STARTTAG_TSPAN)) { 288 | tspan_characters(ch, start, length); 289 | } else if (mPrivateDataCurrentKey != null) { 290 | mPrivateDataMap.put(mPrivateDataCurrentKey, new String(ch, start, 291 | length)); 292 | } 293 | } 294 | 295 | @Override 296 | public void endElement(String uri, String localName, String name) 297 | throws SAXException { 298 | super.endElement(uri, localName, name); 299 | 300 | mPrivateDataCurrentKey = ""; 301 | mCurrentElement = ""; 302 | 303 | if (localName.equalsIgnoreCase(STARTTAG_G)) { 304 | addEndGroup(); 305 | } else if (localName.equalsIgnoreCase(STARTTAG_LINEARGRADIENT)) { 306 | finaliseLinearGradient(); 307 | } else if (localName.equalsIgnoreCase(STARTTAG_RADIALGRADIENT)) { 308 | finaliseRadialGradient(); 309 | } else if (localName.equalsIgnoreCase(STARTTAG_DEFS)) { 310 | completeXLinks(); 311 | } else if (localName.equalsIgnoreCase(STARTTAG_PATTERN)) { 312 | endPattern(); 313 | } 314 | 315 | tagDepth--; 316 | 317 | if (matrixExistsAtDepth[tagDepth]) { 318 | this.matrixEvStack.pop(); 319 | } 320 | 321 | mStyleParseStack.pop(); 322 | } 323 | 324 | @Override 325 | public void startDocument() throws SAXException { 326 | super.startDocument(); 327 | } 328 | 329 | @Override 330 | public void endDocument() throws SAXException { 331 | super.endDocument(); 332 | } 333 | 334 | /** 335 | * 336 | */ 337 | @Override 338 | public void startElement(String uri, String localName, String qName, 339 | Attributes attributes) throws SAXException { 340 | 341 | super.startElement(uri, localName, qName, attributes); 342 | 343 | matrixExistsAtDepth[tagDepth] = false; 344 | mCurrentElement = localName; 345 | mParsedAttributes.svgStyle = new SvgStyle(mStyleParseStack.peek()); 346 | 347 | if (mPrivateDataNamespace != null 348 | && qName.startsWith(mPrivateDataNamespace)) { 349 | mPrivateDataCurrentKey = localName; 350 | } else { 351 | mPrivateDataCurrentKey = null; 352 | } 353 | 354 | if (localName.equalsIgnoreCase(STARTTAG_SVG)) { 355 | parseAttributes(attributes); 356 | svg(); 357 | } else if (localName.equalsIgnoreCase(STARTTAG_G)) { 358 | parseAttributes(attributes); 359 | addBeginGroup(mParsedAttributes.id); 360 | } else if (localName.equalsIgnoreCase(STARTTAG_PATH)) { 361 | parseAttributes(attributes); 362 | path(); 363 | } else if (localName.equalsIgnoreCase(STARTTAG_RECT)) { 364 | parseAttributes(attributes); 365 | rect(); 366 | } else if (localName.equalsIgnoreCase(STARTTAG_LINE)) { 367 | parseAttributes(attributes); 368 | line(); 369 | } else if (localName.equalsIgnoreCase(STARTTAG_POLYGON)) { 370 | parseAttributes(attributes); 371 | polygon(); 372 | } else if (localName.equalsIgnoreCase(STARTTAG_CIRCLE)) { 373 | parseAttributes(attributes); 374 | circle(); 375 | } else if (localName.equalsIgnoreCase(STARTTAG_TEXT)) { 376 | parseAttributes(attributes); 377 | text_element(); 378 | } else if (localName.equalsIgnoreCase(STARTTAG_TSPAN)) { 379 | parseAttributes(attributes); 380 | tspan_element(); 381 | } else if (localName.equalsIgnoreCase(STARTTAG_LINEARGRADIENT)) { 382 | parseAttributes(attributes); 383 | linearGradient(); 384 | } else if (localName.equalsIgnoreCase(STARTTAG_RADIALGRADIENT)) { 385 | parseAttributes(attributes); 386 | radialGradient(); 387 | } else if (localName.equalsIgnoreCase(STARTTAG_STOP)) { 388 | parseAttributes(attributes); 389 | gradientStop(); 390 | } else if (localName.equalsIgnoreCase(STARTTAG_PATTERN)) { 391 | parseAttributes(attributes); 392 | startPattern(); 393 | } 394 | 395 | mStyleParseStack.add(mParsedAttributes.svgStyle); 396 | tagDepth++; 397 | } 398 | 399 | private void parseAttributes(Attributes attributes) { 400 | 401 | AttributesImpl attrImpl = new AttributesImpl(attributes); 402 | 403 | // Reset attributes that don't inherit. 404 | mParsedAttributes.transformData = null; 405 | mParsedAttributes.styleData = null; 406 | mParsedAttributes.id = ""; 407 | mParsedAttributes.anchorRight = false; 408 | mParsedAttributes.anchorBottom = false; 409 | mParsedAttributes.stretchToRemainderWidth = false; 410 | mParsedAttributes.stretchToRemainderWidth = false; 411 | mParsedAttributes.rotations = new ArrayList(); 412 | // It is important to reset co-ordinates to zero because I've seen some 413 | // elements (produced by Illustrator) that 414 | // omit co-ordinates (implying 0,0 or top left) and use a transform to 415 | // actually place the element. 416 | mParsedAttributes.x = 0; 417 | mParsedAttributes.y = 0; 418 | mParsedAttributes.cx = 0; 419 | mParsedAttributes.cy = 0; 420 | mParsedAttributes.x1 = 0; 421 | mParsedAttributes.x2 = 0; 422 | mParsedAttributes.y1 = 0; 423 | mParsedAttributes.y2 = 0; 424 | mParsedAttributes.rx = 0; 425 | mParsedAttributes.ry = 0; 426 | 427 | // Not sure if the 'opacity' attribute (as opposed to fill-opacity or 428 | // stroke-opacity 429 | // attributes) is supposed to inherit, so for now reset it to 1 each 430 | // time. Remove this later 431 | // if it needs to inherit. Also, fill-opacity and stroke-opacity do 432 | // inherit for time being. 433 | mParsedAttributes.svgStyle.masterOpacity = 1; 434 | mParsedAttributes.svgStyle.fillOpacity = 1; 435 | mParsedAttributes.svgStyle.strokeOpacity = 1; 436 | 437 | mParsedAttributes.textLength = 0; 438 | mParsedAttributes.textLengthAdjustSize = false; 439 | 440 | // During execution of the loop, the length of attrImpl will expand if a 441 | //