package org.docx4j.fonts;
import static org.junit.Assert.assertEquals;
import java.io.File;
import org.docx4j.XmlUtils;
import org.docx4j.dml.Theme;
import org.docx4j.fonts.RunFontSelector.RunFontActionType;
import org.docx4j.fonts.RunFontSelector.RunFontCharacterVisitor;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.ThemePart;
import org.docx4j.openpackaging.parts.WordprocessingML.DocumentSettingsPart;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
import org.docx4j.wml.CTLanguage;
import org.docx4j.wml.CTSettings;
import org.docx4j.wml.Document;
import org.docx4j.wml.P;
import org.docx4j.wml.PPr;
import org.docx4j.wml.R;
import org.docx4j.wml.RPr;
import org.docx4j.wml.Styles;
import org.docx4j.wml.Text;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
public class RunFontSelectorRussian1Test {
protected static Logger log = LoggerFactory.getLogger(RunFontSelector.class); // same logger
static String[] expectedFont = { "Verdana"};
@Test
public void testFont() throws Exception {
boolean save = false;
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
MainDocumentPart mdp = wordMLPackage.getMainDocumentPart();
// Styles part
StyleDefinitionsPart sdp = mdp.getStyleDefinitionsPart();
Styles styles = (Styles)XmlUtils.unmarshalString(stylesXML);
sdp.setJaxbElement(styles);
// Theme part
ThemePart themePart = new ThemePart();
Theme theme = (Theme)XmlUtils.unmarshalString(themeXML);
themePart.setJaxbElement(theme);
mdp.addTargetPart(themePart);
// Settings
DocumentSettingsPart dsp = new DocumentSettingsPart();
dsp.setJaxbElement(createSettings());
mdp.addTargetPart(dsp);
Document document = (Document)XmlUtils.unmarshalString(documentXML);
wordMLPackage.getMainDocumentPart().setJaxbElement(document);
if (save) {
wordMLPackage.save(new File(System.getProperty("user.dir") + "/OUT_RunFontSelectorTests.docx"));
}
RunFontSelector rfs = createRunFontSelector(wordMLPackage);
// For each w:p, test w:r/w:t
for (int i=0; i<document.getContent().size(); i++) {
P p = (P)document.getContent().get(i);
PPr pPr = p.getPPr();
RPr rPr = ((R)p.getContent().get(0)).getRPr();
Text wmlText = (Text)XmlUtils.unwrap(((R)p.getContent().get(0)).getContent().get(0));
log.debug(wmlText.getValue());
Object result = rfs.fontSelector(pPr, rPr, wmlText);
// System.out.println(result.getClass().getName());
DocumentFragment df = (DocumentFragment)result;
log.debug(XmlUtils.w3CDomNodeToString(df));
Element foInline = (Element)df.getFirstChild();
// System.out.println(foInline.getAttribute("font-family"));
assertEquals(foInline.getAttribute("font-family"), expectedFont[i]);
}
}
String documentXML ="<w:document mc:Ignorable=\"w14 wp14\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:xml=\"http://www.w3.org/XML/1998/namespace\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"
+ "<w:body>"
+ "<w:p>"
+ "<w:r>"
+ "<w:rPr>"
+ "<w:rFonts w:ascii=\"Verdana\" w:hAnsi=\"Verdana\"/>"
+ "<w:b/>"
+ "<w:bCs/>"
+ "<w:color w:val=\"000000\"/>"
+ "<w:sz w:val=\"21\"/>"
+ "<w:szCs w:val=\"21\"/>"
+ "<w:lang w:eastAsia=\"ru-RU\"/>"
+"</w:rPr>"
+ "<w:t>Частичное</w:t>"
+"</w:r>"
+"</w:p>"
+"</w:body>"
+"</w:document>";
public CTSettings createSettings() {
org.docx4j.wml.ObjectFactory wmlObjectFactory = new org.docx4j.wml.ObjectFactory();
CTSettings settings = wmlObjectFactory.createCTSettings();
// JAXBElement<org.docx4j.wml.CTSettings> settingsWrapped = wmlObjectFactory.createSettings(settings);
// Create object for themeFontLang
CTLanguage language = wmlObjectFactory.createCTLanguage();
settings.setThemeFontLang(language);
language.setVal( "ru-RU");
language.setEastAsia( "ko-KR");
return settings;
}
static String stylesXML = "<w:styles mc:Ignorable=\"w14\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\">"
+ "<w:docDefaults>"
+ "<w:rPrDefault>"
+ "<w:rPr>"
+ "<w:rFonts w:ascii=\"Calibri\" w:cs=\"Times New Roman\" w:eastAsia=\"Calibri\" w:hAnsi=\"Calibri\"/>"
+ "<w:lang w:bidi=\"ar-SA\" w:eastAsia=\"ko-KR\" w:val=\"en-US\"/>"
+"</w:rPr>"
+"</w:rPrDefault>"
+ "<w:pPrDefault/>"
+"</w:docDefaults>"
+ "<w:style w:default=\"1\" w:styleId=\"Normal\" w:type=\"paragraph\">"
+ "<w:name w:val=\"Normal\"/>"
+ "<w:rsid w:val=\"00117BB2\"/>"
+ "<w:pPr>"
+ "<w:widowControl w:val=\"0\"/>"
+ "<w:jc w:val=\"both\"/>"
+"</w:pPr>"
+ "<w:rPr>"
+ "<w:sz w:val=\"22\"/>"
+ "<w:szCs w:val=\"22\"/>"
+ "<w:lang w:eastAsia=\"en-US\" w:val=\"ru-RU\"/>"
+"</w:rPr>"
+"</w:style>"
+ "<w:style w:default=\"1\" w:styleId=\"DefaultParagraphFont\" w:type=\"character\">"
+ "<w:name w:val=\"Default Paragraph Font\"/>"
+ "<w:uiPriority w:val=\"1\"/>"
+ "<w:semiHidden/>"
+ "<w:unhideWhenUsed/>"
+"</w:style>"
+"</w:styles>";
String themeXML = "<a:theme name=\"Office Theme\" xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
+ "<a:themeElements>"
+ "<a:clrScheme name=\"Office\">"
+ "<a:dk1>"
+ "<a:sysClr lastClr=\"000000\" val=\"windowText\"/>"
+"</a:dk1>"
+ "<a:lt1>"
+ "<a:sysClr lastClr=\"FFFFFF\" val=\"window\"/>"
+"</a:lt1>"
+ "<a:dk2>"
+ "<a:srgbClr val=\"1F497D\"/>"
+"</a:dk2>"
+ "<a:lt2>"
+ "<a:srgbClr val=\"EEECE1\"/>"
+"</a:lt2>"
+ "<a:accent1>"
+ "<a:srgbClr val=\"4F81BD\"/>"
+"</a:accent1>"
+ "<a:accent2>"
+ "<a:srgbClr val=\"C0504D\"/>"
+"</a:accent2>"
+ "<a:accent3>"
+ "<a:srgbClr val=\"9BBB59\"/>"
+"</a:accent3>"
+ "<a:accent4>"
+ "<a:srgbClr val=\"8064A2\"/>"
+"</a:accent4>"
+ "<a:accent5>"
+ "<a:srgbClr val=\"4BACC6\"/>"
+"</a:accent5>"
+ "<a:accent6>"
+ "<a:srgbClr val=\"F79646\"/>"
+"</a:accent6>"
+ "<a:hlink>"
+ "<a:srgbClr val=\"0000FF\"/>"
+"</a:hlink>"
+ "<a:folHlink>"
+ "<a:srgbClr val=\"800080\"/>"
+"</a:folHlink>"
+"</a:clrScheme>"
+ "<a:fontScheme name=\"Office\">"
+ "<a:majorFont>"
+ "<a:latin typeface=\"Cambria\"/>"
+ "<a:ea typeface=\"\"/>"
+ "<a:cs typeface=\"\"/>"
+ "<a:font script=\"Jpan\" typeface=\"MS ゴシック\"/>"
+ "<a:font script=\"Hang\" typeface=\"맑은 고딕\"/>"
+ "<a:font script=\"Hans\" typeface=\"宋体\"/>"
+ "<a:font script=\"Hant\" typeface=\"新細明體\"/>"
+ "<a:font script=\"Arab\" typeface=\"Times New Roman\"/>"
+ "<a:font script=\"Hebr\" typeface=\"Times New Roman\"/>"
+ "<a:font script=\"Thai\" typeface=\"Angsana New\"/>"
+ "<a:font script=\"Ethi\" typeface=\"Nyala\"/>"
+ "<a:font script=\"Beng\" typeface=\"Vrinda\"/>"
+ "<a:font script=\"Gujr\" typeface=\"Shruti\"/>"
+ "<a:font script=\"Khmr\" typeface=\"MoolBoran\"/>"
+ "<a:font script=\"Knda\" typeface=\"Tunga\"/>"
+ "<a:font script=\"Guru\" typeface=\"Raavi\"/>"
+ "<a:font script=\"Cans\" typeface=\"Euphemia\"/>"
+ "<a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/>"
+ "<a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/>"
+ "<a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/>"
+ "<a:font script=\"Thaa\" typeface=\"MV Boli\"/>"
+ "<a:font script=\"Deva\" typeface=\"Mangal\"/>"
+ "<a:font script=\"Telu\" typeface=\"Gautami\"/>"
+ "<a:font script=\"Taml\" typeface=\"Latha\"/>"
+ "<a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/>"
+ "<a:font script=\"Orya\" typeface=\"Kalinga\"/>"
+ "<a:font script=\"Mlym\" typeface=\"Kartika\"/>"
+ "<a:font script=\"Laoo\" typeface=\"DokChampa\"/>"
+ "<a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/>"
+ "<a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/>"
+ "<a:font script=\"Viet\" typeface=\"Times New Roman\"/>"
+ "<a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/>"
+"</a:majorFont>"
+ "<a:minorFont>"
+ "<a:latin typeface=\"Calibri\"/>"
+ "<a:ea typeface=\"\"/>"
+ "<a:cs typeface=\"\"/>"
+ "<a:font script=\"Jpan\" typeface=\"MS 明朝\"/>"
+ "<a:font script=\"Hang\" typeface=\"맑은 고딕\"/>"
+ "<a:font script=\"Hans\" typeface=\"宋体\"/>"
+ "<a:font script=\"Hant\" typeface=\"新細明體\"/>"
+ "<a:font script=\"Arab\" typeface=\"Arial\"/>"
+ "<a:font script=\"Hebr\" typeface=\"Arial\"/>"
+ "<a:font script=\"Thai\" typeface=\"Cordia New\"/>"
+ "<a:font script=\"Ethi\" typeface=\"Nyala\"/>"
+ "<a:font script=\"Beng\" typeface=\"Vrinda\"/>"
+ "<a:font script=\"Gujr\" typeface=\"Shruti\"/>"
+ "<a:font script=\"Khmr\" typeface=\"DaunPenh\"/>"
+ "<a:font script=\"Knda\" typeface=\"Tunga\"/>"
+ "<a:font script=\"Guru\" typeface=\"Raavi\"/>"
+ "<a:font script=\"Cans\" typeface=\"Euphemia\"/>"
+ "<a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/>"
+ "<a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/>"
+ "<a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/>"
+ "<a:font script=\"Thaa\" typeface=\"MV Boli\"/>"
+ "<a:font script=\"Deva\" typeface=\"Mangal\"/>"
+ "<a:font script=\"Telu\" typeface=\"Gautami\"/>"
+ "<a:font script=\"Taml\" typeface=\"Latha\"/>"
+ "<a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/>"
+ "<a:font script=\"Orya\" typeface=\"Kalinga\"/>"
+ "<a:font script=\"Mlym\" typeface=\"Kartika\"/>"
+ "<a:font script=\"Laoo\" typeface=\"DokChampa\"/>"
+ "<a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/>"
+ "<a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/>"
+ "<a:font script=\"Viet\" typeface=\"Arial\"/>"
+ "<a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/>"
+"</a:minorFont>"
+"</a:fontScheme>"
+ "<a:fmtScheme name=\"Office\">"
+ "<a:fillStyleLst>"
+ "<a:solidFill>"
+ "<a:schemeClr val=\"phClr\"/>"
+"</a:solidFill>"
+ "<a:gradFill rotWithShape=\"1\">"
+ "<a:gsLst>"
+ "<a:gs pos=\"0\">"
+ "<a:schemeClr val=\"phClr\">"
+ "<a:tint val=\"50000\"/>"
+ "<a:satMod val=\"300000\"/>"
+"</a:schemeClr>"
+"</a:gs>"
+ "<a:gs pos=\"35000\">"
+ "<a:schemeClr val=\"phClr\">"
+ "<a:tint val=\"37000\"/>"
+ "<a:satMod val=\"300000\"/>"
+"</a:schemeClr>"
+"</a:gs>"
+ "<a:gs pos=\"100000\">"
+ "<a:schemeClr val=\"phClr\">"
+ "<a:tint val=\"15000\"/>"
+ "<a:satMod val=\"350000\"/>"
+"</a:schemeClr>"
+"</a:gs>"
+"</a:gsLst>"
+ "<a:lin ang=\"16200000\" scaled=\"1\"/>"
+"</a:gradFill>"
+ "<a:gradFill rotWithShape=\"1\">"
+ "<a:gsLst>"
+ "<a:gs pos=\"0\">"
+ "<a:schemeClr val=\"phClr\">"
+ "<a:shade val=\"51000\"/>"
+ "<a:satMod val=\"130000\"/>"
+"</a:schemeClr>"
+"</a:gs>"
+ "<a:gs pos=\"80000\">"
+ "<a:schemeClr val=\"phClr\">"
+ "<a:shade val=\"93000\"/>"
+ "<a:satMod val=\"130000\"/>"
+"</a:schemeClr>"
+"</a:gs>"
+ "<a:gs pos=\"100000\">"
+ "<a:schemeClr val=\"phClr\">"
+ "<a:shade val=\"94000\"/>"
+ "<a:satMod val=\"135000\"/>"
+"</a:schemeClr>"
+"</a:gs>"
+"</a:gsLst>"
+ "<a:lin ang=\"16200000\" scaled=\"0\"/>"
+"</a:gradFill>"
+"</a:fillStyleLst>"
+ "<a:lnStyleLst>"
+ "<a:ln algn=\"ctr\" cap=\"flat\" cmpd=\"sng\" w=\"9525\">"
+ "<a:solidFill>"
+ "<a:schemeClr val=\"phClr\">"
+ "<a:shade val=\"95000\"/>"
+ "<a:satMod val=\"105000\"/>"
+"</a:schemeClr>"
+"</a:solidFill>"
+ "<a:prstDash val=\"solid\"/>"
+"</a:ln>"
+ "<a:ln algn=\"ctr\" cap=\"flat\" cmpd=\"sng\" w=\"25400\">"
+ "<a:solidFill>"
+ "<a:schemeClr val=\"phClr\"/>"
+"</a:solidFill>"
+ "<a:prstDash val=\"solid\"/>"
+"</a:ln>"
+ "<a:ln algn=\"ctr\" cap=\"flat\" cmpd=\"sng\" w=\"38100\">"
+ "<a:solidFill>"
+ "<a:schemeClr val=\"phClr\"/>"
+"</a:solidFill>"
+ "<a:prstDash val=\"solid\"/>"
+"</a:ln>"
+"</a:lnStyleLst>"
+ "<a:effectStyleLst>"
+ "<a:effectStyle>"
+ "<a:effectLst>"
+ "<a:outerShdw blurRad=\"40000\" dir=\"5400000\" dist=\"20000\" rotWithShape=\"0\">"
+ "<a:srgbClr val=\"000000\">"
+ "<a:alpha val=\"38000\"/>"
+"</a:srgbClr>"
+"</a:outerShdw>"
+"</a:effectLst>"
+"</a:effectStyle>"
+ "<a:effectStyle>"
+ "<a:effectLst>"
+ "<a:outerShdw blurRad=\"40000\" dir=\"5400000\" dist=\"23000\" rotWithShape=\"0\">"
+ "<a:srgbClr val=\"000000\">"
+ "<a:alpha val=\"35000\"/>"
+"</a:srgbClr>"
+"</a:outerShdw>"
+"</a:effectLst>"
+"</a:effectStyle>"
+ "<a:effectStyle>"
+ "<a:effectLst>"
+ "<a:outerShdw blurRad=\"40000\" dir=\"5400000\" dist=\"23000\" rotWithShape=\"0\">"
+ "<a:srgbClr val=\"000000\">"
+ "<a:alpha val=\"35000\"/>"
+"</a:srgbClr>"
+"</a:outerShdw>"
+"</a:effectLst>"
+ "<a:scene3d>"
+ "<a:camera prst=\"orthographicFront\">"
+ "<a:rot lat=\"0\" lon=\"0\" rev=\"0\"/>"
+"</a:camera>"
+ "<a:lightRig dir=\"t\" rig=\"threePt\">"
+ "<a:rot lat=\"0\" lon=\"0\" rev=\"1200000\"/>"
+"</a:lightRig>"
+"</a:scene3d>"
+ "<a:sp3d>"
+ "<a:bevelT h=\"25400\" w=\"63500\"/>"
+"</a:sp3d>"
+"</a:effectStyle>"
+"</a:effectStyleLst>"
+ "<a:bgFillStyleLst>"
+ "<a:solidFill>"
+ "<a:schemeClr val=\"phClr\"/>"
+"</a:solidFill>"
+ "<a:gradFill rotWithShape=\"1\">"
+ "<a:gsLst>"
+ "<a:gs pos=\"0\">"
+ "<a:schemeClr val=\"phClr\">"
+ "<a:tint val=\"40000\"/>"
+ "<a:satMod val=\"350000\"/>"
+"</a:schemeClr>"
+"</a:gs>"
+ "<a:gs pos=\"40000\">"
+ "<a:schemeClr val=\"phClr\">"
+ "<a:tint val=\"45000\"/>"
+ "<a:shade val=\"99000\"/>"
+ "<a:satMod val=\"350000\"/>"
+"</a:schemeClr>"
+"</a:gs>"
+ "<a:gs pos=\"100000\">"
+ "<a:schemeClr val=\"phClr\">"
+ "<a:shade val=\"20000\"/>"
+ "<a:satMod val=\"255000\"/>"
+"</a:schemeClr>"
+"</a:gs>"
+"</a:gsLst>"
+ "<a:path path=\"circle\">"
+ "<a:fillToRect b=\"180000\" l=\"50000\" r=\"50000\" t=\"-80000\"/>"
+"</a:path>"
+"</a:gradFill>"
+ "<a:gradFill rotWithShape=\"1\">"
+ "<a:gsLst>"
+ "<a:gs pos=\"0\">"
+ "<a:schemeClr val=\"phClr\">"
+ "<a:tint val=\"80000\"/>"
+ "<a:satMod val=\"300000\"/>"
+"</a:schemeClr>"
+"</a:gs>"
+ "<a:gs pos=\"100000\">"
+ "<a:schemeClr val=\"phClr\">"
+ "<a:shade val=\"30000\"/>"
+ "<a:satMod val=\"200000\"/>"
+"</a:schemeClr>"
+"</a:gs>"
+"</a:gsLst>"
+ "<a:path path=\"circle\">"
+ "<a:fillToRect b=\"50000\" l=\"50000\" r=\"50000\" t=\"50000\"/>"
+"</a:path>"
+"</a:gradFill>"
+"</a:bgFillStyleLst>"
+"</a:fmtScheme>"
+"</a:themeElements>"
+ "<a:objectDefaults/>"
+ "<a:extraClrSchemeLst/>"
+"</a:theme>";
// copied from FOConversionContext
private static RunFontSelector createRunFontSelector(WordprocessingMLPackage wmlPackage) {
return new RunFontSelector(wmlPackage,
new RunFontCharacterVisitor() {
DocumentFragment df;
StringBuilder sb = new StringBuilder(1024);
Element span;
String lastFont;
String fallbackFontName;
private org.w3c.dom.Document document;
@Override
public void setDocument(org.w3c.dom.Document document) {
this.document = document;
df = document.createDocumentFragment();
}
private boolean spanReusable = true;
public boolean isReusable() {
return spanReusable;
}
public void addCharacterToCurrent(char c) {
sb.append(c);
}
public void finishPrevious() {
if (sb.length()>0) {
if (span==null) { // init
span = runFontSelector.createElement(document);
// so that spaces have correct font set
if (lastFont!=null) {
runFontSelector.setAttribute(span, lastFont);
}
}
df.appendChild(span);
span.setTextContent(sb.toString());
// log.info("span: " + sb.toString());
sb.setLength(0);
}
}
public void createNew() {
span = runFontSelector.createElement(document);
}
public void setMustCreateNewFlag(boolean val) {
spanReusable = !val;
}
public void fontAction(String fontname) {
// System.out.println(fontname);
// Throwable t = new Throwable();
// t.printStackTrace();
if (fontname==null) {
runFontSelector.setAttribute(span, fallbackFontName);
} else {
runFontSelector.setAttribute(span, fontname);
lastFont = fontname;
}
}
@Override
public Object getResult() {
span=null; // ready for next time
return df;
}
private RunFontSelector runFontSelector;
@Override
public void setRunFontSelector(RunFontSelector runFontSelector) {
this.runFontSelector = runFontSelector;
}
@Override
public void setFallbackFont(String fontname) {
fallbackFontName = fontname;
}
}, RunFontActionType.XSL_FO);
}
}