diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/SVGDrawer.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/SVGDrawer.java index 280aed900..72b7a210f 100644 --- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/SVGDrawer.java +++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/extend/SVGDrawer.java @@ -1,9 +1,15 @@ package com.openhtmltopdf.extend; +import java.util.List; + import org.w3c.dom.Element; +import com.openhtmltopdf.css.sheet.FontFaceRule; +import com.openhtmltopdf.layout.SharedContext; import com.openhtmltopdf.render.RenderingContext; public interface SVGDrawer { - public void drawSVG(Element svgElement, OutputDevice outputDevice, RenderingContext ctx, double x, double y); + public void drawSVG(Element svgElement, OutputDevice outputDevice, RenderingContext ctx, double x, double y, SharedContext shared); + + public void importFontFaceRules(List fontFaces); } diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java index 96c8329ae..e6afdfa77 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java @@ -53,6 +53,8 @@ import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDFontFactory; +import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory; import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; @@ -1260,8 +1262,6 @@ public void setBidiReorderer(BidiReorderer reorderer) { @Override public void drawText(RenderingContext c, String text, float x, float y) { - // TODO Auto-generated method stub - } @Override diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java index d3afeb43a..a764ca3bb 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java @@ -102,6 +102,7 @@ public class PdfBoxRenderer { private PDFCreationListener _listener; private OutputStream _os; + private SVGDrawer _svgImpl; public PdfBoxRenderer(boolean testMode) { this(DEFAULT_DOTS_PER_POINT, DEFAULT_DOTS_PER_PIXEL, true, testMode, null, null, null, null); @@ -109,7 +110,7 @@ public PdfBoxRenderer(boolean testMode) { public PdfBoxRenderer(float dotsPerPoint, int dotsPerPixel, boolean useSubsets, boolean testMode, HttpStreamFactory factory, FSUriResolver _resolver, FSCache _cache, SVGDrawer svgImpl) { _pdfDoc = new PDDocument(); - + _svgImpl = svgImpl; _dotsPerPoint = dotsPerPoint; _testMode = testMode; _outputDevice = new PdfBoxOutputDevice(dotsPerPoint, testMode); @@ -255,6 +256,10 @@ public void setDocument(Document doc, String url, NamespaceHandler nsh) { _sharedContext.setNamespaceHandler(nsh); _sharedContext.getCss().setDocumentContext(_sharedContext, _sharedContext.getNamespaceHandler(), doc, new NullUserInterface()); getFontResolver().importFontFaces(_sharedContext.getCss().getFontFaceRules()); + + if (_svgImpl != null) { + _svgImpl.importFontFaceRules(_sharedContext.getCss().getFontFaceRules()); + } } public PDEncryption getPDFEncryption() { diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSVGReplacedElement.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSVGReplacedElement.java index 56967b4ad..95c84a9d5 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSVGReplacedElement.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSVGReplacedElement.java @@ -68,7 +68,7 @@ public int getBaseline() { @Override public void paint(RenderingContext c, PdfBoxOutputDevice outputDevice, BlockBox box) { - svg.drawSVG(e, outputDevice, null, point.getX(), point.getY()); + svg.drawSVG(e, outputDevice, c, point.getX(), point.getY(), ((PdfBoxOutputDevice) outputDevice).getSharedContext()); } } diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGDrawer.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGDrawer.java index fae511e0b..762298a96 100644 --- a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGDrawer.java +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/BatikSVGDrawer.java @@ -1,5 +1,7 @@ package com.openhtmltopdf.svgsupport; +import java.util.List; + import org.apache.batik.anim.dom.SVGDOMImplementation; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscoderInput; @@ -8,8 +10,10 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; +import com.openhtmltopdf.css.sheet.FontFaceRule; import com.openhtmltopdf.extend.OutputDevice; import com.openhtmltopdf.extend.SVGDrawer; +import com.openhtmltopdf.layout.SharedContext; import com.openhtmltopdf.render.RenderingContext; import com.openhtmltopdf.util.XRLog; @@ -17,11 +21,18 @@ public class BatikSVGDrawer implements SVGDrawer { private static final String DEFAULT_VP_WIDTH = "400"; private static final String DEFAULT_VP_HEIGHT = "400"; + private List rules; @Override - public void drawSVG(Element svgElement, OutputDevice outputDevice, RenderingContext ctx, double x, double y) { - PDFTranscoder transcoder = new PDFTranscoder(outputDevice, ctx, x, y); - + public void importFontFaceRules(List fontFaces) { + this.rules = fontFaces; + } + + @Override + public void drawSVG(Element svgElement, OutputDevice outputDevice, RenderingContext ctx, double x, double y, SharedContext shared) { + PDFTranscoder transcoder = new PDFTranscoder(outputDevice, ctx, x, y, shared); + transcoder.fontResolver.importFontFaces(rules); + try { DOMImplementation impl = SVGDOMImplementation.getDOMImplementation(); Document newDocument = impl.createDocument(SVGDOMImplementation.SVG_NAMESPACE_URI, "svg", null); diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlGvtFont.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlGvtFont.java new file mode 100644 index 000000000..f7b205b11 --- /dev/null +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlGvtFont.java @@ -0,0 +1,174 @@ +package com.openhtmltopdf.svgsupport; + +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.font.FontRenderContext; +import java.awt.font.TextAttribute; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.text.CharacterIterator; + +import org.apache.batik.gvt.font.GVTFont; +import org.apache.batik.gvt.font.GVTFontFamily; +import org.apache.batik.gvt.font.GVTGlyphVector; +import org.apache.batik.gvt.font.GVTLineMetrics; + +/** + * An adapter around awt.Font to GVTFont. + * Code from: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/fop-core/src/main/java/org/apache/fop/svg/font/FOPGVTFont.java + * + */ +public class OpenHtmlGvtFont implements GVTFont { + + private final Font baseFont; + private final GVTFontFamily fontFamily; + private final float size; + + private static int toFontWeight(Float weight) { + if (weight == null) { + return Font.PLAIN; + } + else if (weight <= TextAttribute.WEIGHT_BOLD) { + return Font.PLAIN; + } + else { + return Font.BOLD; + } + } + + private static int toStyle(Float posture) { + return ((posture != null) && (posture.floatValue() > 0.0)) + ? Font.ITALIC + : Font.PLAIN; + } + + + public OpenHtmlGvtFont(byte[] fontBytes, GVTFontFamily family, float size, Float fontWeight, Float fontStyle) throws FontFormatException { + Font font; + + try { + font = Font.createFont(Font.TRUETYPE_FONT, new ByteArrayInputStream(fontBytes)).deriveFont(toFontWeight(fontWeight) | toStyle(fontStyle) , size); + } catch (IOException e) { + // Shouldn't happen + e.printStackTrace(); + font = null; + } + + this.baseFont = font; + this.fontFamily = family; + this.size = size; + } + + private OpenHtmlGvtFont(Font font, GVTFontFamily family, float size) { + this.baseFont = font; + this.fontFamily = family; + this.size = size; + } + + @Override + public boolean canDisplay(char c) { + return this.baseFont.canDisplay(c); + } + + @Override + public int canDisplayUpTo(String str) { + for (int i = 0; i < str.length(); i++) { + if (!this.baseFont.canDisplay(str.charAt(i))) + return i; + } + + return -1; + } + + @Override + public int canDisplayUpTo(char[] str, int start, int limit) { + for (int i = start; i < limit; i++) { + if (!this.baseFont.canDisplay(str[i])) + return i; + } + + return -1; + } + + @Override + public int canDisplayUpTo(CharacterIterator iter, int start, int limit) { + for (char c = iter.setIndex(start); iter.getIndex() < limit; c = iter.next()) { + if (!canDisplay(c)) { + return iter.getIndex(); + } + } + + return -1; + } + + @Override + public GVTGlyphVector createGlyphVector(FontRenderContext frc, char[] arg1) { + return createGlyphVector(frc, new String(arg1)); + } + + @Override + public GVTGlyphVector createGlyphVector(FontRenderContext frc, + CharacterIterator arg1) { + return new OpenHtmlGvtGlyphVector(this.baseFont.createGlyphVector(frc, arg1), this, frc); + } + + @Override + public GVTGlyphVector createGlyphVector(FontRenderContext frc, String arg1) { + return new OpenHtmlGvtGlyphVector(this.baseFont.createGlyphVector(frc, arg1), this, frc); + } + + @Override + public GVTGlyphVector createGlyphVector(FontRenderContext frc, int[] arg1, + CharacterIterator arg2) { + throw new UnsupportedOperationException(); + } + + @Override + public GVTFont deriveFont(float arg0) { + Font newFont = this.baseFont.deriveFont(arg0); + return new OpenHtmlGvtFont(newFont, this.fontFamily, arg0); + } + + @Override + public String getFamilyName() { + return this.fontFamily.getFamilyName(); + } + + @Override + public float getHKern(int arg0, int arg1) { + return 0; + } + + @Override + public GVTLineMetrics getLineMetrics(String arg0, FontRenderContext arg1) { + return new GVTLineMetrics(this.baseFont.getLineMetrics(arg0, arg1)); + } + + @Override + public GVTLineMetrics getLineMetrics(char[] arg0, int arg1, int arg2, + FontRenderContext arg3) { + return new GVTLineMetrics(this.baseFont.getLineMetrics(arg0, arg1, arg2, arg3)); + } + + @Override + public GVTLineMetrics getLineMetrics(CharacterIterator arg0, int arg1, + int arg2, FontRenderContext arg3) { + return new GVTLineMetrics(this.baseFont.getLineMetrics(arg0, arg1, arg2, arg3)); + } + + @Override + public GVTLineMetrics getLineMetrics(String arg0, int arg1, int arg2, + FontRenderContext arg3) { + return new GVTLineMetrics(this.baseFont.getLineMetrics(arg0, arg1, arg2, arg3)); + } + + @Override + public float getSize() { + return this.baseFont.getSize() / 1000f; + } + + @Override + public float getVKern(int arg0, int arg1) { + return 0; + } +} diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlGvtFontFamily.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlGvtFontFamily.java new file mode 100644 index 000000000..e101c7ecb --- /dev/null +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlGvtFontFamily.java @@ -0,0 +1,106 @@ +package com.openhtmltopdf.svgsupport; + +import java.awt.FontFormatException; +import java.awt.font.TextAttribute; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.AttributedCharacterIterator; +import java.util.HashMap; +import java.util.Map; + +import org.apache.batik.gvt.font.GVTFont; +import org.apache.batik.gvt.font.GVTFontFace; +import org.apache.batik.gvt.font.GVTFontFamily; + +import com.openhtmltopdf.util.XRLog; + +public class OpenHtmlGvtFontFamily implements GVTFontFamily { + + private static class FontDescriptor { + Float size; + Float style; + Float weight; + + private boolean eq(Object obj1, Object obj2) + { + if (obj1 == null && obj2 == null) + return true; + else if (obj1 == null) + return false; + else + return obj1.equals(obj2); + + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof FontDescriptor && + eq(((FontDescriptor) obj).style, this.style) && + eq(((FontDescriptor) obj).weight, this.weight) && + eq(((FontDescriptor) obj).size, this.size)); + } + + @Override + public int hashCode() { + return (size == null ? 0 : size.hashCode()) + (style == null ? 0 : style.hashCode()) + (weight == null ? 0 : weight.hashCode()); + + } + } + + private final Map fonts = new HashMap(1); + private final String fontFamily; + + public OpenHtmlGvtFontFamily(String family) { + this.fontFamily = family; + } + + public void addFont(byte[] bytes, float size, Float fontWeight, Float fontStyle) throws FontFormatException { + FontDescriptor des = new FontDescriptor(); + des.size = size; + des.style = fontStyle; + des.weight = fontWeight; + + fonts.put(des, new OpenHtmlGvtFont(bytes, this, size, fontWeight, fontStyle)); + } + + @Override + public GVTFont deriveFont(float sz, AttributedCharacterIterator arg1) { + return deriveFont(sz, arg1.getAttributes()); + } + + @Override + public GVTFont deriveFont(float size, @SuppressWarnings("rawtypes") Map attrs) { + Float fontWeight = (Float) attrs.get(TextAttribute.WEIGHT); + Float fontStyle = (Float) attrs.get(TextAttribute.POSTURE); + Float sz = size; + + FontDescriptor des = new FontDescriptor(); + des.weight = fontWeight; + des.style = fontStyle; + des.size = sz; + + if (fonts.containsKey(des)) { + return fonts.get(des); + } + + return fonts.values().iterator().next().deriveFont(sz); + } + + @Override + public String getFamilyName() { + return this.fontFamily; + } + + @Override + public GVTFontFace getFontFace() { + return new GVTFontFace(this.fontFamily); + } + + @Override + public boolean isComplex() { + return false; + } + +} diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlGvtGlyphVector.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlGvtGlyphVector.java new file mode 100644 index 000000000..e157d6db3 --- /dev/null +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlGvtGlyphVector.java @@ -0,0 +1,169 @@ +package com.openhtmltopdf.svgsupport; + +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphJustificationInfo; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.text.AttributedCharacterIterator; + +import org.apache.batik.gvt.font.GVTFont; +import org.apache.batik.gvt.font.GVTGlyphMetrics; +import org.apache.batik.gvt.font.GVTGlyphVector; + +public class OpenHtmlGvtGlyphVector implements GVTGlyphVector { + + private final java.awt.font.GlyphVector vec; + private final GVTFont font; + private final FontRenderContext frc; + + public OpenHtmlGvtGlyphVector(java.awt.font.GlyphVector vec, GVTFont font, FontRenderContext frc) { + this.vec = vec; + this.font = font; + this.frc = frc; + } + + @Override + public void draw(Graphics2D g2d, AttributedCharacterIterator arg1) { + g2d.fill(this.vec.getOutline()); + } + + @Override + public Rectangle2D getBounds2D(AttributedCharacterIterator arg0) { + return this.getOutline().getBounds2D(); + } + + @Override + public int getCharacterCount(int start, int end) { + return end - start + 1; + } + + @Override + public GVTFont getFont() { + return this.font; + } + + @Override + public FontRenderContext getFontRenderContext() { + return this.frc; + } + + @Override + public Rectangle2D getGeometricBounds() { + return this.vec.getVisualBounds(); + } + + @Override + public Rectangle2D getGlyphCellBounds(int arg0) { + throw new UnsupportedOperationException(); + } + + @Override + public int getGlyphCode(int idx) { + return this.vec.getGlyphCode(idx); + } + + @Override + public int[] getGlyphCodes(int arg0, int arg1, int[] arg2) { + return this.vec.getGlyphCodes(arg0, arg1, arg2); + } + + @Override + public GlyphJustificationInfo getGlyphJustificationInfo(int idx) { + return this.vec.getGlyphJustificationInfo(idx); + } + + @Override + public Shape getGlyphLogicalBounds(int arg0) { + return this.vec.getGlyphLogicalBounds(arg0); + } + + @Override + public GVTGlyphMetrics getGlyphMetrics(int arg0) { + return new GVTGlyphMetrics(this.vec.getGlyphMetrics(arg0), 100000); + } + + @Override + public Shape getGlyphOutline(int arg0) { + return this.vec.getGlyphOutline(arg0); + } + + @Override + public Point2D getGlyphPosition(int arg0) { + return this.vec.getGlyphPosition(arg0); + } + + @Override + public float[] getGlyphPositions(int arg0, int arg1, float[] arg2) { + return this.vec.getGlyphPositions(arg0, arg1, arg2); + } + + @Override + public AffineTransform getGlyphTransform(int arg0) { + return this.vec.getGlyphTransform(arg0); + } + + @Override + public Shape getGlyphVisualBounds(int arg0) { + return this.vec.getGlyphVisualBounds(arg0); + } + + @Override + public Rectangle2D getLogicalBounds() { + return this.vec.getLogicalBounds(); + } + + @Override + public int getNumGlyphs() { + return this.vec.getNumGlyphs(); + } + + @Override + public Shape getOutline() { + return this.vec.getOutline(); + } + + @Override + public Shape getOutline(float arg0, float arg1) { + return this.vec.getOutline(arg0, arg1); + } + + @Override + public boolean isGlyphVisible(int arg0) { + return true; + } + + @Override + public boolean isReversed() { + return false; + } + + @Override + public void maybeReverse(boolean arg0) { + } + + @Override + public void performDefaultLayout() { + this.vec.performDefaultLayout(); + } + + @Override + public void setGlyphPosition(int arg0, Point2D arg1) { + if (arg0 == this.getNumGlyphs()) + return; + + this.vec.setGlyphPosition(arg0, arg1); + } + + @Override + public void setGlyphTransform(int arg0, AffineTransform arg1) { + this.vec.setGlyphTransform(arg0, arg1); + } + + @Override + public void setGlyphVisible(int arg0, boolean arg1) { + } + +} diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlUserAgent.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlUserAgent.java new file mode 100644 index 000000000..38b99d93e --- /dev/null +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/OpenHtmlUserAgent.java @@ -0,0 +1,260 @@ +package com.openhtmltopdf.svgsupport; + +import java.awt.Cursor; +import java.awt.Point; +import java.awt.geom.AffineTransform; +import java.awt.geom.Dimension2D; + +import org.apache.batik.bridge.BridgeExtension; +import org.apache.batik.bridge.ExternalResourceSecurity; +import org.apache.batik.bridge.FontFamilyResolver; +import org.apache.batik.bridge.Mark; +import org.apache.batik.bridge.ScriptSecurity; +import org.apache.batik.bridge.UserAgent; +import org.apache.batik.gvt.event.EventDispatcher; +import org.apache.batik.util.ParsedURL; +import org.w3c.dom.Element; +import org.w3c.dom.svg.SVGAElement; +import org.w3c.dom.svg.SVGDocument; + +import com.openhtmltopdf.svgsupport.PDFTranscoder.OpenHtmlFontResolver; + +public class OpenHtmlUserAgent implements UserAgent { + + private final OpenHtmlFontResolver resolver; + + public OpenHtmlUserAgent(OpenHtmlFontResolver resolver) { + this.resolver = resolver; + } + + @Override + public boolean supportExtension(String arg0) { + // TODO Auto-generated method stub + return false; + } + + @Override + public String showPrompt(String arg0, String arg1) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String showPrompt(String arg0) { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean showConfirm(String arg0) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void showAlert(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void setTransform(AffineTransform arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void setTextSelection(Mark arg0, Mark arg1) { + // TODO Auto-generated method stub + + } + + @Override + public void setSVGCursor(Cursor arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void registerExtension(BridgeExtension arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void openLink(SVGAElement arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void loadDocument(String arg0) { + System.err.println("LOAD DOC: " + arg0); + + } + + @Override + public boolean isXMLParserValidating() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean hasFeature(String arg0) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void handleElement(Element arg0, Object arg1) { + // TODO Auto-generated method stub + + } + + @Override + public String getXMLParserClassName() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Dimension2D getViewportSize() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getUserStyleSheetURI() { + // TODO Auto-generated method stub + return null; + } + + @Override + public AffineTransform getTransform() { + // TODO Auto-generated method stub + return null; + } + + @Override + public ScriptSecurity getScriptSecurity(String arg0, ParsedURL arg1, + ParsedURL arg2) { + // TODO Auto-generated method stub + return null; + } + + @Override + public float getPixelUnitToMillimeter() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public float getPixelToMM() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public float getMediumFontSize() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public String getMedia() { + return "print"; + } + + @Override + public float getLighterFontWeight(float arg0) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public String getLanguages() { + // TODO Auto-generated method stub + return null; + } + + @Override + public FontFamilyResolver getFontFamilyResolver() { + return this.resolver; + } + + @Override + public ExternalResourceSecurity getExternalResourceSecurity(ParsedURL arg0, + ParsedURL arg1) { + // TODO Auto-generated method stub + return null; + } + + @Override + public EventDispatcher getEventDispatcher() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getDefaultFontFamily() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Point getClientAreaLocationOnScreen() { + // TODO Auto-generated method stub + return null; + } + + @Override + public SVGDocument getBrokenLinkDocument(Element arg0, String arg1, + String arg2) { + // TODO Auto-generated method stub + return null; + } + + @Override + public float getBolderFontWeight(float arg0) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public String getAlternateStyleSheet() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void displayMessage(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void displayError(Exception arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void deselectAll() { + // TODO Auto-generated method stub + + } + + @Override + public void checkLoadScript(String arg0, ParsedURL arg1, ParsedURL arg2) + throws SecurityException { + // TODO Auto-generated method stub + + } + + @Override + public void checkLoadExternalResource(ParsedURL arg0, ParsedURL arg1) + throws SecurityException { + // TODO Auto-generated method stub + + } +} diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFGraphics2DOutputDeviceAdapter.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFGraphics2DOutputDeviceAdapter.java index d3aeb635a..a0020020a 100644 --- a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFGraphics2DOutputDeviceAdapter.java +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFGraphics2DOutputDeviceAdapter.java @@ -170,13 +170,13 @@ public void drawRenderableImage(RenderableImage img, AffineTransform xform) { @Override public void drawString(String str, float x, float y) { - System.out.println("DRAW STRING"); + this.od.setColor(new FSRGBColor(128, 128, 128)); + this.od.drawText(this.ctx, str, x, y); } @Override public void drawString(AttributedCharacterIterator iterator, float x, float y) { - System.out.println("DRAW STRING"); - +System.out.println("DRAWING STRING"); } @Override diff --git a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFTranscoder.java b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFTranscoder.java index b85598607..2361edb63 100644 --- a/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFTranscoder.java +++ b/openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFTranscoder.java @@ -1,49 +1,187 @@ package com.openhtmltopdf.svgsupport; -import java.awt.Cursor; -import java.awt.Point; -import java.awt.geom.AffineTransform; +import java.awt.FontFormatException; +import java.awt.font.TextAttribute; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; -import org.apache.batik.bridge.BridgeExtension; +import org.apache.batik.bridge.FontFace; import org.apache.batik.bridge.FontFamilyResolver; -import org.apache.batik.bridge.Mark; -import org.apache.batik.bridge.ScriptSecurity; -import org.apache.batik.bridge.UserAgent; +import org.apache.batik.gvt.font.GVTFontFamily; import org.apache.batik.transcoder.ErrorHandler; import org.apache.batik.transcoder.SVGAbstractTranscoder; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscoderOutput; -import org.apache.batik.transcoder.TranscodingHints; -import org.apache.batik.util.ParsedURL; import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.svg.SVGAElement; -import org.w3c.dom.svg.SVGDocument; +import com.openhtmltopdf.css.constants.CSSName; +import com.openhtmltopdf.css.constants.IdentValue; +import com.openhtmltopdf.css.sheet.FontFaceRule; +import com.openhtmltopdf.css.style.CalculatedStyle; +import com.openhtmltopdf.css.style.FSDerivedValue; import com.openhtmltopdf.extend.OutputDevice; +import com.openhtmltopdf.layout.SharedContext; import com.openhtmltopdf.render.RenderingContext; import com.openhtmltopdf.util.XRLog; public class PDFTranscoder extends SVGAbstractTranscoder { private final PDFGraphics2DOutputDeviceAdapter od; + public final OpenHtmlFontResolver fontResolver; - public PDFTranscoder(OutputDevice od, RenderingContext ctx, double x, double y) { + public PDFTranscoder(OutputDevice od, RenderingContext ctx, double x, double y, SharedContext shared) { this.od = new PDFGraphics2DOutputDeviceAdapter(ctx, od, x, y); + this.fontResolver = new OpenHtmlFontResolver(shared); } + public static class OpenHtmlFontResolver implements FontFamilyResolver { + private final Map families = new HashMap(4); + private final SharedContext ctx; + + public OpenHtmlFontResolver(SharedContext ctx) { + this.ctx = ctx; + } + + @Override + public GVTFontFamily resolve(String arg0, FontFace arg1) { + return null; + } + + @Override + public GVTFontFamily resolve(String family) { + if (families.containsKey(family)) + return families.get(family); + + return null; + } + + @Override + public GVTFontFamily loadFont(InputStream arg0, FontFace arg1) + throws Exception { + return null; + } + + @Override + public GVTFontFamily getFamilyThatCanDisplay(char arg0) { + return null; + } + + @Override + public GVTFontFamily getDefault() { + return null; + } + + private Float getStyle(IdentValue fontStyle) { + + if (fontStyle == IdentValue.ITALIC || + fontStyle == IdentValue.OBLIQUE) + return TextAttribute.POSTURE_OBLIQUE; + + return null; + } + + private Float getWeight(IdentValue weight) { + if (weight == IdentValue.NORMAL) { + return TextAttribute.WEIGHT_REGULAR; + } else if (weight == IdentValue.BOLD) { + return TextAttribute.WEIGHT_BOLD; + } else if (weight == IdentValue.FONT_WEIGHT_100) { + return TextAttribute.WEIGHT_EXTRA_LIGHT; + } else if (weight == IdentValue.FONT_WEIGHT_200) { + return TextAttribute.WEIGHT_LIGHT; + } else if (weight == IdentValue.FONT_WEIGHT_300) { + return TextAttribute.WEIGHT_LIGHT; + } else if (weight == IdentValue.FONT_WEIGHT_400) { + return TextAttribute.WEIGHT_MEDIUM; + } else if (weight == IdentValue.FONT_WEIGHT_500) { + return TextAttribute.WEIGHT_SEMIBOLD; + } else if (weight == IdentValue.FONT_WEIGHT_600) { + return TextAttribute.WEIGHT_SEMIBOLD; + } else if (weight == IdentValue.FONT_WEIGHT_700) { + return TextAttribute.WEIGHT_BOLD; + } else if (weight == IdentValue.FONT_WEIGHT_800) { + return TextAttribute.WEIGHT_EXTRABOLD; + } else if (weight == IdentValue.FONT_WEIGHT_900) { + return TextAttribute.WEIGHT_ULTRABOLD; + } else if (weight == IdentValue.LIGHTER) { + // FIXME + return TextAttribute.WEIGHT_MEDIUM; + } else if (weight == IdentValue.BOLDER) { + // FIXME + return TextAttribute.WEIGHT_MEDIUM; + } + else { + return null; + } + } + + private void addFontFaceFont( + String fontFamilyNameOverride, IdentValue fontWeightOverride, IdentValue fontStyleOverride, String uri, byte[] font1) + throws FontFormatException { + + OpenHtmlGvtFontFamily family = null; + + if (families.containsKey(fontFamilyNameOverride)) + family = families.get(fontFamilyNameOverride); + else { + family = new OpenHtmlGvtFontFamily(fontFamilyNameOverride); + families.put(fontFamilyNameOverride, family); + } + + family.addFont(font1, 1, getWeight(fontWeightOverride), getStyle(fontStyleOverride)); + } + + + public void importFontFaces(List fontFaces) { + for (FontFaceRule rule : fontFaces) { + CalculatedStyle style = rule.getCalculatedStyle(); + + FSDerivedValue src = style.valueByName(CSSName.SRC); + if (src == IdentValue.NONE) { + continue; + } + + byte[] font1 = ctx.getUac().getBinaryResource(src.asString()); + if (font1 == null) { + XRLog.exception("Could not load font " + src.asString()); + continue; + } + + String fontFamily = null; + IdentValue fontWeight = null; + IdentValue fontStyle = null; + + if (rule.hasFontFamily()) { + fontFamily = style.valueByName(CSSName.FONT_FAMILY).asString(); + } + + if (rule.hasFontWeight()) { + fontWeight = style.getIdent(CSSName.FONT_WEIGHT); + } + + if (rule.hasFontStyle()) { + fontStyle = style.getIdent(CSSName.FONT_STYLE); + } + + try { + addFontFaceFont(fontFamily, fontWeight, fontStyle, src.asString(), font1); + } catch (FontFormatException e) { + XRLog.exception("Couldn't read font", e); + continue; + } + } + } + } + @Override protected void transcode(Document svg, String uri, TranscoderOutput out) throws TranscoderException { + this.userAgent = new OpenHtmlUserAgent(this.fontResolver); super.transcode(svg, uri, out); this.root.paint(od); } - @Override - public TranscodingHints getTranscodingHints() { - // TODO Auto-generated method stub - return super.getTranscodingHints(); - } - @Override public ErrorHandler getErrorHandler() { return new ErrorHandler() {