├── 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 | //