Skip to content

Commit

Permalink
FOP-3135: SVG tspan content is displayed out of place by João André G…
Browse files Browse the repository at this point in the history
…onçalves
  • Loading branch information
simonsteiner1984 committed Jul 15, 2024
1 parent c04cbfb commit ef173cf
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 27 deletions.
4 changes: 4 additions & 0 deletions fop-core/src/main/java/org/apache/fop/apps/FOUserAgent.java
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ public float getTargetResolution() {
return FOUserAgent.this.getTargetResolution();
}

public float getSourceResolution() {
return FOUserAgent.this.getSourceResolution();
}

public Source resolveURI(String uri) {
return FOUserAgent.this.resolveURI(uri);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.gvt.GraphicsNode;

import org.apache.xmlgraphics.image.GraphicsConstants;
import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageException;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
Expand Down Expand Up @@ -74,13 +73,7 @@ public Image convert(final Image src, Map hints) throws ImageException {
+ svg.getRootNamespace());
}

//Prepare
float pxToMillimeter = UnitConv.IN2MM / GraphicsConstants.DEFAULT_DPI;
Number ptm = (Number)hints.get(ImageProcessingHints.SOURCE_RESOLUTION);
if (ptm != null) {
pxToMillimeter = (float)(UnitConv.IN2MM / ptm.doubleValue());
}
UserAgent ua = createBatikUserAgent(pxToMillimeter);
UserAgent ua = createBatikUserAgent(hints);
GVTBuilder builder = new GVTBuilder();

