diff options
author | Maximilian Berger <maxberger@apache.org> | 2008-05-28 16:10:32 +0000 |
---|---|---|
committer | Maximilian Berger <maxberger@apache.org> | 2008-05-28 16:10:32 +0000 |
commit | a2e6bdf461aa7686d55ebba10eb70b9f787f1fd7 (patch) | |
tree | 36b767ea4e4f6e968a5414773ef9e7a817b5dcb3 | |
parent | 3f7898c97421c9617c0b352ca8b0f23bf82d38ef (diff) | |
download | xmlgraphics-fop-a2e6bdf461aa7686d55ebba10eb70b9f787f1fd7.tar.gz xmlgraphics-fop-a2e6bdf461aa7686d55ebba10eb70b9f787f1fd7.zip |
Implemented Font auto-selection word-by-word
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@660998 13f79535-47bb-0310-9956-ffa450edef68
5 files changed, 275 insertions, 81 deletions
diff --git a/src/java/org/apache/fop/fo/FOText.java b/src/java/org/apache/fop/fo/FOText.java index 8c85bb039..f21386075 100644 --- a/src/java/org/apache/fop/fo/FOText.java +++ b/src/java/org/apache/fop/fo/FOText.java @@ -37,7 +37,7 @@ import org.apache.fop.fo.properties.SpaceProperty; /** * A text node (PCDATA) in the formatting object tree. * - * Unfortunately the BufferManager implementatation holds + * Unfortunately the BufferManager implementation holds * onto references to the character data in this object * longer than the lifetime of the object itself, causing * excessive memory consumption and OOM errors. diff --git a/src/java/org/apache/fop/fonts/FontSelector.java b/src/java/org/apache/fop/fonts/FontSelector.java new file mode 100644 index 000000000..b18e24eb9 --- /dev/null +++ b/src/java/org/apache/fop/fonts/FontSelector.java @@ -0,0 +1,142 @@ +/* + * 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. + */ + +/* $Id: FontCollection.java 654783 2008-05-09 12:30:40Z vhennebert $ */ + +package org.apache.fop.fonts; + +import org.apache.fop.datatypes.PercentBaseContext; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.FOText; +import org.apache.fop.fo.flow.Character; +import org.apache.fop.fo.properties.CommonFont; + +/** + * Helper class for automatic font selection. + * <p> + * TODO: Check if this could be merged with another font class, such as + * {@link FontManager}. + */ +public final class FontSelector { + private FontSelector() { + // Static since this is an utility class. + } + + private static Font selectFontForCharacter(char c, FONode fonode, + CommonFont commonFont, PercentBaseContext context) { + FontInfo fi = fonode.getFOEventHandler().getFontInfo(); + FontTriplet[] fontkeys = commonFont.getFontState(fi); + for (int i = 0; i < fontkeys.length; i++) { + Font font = fi.getFontInstance(fontkeys[i], commonFont.fontSize + .getValue(context)); + if (font.hasChar(c)) { + return font; + } + } + return fi.getFontInstance(fontkeys[0], commonFont.fontSize + .getValue(context)); + + } + + /** + * Selects a font which is able to display the given character. + * + * @param fobj + * a Character object containing the character and its + * attributes. + * @param context + * the Percent-based context needed for creating the actual font. + * @return a Font object. + */ + public static Font selectFontForCharacter(Character fobj, + PercentBaseContext context) { + return FontSelector.selectFontForCharacter(fobj.getCharacter(), fobj, + fobj.getCommonFont(), context); + } + + /** + * Selects a font which is able to display the given character. + * + * @param c + * character to find. + * @param text + * the text object which contains the character + * @param context + * the Percent-based context needed for creating the actual font. + * @return a Font object. + */ + public static Font selectFontForCharacterInText(char c, FOText text, + PercentBaseContext context) { + return FontSelector.selectFontForCharacter(c, text, text + .getCommonFont(), context); + } + + /** + * Selects a font which is able to display the most of the given characters. + * + * @param textArray + * Text to go through + * @param firstIndex + * first index within text. + * @param breakIndex + * last index +1 within text. + * @param text + * the text object which contains the character + * @param context + * the Percent-based context needed for creating the actual font. + * @return a Font object. + */ + public static Font selectFontForCharactersInText(char[] textArray, + int firstIndex, int breakIndex, FOText text, + PercentBaseContext context) { + final FontInfo fi = text.getFOEventHandler().getFontInfo(); + final CommonFont commonFont = text.getCommonFont(); + final FontTriplet[] fontkeys = commonFont.getFontState(fi); + final int numFonts = fontkeys.length; + final Font[] fonts = new Font[numFonts]; + final int[] fontCount = new int[numFonts]; + + for (int fontnum = 0; fontnum < numFonts; fontnum++) { + final Font font = fi.getFontInstance(fontkeys[fontnum], + commonFont.fontSize.getValue(context)); + fonts[fontnum] = font; + for (int pos = firstIndex; pos < breakIndex; pos++) { + if (font.hasChar(textArray[pos])) { + fontCount[fontnum]++; + } + } + + // quick fall through if all characters can be displayed + if (fontCount[fontnum] == (breakIndex - firstIndex)) { + return font; + } + } + + Font font = fonts[0]; + int max = fontCount[0]; + + for (int fontnum = 1; fontnum < numFonts; fontnum++) { + final int curCount = fontCount[fontnum]; + if (curCount > max) { + font = fonts[fontnum]; + max = curCount; + } + } + return font; + } + +} diff --git a/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java index b292d97bf..a6f9be7af 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java @@ -26,8 +26,7 @@ import org.apache.fop.area.Trait; import org.apache.fop.fo.flow.Character; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fonts.Font; -import org.apache.fop.fonts.FontInfo; -import org.apache.fop.fonts.FontTriplet; +import org.apache.fop.fonts.FontSelector; import org.apache.fop.layoutmgr.InlineKnuthSequence; import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthGlue; @@ -62,7 +61,7 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager { /** {@inheritDoc} */ public void initialize() { Character fobj = (Character)this.fobj; - font = this.selectFontForCharacter(fobj); + font = FontSelector.selectFontForCharacter(fobj, this); SpaceVal ls = SpaceVal.makeLetterSpacing(fobj.getLetterSpacing()); letterSpaceIPD = ls.getSpace(); hyphIPD = fobj.getCommonHyphenation().getHyphIPD(font); @@ -72,33 +71,6 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager { chArea.setBaselineOffset(font.getAscender()); setCurrentArea(chArea); } - - /** - * Selects a font which is able to display the given character. - * <p> - * Please note: this implements the font-selection-strategy - * character-by-character. - * <p> - * TODO: The same function could apply to other elements as well. - * - * @param fobj - * a Character object containing the character and its - * attributed. - * @return a Font object. - */ - private Font selectFontForCharacter(Character fobj) { - FontInfo fi = fobj.getFOEventHandler().getFontInfo(); - FontTriplet[] fontkeys = fobj.getCommonFont().getFontState(fi); - for (int i = 0; i < fontkeys.length; i++) { - font = fi.getFontInstance(fontkeys[i], - fobj.getCommonFont().fontSize.getValue(this)); - if (font.hasChar(fobj.getCharacter())) { - return font; - } - } - return fi.getFontInstance(fontkeys[0], - fobj.getCommonFont().fontSize.getValue(this)); - } private org.apache.fop.area.inline.TextArea getCharacterInlineArea(Character node) { org.apache.fop.area.inline.TextArea text diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java index be8a13d50..ffd364626 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java @@ -32,6 +32,7 @@ import org.apache.fop.fo.Constants; import org.apache.fop.fo.FOText; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontSelector; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.layoutmgr.InlineKnuthSequence; import org.apache.fop.layoutmgr.KnuthBox; @@ -70,6 +71,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { private boolean isHyphenated; private boolean isSpace; private boolean breakOppAfter; + private final Font font; AreaInfo(short startIndex, short breakIndex, @@ -78,7 +80,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager { MinOptMax areaIPD, boolean isHyphenated, boolean isSpace, - boolean breakOppAfter) { + boolean breakOppAfter, + Font font) { this.startIndex = startIndex; this.breakIndex = breakIndex; this.wordSpaceCount = wordSpaceCount; @@ -87,6 +90,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { this.isHyphenated = isHyphenated; this.isSpace = isSpace; this.breakOppAfter = breakOppAfter; + this.font = font; } public String toString() { @@ -97,6 +101,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { + ", bidx=" + breakIndex + ", hyph=" + isHyphenated + ", space=" + isSpace + + ", font=" + font + "]"; } @@ -139,7 +144,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager { private static final char NEWLINE = '\n'; - private Font font = null; + /** Font used for the space between words. */ + private Font spaceFont = null; /** Start index of next TextArea */ private short nextStart = 0; /** size of a space character (U+0020) glyph in current font */ @@ -150,10 +156,6 @@ public class TextLayoutManager extends LeafNodeLayoutManager { private int hyphIPD; /** 1/1 of word-spacing value */ private SpaceVal ws; - /** 1/2 of word-spacing value */ - private SpaceVal halfWS; - /** 1/2 of letter-spacing value */ - private SpaceVal halfLS; private boolean hasChanged = false; private int returnedIndex = 0; @@ -206,23 +208,19 @@ public class TextLayoutManager extends LeafNodeLayoutManager { /** {@inheritDoc} */ public void initialize() { - FontInfo fi = foText.getFOEventHandler().getFontInfo(); - FontTriplet[] fontkeys = foText.getCommonFont().getFontState(fi); - font = fi.getFontInstance(fontkeys[0], foText.getCommonFont().fontSize.getValue(this)); + + spaceFont = FontSelector.selectFontForCharacterInText(' ', foText, this); // With CID fonts, space isn't neccesary currentFontState.width(32) - spaceCharIPD = font.getCharWidth(' '); + spaceCharIPD = spaceFont.getCharWidth(' '); // Use hyphenationChar property - hyphIPD = foText.getCommonHyphenation().getHyphIPD(font); + + // TODO: Use hyphen based on actual font used! + hyphIPD = foText.getCommonHyphenation().getHyphIPD(spaceFont); SpaceVal ls = SpaceVal.makeLetterSpacing(foText.getLetterSpacing()); - halfLS = new SpaceVal(MinOptMax.multiply(ls.getSpace(), 0.5), - ls.isConditional(), ls.isForcing(), ls.getPrecedence()); - ws = SpaceVal.makeWordSpacing(foText.getWordSpacing(), ls, font); - // Make half-space: <space> on either side of a word-space) - halfWS = new SpaceVal(MinOptMax.multiply(ws.getSpace(), 0.5), - ws.isConditional(), ws.isForcing(), ws.getPrecedence()); + ws = SpaceVal.makeWordSpacing(foText.getWordSpacing(), ls, spaceFont); // letter space applies only to consecutive non-space characters, // while word space applies to space characters; @@ -255,7 +253,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { public void addAreas(PositionIterator posIter, LayoutContext context) { // Add word areas - AreaInfo ai = null; + AreaInfo ai; int wordSpaceCount = 0; int letterSpaceCount = 0; int firstAreaInfoIndex = -1; @@ -265,6 +263,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { /* On first area created, add any leading space. * Calculate word-space stretch value. */ + AreaInfo lastAi = null; while (posIter.hasNext()) { LeafPosition tbpNext = (LeafPosition) posIter.next(); if (tbpNext == null) { @@ -272,18 +271,38 @@ public class TextLayoutManager extends LeafNodeLayoutManager { } if (tbpNext.getLeafPos() != -1) { ai = (AreaInfo) vecAreaInfo.get(tbpNext.getLeafPos()); - if (firstAreaInfoIndex == -1) { + if (lastAi == null || ai.font != lastAi.font) { + if (lastAi != null) { + this.addAreaInfoAreas(lastAi, wordSpaceCount, + letterSpaceCount, firstAreaInfoIndex, + lastAreaInfoIndex, realWidth, context); + } firstAreaInfoIndex = tbpNext.getLeafPos(); - } + wordSpaceCount = 0; + letterSpaceCount = 0; + realWidth = new MinOptMax(0); + } wordSpaceCount += ai.wordSpaceCount; letterSpaceCount += ai.letterSpaceCount; realWidth.add(ai.areaIPD); lastAreaInfoIndex = tbpNext.getLeafPos(); + lastAi = ai; } } - if (ai == null) { - return; + if (lastAi != null) { + this.addAreaInfoAreas(lastAi, wordSpaceCount, letterSpaceCount, + firstAreaInfoIndex, lastAreaInfoIndex, realWidth, context); } + } + + private void addAreaInfoAreas(AreaInfo ai, int wordSpaceCount, + int letterSpaceCount, int firstAreaInfoIndex, + int lastAreaInfoIndex, MinOptMax realWidth, LayoutContext context) { + + // TODO: These two statements (if, for) where like this before my recent + // changes. However, it seems as if they should use the AreaInfo from + // firstAreaInfoIndex.. lastAreaInfoIndex rather than just the last ai. + // This needs to be checked. int textLength = ai.breakIndex - ai.startIndex; if (ai.letterSpaceCount == textLength && !ai.isHyphenated && context.isLastArea()) { @@ -353,9 +372,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager { } TextArea t = createTextArea(realWidth, totalAdjust, context, - wordSpaceIPD.opt - spaceCharIPD, - firstAreaInfoIndex, lastAreaInfoIndex, - context.isLastArea()); + wordSpaceIPD.opt - spaceCharIPD, firstAreaInfoIndex, + lastAreaInfoIndex, context.isLastArea(), ai.font); // wordSpaceDim is computed in relation to wordSpaceIPD.opt // but the renderer needs to know the adjustment in relation @@ -391,11 +409,12 @@ public class TextLayoutManager extends LeafNodeLayoutManager { * @param firstIndex the index of the first AreaInfo used for the TextArea * @param lastIndex the index of the last AreaInfo used for the TextArea * @param isLastArea is this TextArea the last in a line? + * @param font Font to be used in this particular TextArea * @return the new text area */ protected TextArea createTextArea(MinOptMax width, int adjust, - LayoutContext context, int spaceDiff, - int firstIndex, int lastIndex, boolean isLastArea) { + LayoutContext context, int spaceDiff, int firstIndex, + int lastIndex, boolean isLastArea, Font font) { TextArea textArea; if (context.getIPDAdjust() == 0.0) { // create just a TextArea @@ -409,6 +428,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { } textArea.setIPD(width.opt + adjust); textArea.setBPD(font.getAscender() - font.getDescender()); + textArea.setBaselineOffset(font.getAscender()); if (textArea.getBPD() == alignmentContext.getHeight()) { textArea.setOffset(0); @@ -548,6 +568,9 @@ public class TextLayoutManager extends LeafNodeLayoutManager { while (lastIndex > 0 && textArray[lastIndex - 1] == CharUtilities.SOFT_HYPHEN) { lastIndex--; } + final Font font = FontSelector + .selectFontForCharactersInText(textArray, + thisStart, lastIndex, foText, this); int wordLength = lastIndex - thisStart; boolean kerning = font.hasKerning(); MinOptMax wordIPD = new MinOptMax(0); @@ -592,8 +615,9 @@ public class TextLayoutManager extends LeafNodeLayoutManager { // create the AreaInfo object ai = new AreaInfo(thisStart, lastIndex, (short) 0, - (short) iLetterSpaces, - wordIPD, textArray[lastIndex] == CharUtilities.SOFT_HYPHEN, false, breakOpportunity); + (short) iLetterSpaces, wordIPD, + textArray[lastIndex] == CharUtilities.SOFT_HYPHEN, + false, breakOpportunity, font); prevAi = ai; vecAreaInfo.add(ai); tempStart = nextStart; @@ -610,8 +634,9 @@ public class TextLayoutManager extends LeafNodeLayoutManager { // create the AreaInfo object ai = new AreaInfo(thisStart, nextStart, (short) (nextStart - thisStart), (short) 0, - MinOptMax.multiply(wordSpaceIPD, nextStart - thisStart), - false, true, breakOpportunity); + MinOptMax.multiply(wordSpaceIPD, nextStart + - thisStart), false, true, + breakOpportunity, spaceFont); vecAreaInfo.add(ai); prevAi = ai; @@ -647,15 +672,17 @@ public class TextLayoutManager extends LeafNodeLayoutManager { // preserved space or non-breaking space: // create the AreaInfo object ai = new AreaInfo(nextStart, (short) (nextStart + 1), - (short) 1, (short) 0, - wordSpaceIPD, false, true, breakOpportunity); + (short) 1, (short) 0, wordSpaceIPD, false, true, + breakOpportunity, spaceFont); thisStart = (short) (nextStart + 1); } else if (CharUtilities.isFixedWidthSpace(ch) || CharUtilities.isZeroWidthSpace(ch)) { // create the AreaInfo object + final Font font = FontSelector.selectFontForCharacterInText(ch, + foText, this); MinOptMax ipd = new MinOptMax(font.getCharWidth(ch)); ai = new AreaInfo(nextStart, (short) (nextStart + 1), - (short) 0, (short) 0, - ipd, false, true, breakOpportunity); + (short) 0, (short) 0, ipd, false, true, + breakOpportunity, font); thisStart = (short) (nextStart + 1); } else if (ch == NEWLINE) { // linefeed; this can happen when linefeed-treatment="preserve" @@ -673,6 +700,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager { lastIndex--; } int wordLength = lastIndex - thisStart; + final Font font = FontSelector.selectFontForCharactersInText( + textArray, thisStart, lastIndex, foText, this); boolean kerning = font.hasKerning(); MinOptMax wordIPD = new MinOptMax(0); for (int i = thisStart; i < lastIndex; i++) { @@ -703,9 +732,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager { wordIPD.add(MinOptMax.multiply(letterSpaceIPD, iLetterSpaces)); // create the AreaInfo object - ai = new AreaInfo(thisStart, (short)lastIndex, (short) 0, - (short) iLetterSpaces, - wordIPD, false, false, false); + ai = new AreaInfo(thisStart, (short) lastIndex, (short) 0, + (short) iLetterSpaces, wordIPD, false, false, false, font); vecAreaInfo.add(ai); tempStart = nextStart; @@ -715,9 +743,9 @@ public class TextLayoutManager extends LeafNodeLayoutManager { ai = null; } else if (inWhitespace) { ai = new AreaInfo(thisStart, (short) (nextStart), - (short) (nextStart - thisStart), (short) 0, - MinOptMax.multiply(wordSpaceIPD, nextStart - thisStart), - false, true, true); + (short) (nextStart - thisStart), (short) 0, MinOptMax + .multiply(wordSpaceIPD, nextStart - thisStart), + false, true, true, spaceFont); vecAreaInfo.add(ai); // create the elements @@ -828,6 +856,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { int startIndex = ai.startIndex; int stopIndex; boolean nothingChanged = true; + final Font font = ai.font; while (startIndex < ai.breakIndex) { MinOptMax newIPD = new MinOptMax(0); @@ -881,15 +910,12 @@ public class TextLayoutManager extends LeafNodeLayoutManager { if (changeList == null) { changeList = new LinkedList(); } - changeList.add - (new PendingChange - (new AreaInfo((short) startIndex, (short) stopIndex, - (short) 0, - (short) (isWordEnd - ? (stopIndex - startIndex - 1) - : (stopIndex - startIndex)), - newIPD, hyphenFollows, false, false), - ((LeafPosition) pos).getLeafPos())); + changeList.add(new PendingChange(new AreaInfo( + (short) startIndex, (short) stopIndex, (short) 0, + (short) (isWordEnd ? (stopIndex - startIndex - 1) + : (stopIndex - startIndex)), newIPD, + hyphenFollows, false, false, font), + ((LeafPosition) pos).getLeafPos())); nothingChanged = false; } startIndex = stopIndex; diff --git a/test/layoutengine/standard-testcases/block_font-autoselect.xml b/test/layoutengine/standard-testcases/block_font-autoselect.xml new file mode 100644 index 000000000..420ab84ae --- /dev/null +++ b/test/layoutengine/standard-testcases/block_font-autoselect.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<!-- $Id: block_font-family.xml 627324 2008-02-13 09:35:01Z maxberger $ --> +<testcase> + <info> + <p> + This test checks the font auto selection. + </p> + </info> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg"> + <fo:layout-master-set> + <fo:simple-page-master master-name="normal" page-width="210mm" page-height="297mm"> + <fo:region-body/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="normal" white-space-collapse="true"> + <fo:flow flow-name="xsl-region-body"> + <fo:block>font-family not given</fo:block> + <fo:block>this text contains a ∑ symbol in the middle</fo:block> + <fo:block>mixed contents should be</fo:block> + <fo:block>∑∑text</fo:block> + <fo:block>∑∑∑∑text</fo:block> + <fo:block>∑∑∑∑sym</fo:block> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <checks> + <eval expected="sans-serif" xpath="//flow/block[1]/lineArea/text/@font-name"/> + <eval expected="sans-serif" xpath="//flow/block[2]/lineArea/text[1]/@font-name"/> + <eval expected="Symbol" xpath="//flow/block[2]/lineArea/text[2]/@font-name"/> + <eval expected="sans-serif" xpath="//flow/block[2]/lineArea/text[3]/@font-name"/> + <eval expected="sans-serif" xpath="//flow/block[3]/lineArea/text[1]/@font-name"/> + <eval expected="sans-serif" xpath="//flow/block[4]/lineArea/text[1]/@font-name"/> + <eval expected="sans-serif" xpath="//flow/block[5]/lineArea/text[1]/@font-name"/> + <eval expected="Symbol" xpath="//flow/block[6]/lineArea/text[1]/@font-name"/> + </checks> +</testcase> |