final ImageManager imageManager = (ImageManager)hints.get(
Expand Down Expand Up @@ -118,14 +111,23 @@ public Image convert(final Image src, Map hints) throws ImageException {
return g2dImage;
}

private float getResolution(Map hints, Object key) {
Number res = (Number) hints.get(key);

if (res != null) {
return res.floatValue();
}
return UnitConv.IN2PT;
}

/**
* Creates a user agent for Batik. Override to provide your own user agent.
* @param pxToMillimeter the source resolution (in px per millimeter)
* @return the newly created user agent
*/
protected SimpleSVGUserAgent createBatikUserAgent(float pxToMillimeter) {
return new SimpleSVGUserAgent(pxToMillimeter, new AffineTransform(),
DefaultFontFamilyResolver.SINGLETON) {
protected SimpleSVGUserAgent createBatikUserAgent(Map hints) {
return new SimpleSVGUserAgent(new AffineTransform(),
DefaultFontFamilyResolver.SINGLETON,
getResolution(hints, ImageProcessingHints.SOURCE_RESOLUTION)) {
/** {@inheritDoc} */
public void displayMessage(String message) {
//TODO Refine and pipe through to caller
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,9 @@ private ImageInfo getImage(String uri, Source src,

private ImageInfo createImageInfo(String uri, ImageContext context, SVGDocument doc) {
Element e = doc.getRootElement();
float pxUnitToMillimeter = UnitConv.IN2MM / context.getSourceResolution();
UserAgent userAg = new SimpleSVGUserAgent(pxUnitToMillimeter,
new AffineTransform(), DefaultFontFamilyResolver.SINGLETON) {
UserAgent userAg = new SimpleSVGUserAgent(
new AffineTransform(), DefaultFontFamilyResolver.SINGLETON,
context.getSourceResolution()) {

/** {@inheritDoc} */
public void displayMessage(String message) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ protected ImageSessionContext getImageSessionContext() {
protected void setupImageInfrastructure(final String baseURI) {
final ImageContext imageContext = new ImageContext() {
public float getSourceResolution() {
return UnitConv.IN2MM / userAgent.getPixelUnitToMillimeter();
return userAgent.getSourceResolution();
}
};
this.imageManager = new ImageManager(imageContext);
Expand All @@ -265,6 +265,10 @@ public float getTargetResolution() {
return getDeviceResolution();
}

public float getSourceResolution() {
return getDeviceResolution();
}

public Source resolveURI(String uri) {
try {
ParsedURL url = new ParsedURL(baseURI, uri);
Expand Down Expand Up @@ -371,7 +375,7 @@ public float getPixelUnitToMillimeter() {
return (Float) getTranscodingHints().get(key);
} else {
// return 0.3528f; // 72 dpi
return UnitConv.IN2MM / 96; //96dpi = 0.2645833333333333333f;
return UnitConv.IN2MM / getSourceResolution(); //96dpi = 0.2645833333333333333f;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class SVGUserAgent extends SimpleSVGUserAgent {
* @param at the current transform
*/
public SVGUserAgent(FOUserAgent foUserAgent, FontFamilyResolver fontFamilyResolver, AffineTransform at) {
super(foUserAgent.getSourcePixelUnitToMillimeter(), at, fontFamilyResolver);
super(at, fontFamilyResolver, foUserAgent.getSourceResolution());
this.eventProducer = SVGEventProducer.Provider.get(foUserAgent.getEventBroadcaster());
}

Expand Down
19 changes: 13 additions & 6 deletions fop-core/src/main/java/org/apache/fop/svg/SimpleSVGUserAgent.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import org.apache.batik.bridge.FontFamilyResolver;
import org.apache.batik.bridge.UserAgentAdapter;

import org.apache.xmlgraphics.util.UnitConv;

/**
* A simple SVG user agent.
* This is an implementation of the Batik SVG user agent. It ignores any message output sent
Expand All @@ -40,27 +42,32 @@ public class SimpleSVGUserAgent extends UserAgentAdapter {

private AffineTransform currentTransform;

private float pixelUnitToMillimeter;

private final FontFamilyResolver fontFamilyResolver;

/**
* Creates a new user agent.
* @param pixelUnitToMM the pixel to millimeter conversion factor currently in effect
* @param at the current transform
*/
public SimpleSVGUserAgent(float pixelUnitToMM, AffineTransform at, FontFamilyResolver fontFamilyResolver) {
public SimpleSVGUserAgent(AffineTransform at, FontFamilyResolver fontFamilyResolver,
float sourceResolution) {
this.fontFamilyResolver = fontFamilyResolver;
pixelUnitToMillimeter = pixelUnitToMM;
currentTransform = at;
setSourceResolution(sourceResolution);
}

/**
* Returns a customized the pixel to mm factor.
* @return the pixel unit to millimeter conversion factor
*/
public float getPixelUnitToMillimeter() {
return pixelUnitToMillimeter;
return UnitConv.IN2MM / getSourceResolution();
}

/**
* @return medium font size adapted to the resolution
*/
public float getMediumFontSize() {
return 12f * UnitConv.IN2MM / (UnitConv.IN2PT * getPixelUnitToMillimeter());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import org.apache.batik.bridge.TextPainter;
import org.apache.batik.gvt.GraphicsNode;

import org.apache.xmlgraphics.util.UnitConv;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.fonts.FontInfo;
Expand All @@ -41,8 +43,12 @@
abstract class NativeTextPainterTest {

protected final Graphics2D runTest(String testcase, OperatorValidator validator) throws Exception {
FontInfo fontInfo = createFontInfo();
BridgeContext bridgeContext = createBridgeContext(fontInfo);
return runTest(testcase, createFontInfo(), validator, UnitConv.IN2PT);
}

protected final Graphics2D runTest(String testcase, FontInfo fontInfo, OperatorValidator validator,
int sourceRes) throws Exception {
BridgeContext bridgeContext = createBridgeContext(fontInfo, sourceRes);
GraphicsNode svg = loadSVG(bridgeContext, testcase);
Graphics2D g2d = createGraphics2D(fontInfo, validator);
svg.paint(g2d);
Expand All @@ -56,10 +62,12 @@ private FontInfo createFontInfo() {
return fontInfo;
}

private BridgeContext createBridgeContext(FontInfo fontInfo) {
private BridgeContext createBridgeContext(FontInfo fontInfo, int sourceResolution) {
FOUserAgent userAgent = FopFactory.newInstance(new File(".").toURI()).newFOUserAgent();
SVGUserAgent svgUserAgent = new SVGUserAgent(userAgent, new FOPFontFamilyResolverImpl(fontInfo),
new AffineTransform());
svgUserAgent.setSourceResolution(sourceResolution);

BridgeContext bridgeContext = new BridgeContext(svgUserAgent);
bridgeContext.setTextPainter(createTextPainter(fontInfo));
return bridgeContext;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.fop.svg;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class SimpleSVGUserAgentTestCase {

@Test
public void testMediumFontResolution72() {
checkGetMediumFontSize(72f, 12f);
}

@Test
public void testMediumFontResolution96() {
checkGetMediumFontSize(96f, 16f);
}

private void checkGetMediumFontSize(float sourceRes, float expectedSize) {
SimpleSVGUserAgent adapter = new SimpleSVGUserAgent(null, null, sourceRes);

// Size must be calculated based on the dpi settings
assertEquals(expectedSize, adapter.getMediumFontSize(), 0.01);
}
}

0 comments on commit ef173cf

Please sign in to comment.