FOP-2094 preliminary support for mapping OTF script tags from @script property FOP-2094 when no lookups match specified or auto script, retry using DFLT script FOP-2093 preliminary support for mapping OTF language tags from @language property git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1623885 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_0
@@ -898,9 +898,12 @@ list of possible build targets. | |||
<target name="junit-complexscripts" depends="junit-compile"> | |||
<junit-run title="complexscripts" testsuite="org.apache.fop.complexscripts.ComplexScriptsTestSuite" outfile="TEST-complexscripts"/> | |||
</target> | |||
<target name="junit-complexscripts-layout" depends="junit-compile" if="junit.present"> | |||
<junit-run title="standard layout engine" testsuite="org.apache.fop.complexscripts.layout.ComplexScriptsLayoutTestSuite" outfile="TEST-complexscripts-layout"/> | |||
</target> | |||
<target name="junit-reduced" depends="junit-userconfig, junit-basic, junit-transcoder, | |||
junit-text-linebreak, junit-fotree, junit-fonts, junit-render-pdf, junit-render-ps, | |||
junit-complexscripts"/> | |||
junit-complexscripts, junit-complexscripts-layout"/> | |||
<target name="junit" depends="junit-all" description="Runs all of FOP's JUnit tests" | |||
if="junit.present"> | |||
<fail><condition><or><isset property="fop.junit.error"/><isset |
@@ -141,7 +141,7 @@ public class FopConfParser { | |||
this(new FileInputStream(fopConfFile), fopConfFile.toURI(), resourceResolver); | |||
} | |||
private FopConfParser(InputStream fopConfStream, URI baseURI, EnvironmentProfile enviro) | |||
public FopConfParser(InputStream fopConfStream, URI baseURI, EnvironmentProfile enviro) | |||
throws SAXException, IOException { | |||
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder(); | |||
Configuration cfg; |
@@ -223,7 +223,11 @@ public class GlyphTable { | |||
} | |||
matchedLookups.put(lsm, lm); | |||
} | |||
return lm; | |||
if (lm.isEmpty() && !OTFScript.isDefault(script) && !OTFScript.isWildCard(script)) { | |||
return matchLookups(OTFScript.DEFAULT, OTFLanguage.DEFAULT, feature); | |||
} else { | |||
return lm; | |||
} | |||
} | |||
/** | |||
@@ -274,6 +278,19 @@ public class GlyphTable { | |||
return (UseSpec[]) uss.toArray(new UseSpec [ uss.size() ]); | |||
} | |||
/** | |||
* Determine if table supports specific feature, i.e., supports at least one lookup. | |||
* | |||
* @param script to qualify feature lookup | |||
* @param language to qualify feature lookup | |||
* @param feature to test | |||
* @return true if feature supported (has at least one lookup) | |||
*/ | |||
public boolean hasFeature(String script, String language, String feature) { | |||
UseSpec[] usa = assembleLookups(new String[] { feature }, matchLookups(script, language, feature)); | |||
return usa.length > 0; | |||
} | |||
/** {@inheritDoc} */ | |||
public String toString() { | |||
StringBuffer sb = new StringBuffer(super.toString()); | |||
@@ -350,8 +367,8 @@ public class GlyphTable { | |||
* @param script a script identifier | |||
* @param language a language identifier | |||
* @param feature a feature identifier | |||
* @param permitEmpty if true the permit empty script, language, or feature | |||
* @param permitWildcard if true the permit wildcard script, language, or feature | |||
* @param permitEmpty if true then permit empty script, language, or feature | |||
* @param permitWildcard if true then permit wildcard script, language, or feature | |||
*/ | |||
LookupSpec(String script, String language, String feature, boolean permitEmpty, boolean permitWildcard) { | |||
if ((script == null) || (!permitEmpty && (script.length() == 0))) { |
@@ -0,0 +1,434 @@ | |||
/* | |||
* 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$ */ | |||
package org.apache.fop.complexscripts.fonts; | |||
/** | |||
* <p>Language system tags defined by OTF specification. Note that this set and their | |||
* values do not correspond with ISO639* or any other language registry.</p> | |||
* | |||
* <p>This work was originally authored by Glenn Adams (gadams@apache.org).</p> | |||
*/ | |||
public final class OTFLanguage { | |||
public static final String ABAZA = "ABA"; | |||
public static final String ABKHAZIAN = "ABK"; | |||
public static final String ADYGHE = "ADY"; | |||
public static final String AFRIKAANS = "AFK"; | |||
public static final String AFAR = "AFR"; | |||
public static final String AGAW = "AGW"; | |||
public static final String ALSATIAN = "ALS"; | |||
public static final String ALTAI = "ALT"; | |||
public static final String AMHARIC = "AMH"; | |||
public static final String PHONETIC_AMERICANIST = "APPH"; | |||
public static final String ARABIC = "ARA"; | |||
public static final String AARI = "ARI"; | |||
public static final String ARAKANESE = "ARK"; | |||
public static final String ASSAMESE = "ASM"; | |||
public static final String ATHAPASKAN = "ATH"; | |||
public static final String AVAR = "AVR"; | |||
public static final String AWADHI = "AWA"; | |||
public static final String AYMARA = "AYM"; | |||
public static final String AZERI = "AZE"; | |||
public static final String BADAGA = "BAD"; | |||
public static final String BAGHELKHANDI = "BAG"; | |||
public static final String BALKAR = "BAL"; | |||
public static final String BAULE = "BAU"; | |||
public static final String BERBER = "BBR"; | |||
public static final String BENCH = "BCH"; | |||
public static final String BIBLE_CREE = "BCR"; | |||
public static final String BELARUSSIAN = "BEL"; | |||
public static final String BEMBA = "BEM"; | |||
public static final String BENGALI = "BEN"; | |||
public static final String BULGARIAN = "BGR"; | |||
public static final String BHILI = "BHI"; | |||
public static final String BHOJPURI = "BHO"; | |||
public static final String BIKOL = "BIK"; | |||
public static final String BILEN = "BIL"; | |||
public static final String BLACKFOOT = "BKF"; | |||
public static final String BALOCHI = "BLI"; | |||
public static final String BALANTE = "BLN"; | |||
public static final String BALTI = "BLT"; | |||
public static final String BAMBARA = "BMB"; | |||
public static final String BAMILEKE = "BML"; | |||
public static final String BOSNIAN = "BOS"; | |||
public static final String BRETON = "BRE"; | |||
public static final String BRAHUI = "BRH"; | |||
public static final String BRAJ_BHASHA = "BRI"; | |||
public static final String BURMESE = "BRM"; | |||
public static final String BASHKIR = "BSH"; | |||
public static final String BETI = "BTI"; | |||
public static final String CATALAN = "CAT"; | |||
public static final String CEBUANO = "CEB"; | |||
public static final String CHECHEN = "CHE"; | |||
public static final String CHAHA_GURAGE = "CHG"; | |||
public static final String CHATTISGARHI = "CHH"; | |||
public static final String CHICHEWA = "CHI"; | |||
public static final String CHUKCHI = "CHK"; | |||
public static final String CHIPEWYAN = "CHP"; | |||
public static final String CHEROKEE = "CHR"; | |||
public static final String CHUVASH = "CHU"; | |||
public static final String COMORIAN = "CMR"; | |||
public static final String COPTIC = "COP"; | |||
public static final String CORSICAN = "COS"; | |||
public static final String CREE = "CRE"; | |||
public static final String CARRIER = "CRR"; | |||
public static final String CRIMEAN_TATAR = "CRT"; | |||
public static final String CHURCH_SLAVONIC = "CSL"; | |||
public static final String CZECH = "CSY"; | |||
public static final String DANISH = "DAN"; | |||
public static final String DARGWA = "DAR"; | |||
public static final String WOODS_CREE = "DCR"; | |||
public static final String GERMAN = "DEU"; | |||
public static final String DEFAULT = "dflt"; | |||
public static final String DOGRI = "DGR"; | |||
public static final String DHIVEHI_DEPRECATED = "DHV"; | |||
public static final String DHIVEHI = "DIV"; | |||
public static final String DJERMA = "DJR"; | |||
public static final String DANGME = "DNG"; | |||
public static final String DINKA = "DNK"; | |||
public static final String DARI = "DRI"; | |||
public static final String DUNGAN = "DUN"; | |||
public static final String DZONGKHA = "DZN"; | |||
public static final String EBIRA = "EBI"; | |||
public static final String EASTERN_CREE = "ECR"; | |||
public static final String EDO = "EDO"; | |||
public static final String EFIK = "EFI"; | |||
public static final String GREEK = "ELL"; | |||
public static final String ENGLISH = "ENG"; | |||
public static final String ERZYA = "ERZ"; | |||
public static final String SPANISH = "ESP"; | |||
public static final String ESTONIAN = "ETI"; | |||
public static final String BASQUE = "EUQ"; | |||
public static final String EVENKI = "EVK"; | |||
public static final String EVEN = "EVN"; | |||
public static final String EWE = "EWE"; | |||
public static final String FRENCH_ANTILLEAN = "FAN"; | |||
public static final String FARSI = "FAR"; | |||
public static final String FINNISH = "FIN"; | |||
public static final String FIJIAN = "FJI"; | |||
public static final String FLEMISH = "FLE"; | |||
public static final String FOREST_NENETS = "FNE"; | |||
public static final String FON = "FON"; | |||
public static final String FAROESE = "FOS"; | |||
public static final String FRENCH = "FRA"; | |||
public static final String FRISIAN = "FRI"; | |||
public static final String FRIULIAN = "FRL"; | |||
public static final String FUTA = "FTA"; | |||
public static final String FULANI = "FUL"; | |||
public static final String GA = "GAD"; | |||
public static final String GAELIC = "GAE"; | |||
public static final String GAGAUZ = "GAG"; | |||
public static final String GALICIAN = "GAL"; | |||
public static final String GARSHUNI = "GAR"; | |||
public static final String GARHWALI = "GAW"; | |||
public static final String GEEZ = "GEZ"; | |||
public static final String GILYAK = "GIL"; | |||
public static final String GUMUZ = "GMZ"; | |||
public static final String GONDI = "GON"; | |||
public static final String GREENLANDIC = "GRN"; | |||
public static final String GARO = "GRO"; | |||
public static final String GUARANI = "GUA"; | |||
public static final String GUJARATI = "GUJ"; | |||
public static final String HAITIAN = "HAI"; | |||
public static final String HALAM = "HAL"; | |||
public static final String HARAUTI = "HAR"; | |||
public static final String HAUSA = "HAU"; | |||
public static final String HAWAIIN = "HAW"; | |||
public static final String HAMMER_BANNA = "HBN"; | |||
public static final String HILIGAYNON = "HIL"; | |||
public static final String HINDI = "HIN"; | |||
public static final String HIGH_MARI = "HMA"; | |||
public static final String HINDKO = "HND"; | |||
public static final String HO = "HO"; | |||
public static final String HARARI = "HRI"; | |||
public static final String CROATIAN = "HRV"; | |||
public static final String HUNGARIAN = "HUN"; | |||
public static final String ARMENIAN = "HYE"; | |||
public static final String IGBO = "IBO"; | |||
public static final String IJO = "IJO"; | |||
public static final String ILOKANO = "ILO"; | |||
public static final String INDONESIAN = "IND"; | |||
public static final String INGUSH = "ING"; | |||
public static final String INUKTITUT = "INU"; | |||
public static final String PHONETIC_IPA = "IPPH"; | |||
public static final String IRISH = "IRI"; | |||
public static final String IRISH_TRADITIONAL = "IRT"; | |||
public static final String ICELANDIC = "ISL"; | |||
public static final String INARI_SAMI = "ISM"; | |||
public static final String ITALIAN = "ITA"; | |||
public static final String HEBREW = "IWR"; | |||
public static final String JAVANESE = "JAV"; | |||
public static final String YIDDISH = "JII"; | |||
public static final String JAPANESE = "JAN"; | |||
public static final String JUDEZMO = "JUD"; | |||
public static final String JULA = "JUL"; | |||
public static final String KABARDIAN = "KAB"; | |||
public static final String KACHCHI = "KAC"; | |||
public static final String KALENJIN = "KAL"; | |||
public static final String KANNADA = "KAN"; | |||
public static final String KARACHAY = "KAR"; | |||
public static final String GEORGIAN = "KAT"; | |||
public static final String KAZAKH = "KAZ"; | |||
public static final String KEBENA = "KEB"; | |||
public static final String KHUTSURI_GEORGIAN = "KGE"; | |||
public static final String KHAKASS = "KHA"; | |||
public static final String KHANTY_KAZIM = "KHK"; | |||
public static final String KHMER = "KHM"; | |||
public static final String KHANTY_SHURISHKAR = "KHS"; | |||
public static final String KHANTY_VAKHI = "KHV"; | |||
public static final String KHOWAR = "KHW"; | |||
public static final String KIKUYU = "KIK"; | |||
public static final String KIRGHIZ = "KIR"; | |||
public static final String KISII = "KIS"; | |||
public static final String KOKNI = "KKN"; | |||
public static final String KALMYK = "KLM"; | |||
public static final String KAMBA = "KMB"; | |||
public static final String KUMAONI = "KMN"; | |||
public static final String KOMO = "KMO"; | |||
public static final String KOMSO = "KMS"; | |||
public static final String KANURI = "KNR"; | |||
public static final String KODAGU = "KOD"; | |||
public static final String KOREAN_OLD_HANGUL = "KOH"; | |||
public static final String KONKANI = "KOK"; | |||
public static final String KIKONGO = "KON"; | |||
public static final String KOMI_PERMYAK = "KOP"; | |||
public static final String KOREAN = "KOR"; | |||
public static final String KOMI_ZYRIAN = "KOZ"; | |||
public static final String KPELLE = "KPL"; | |||
public static final String KRIO = "KRI"; | |||
public static final String KARAKALPAK = "KRK"; | |||
public static final String KARELIAN = "KRL"; | |||
public static final String KARAIM = "KRM"; | |||
public static final String KAREN = "KRN"; | |||
public static final String KOORETE = "KRT"; | |||
public static final String KASHMIRI = "KSH"; | |||
public static final String KHASI = "KSI"; | |||
public static final String KILDIN_SAMI = "KSM"; | |||
public static final String KUI = "KUI"; | |||
public static final String KULVI = "KUL"; | |||
public static final String KUMYK = "KUM"; | |||
public static final String KURDISH = "KUR"; | |||
public static final String KURUKH = "KUU"; | |||
public static final String KUY = "KUY"; | |||
public static final String KORYAK = "KYK"; | |||
public static final String LADIN = "LAD"; | |||
public static final String LAHULI = "LAH"; | |||
public static final String LAK = "LAK"; | |||
public static final String LAMBANI = "LAM"; | |||
public static final String LAO = "LAO"; | |||
public static final String LATIN = "LAT"; | |||
public static final String LAZ = "LAZ"; | |||
public static final String L_CREE = "LCR"; | |||
public static final String LADAKHI = "LDK"; | |||
public static final String LEZGI = "LEZ"; | |||
public static final String LINGALA = "LIN"; | |||
public static final String LOW_MARI = "LMA"; | |||
public static final String LIMBU = "LMB"; | |||
public static final String LOMWE = "LMW"; | |||
public static final String LOWER_SORBIAN = "LSB"; | |||
public static final String LULE_SAMI = "LSM"; | |||
public static final String LITHUANIAN = "LTH"; | |||
public static final String LUXEMBOURGISH = "LTZ"; | |||
public static final String LUBA = "LUB"; | |||
public static final String LUGANDA = "LUG"; | |||
public static final String LUHYA = "LUH"; | |||
public static final String LUO = "LUO"; | |||
public static final String LATVIAN = "LVI"; | |||
public static final String MAJANG = "MAJ"; | |||
public static final String MAKUA = "MAK"; | |||
public static final String MALAYALAM_TRADITIONAL = "MAL"; | |||
public static final String MANSI = "MAN"; | |||
public static final String MAPUDUNGUN = "MAP"; | |||
public static final String MARATHI = "MAR"; | |||
public static final String MARWARI = "MAW"; | |||
public static final String MBUNDU = "MBN"; | |||
public static final String MANCHU = "MCH"; | |||
public static final String MOOSE_CREE = "MCR"; | |||
public static final String MENDE = "MDE"; | |||
public static final String MEEN = "MEN"; | |||
public static final String MIZO = "MIZ"; | |||
public static final String MACEDONIAN = "MKD"; | |||
public static final String MALE = "MLE"; | |||
public static final String MALAGASY = "MLG"; | |||
public static final String MALINKE = "MLN"; | |||
public static final String MALAYALAM_REFORMED = "MLR"; | |||
public static final String MALAY = "MLY"; | |||
public static final String MANDINKA = "MND"; | |||
public static final String MONGOLIAN = "MNG"; | |||
public static final String MANIPURI = "MNI"; | |||
public static final String MANINKA = "MNK"; | |||
public static final String MANX_GAELIC = "MNX"; | |||
public static final String MOHAWK = "MOH"; | |||
public static final String MOKSHA = "MOK"; | |||
public static final String MOLDAVIAN = "MOL"; | |||
public static final String MON = "MON"; | |||
public static final String MOROCCAN = "MOR"; | |||
public static final String MAORI = "MRI"; | |||
public static final String MAITHILI = "MTH"; | |||
public static final String MALTESE = "MTS"; | |||
public static final String MUNDARI = "MUN"; | |||
public static final String NAGA_ASSAMESE = "NAG"; | |||
public static final String NANAI = "NAN"; | |||
public static final String NASKAPI = "NAS"; | |||
public static final String N_CREE = "NCR"; | |||
public static final String NDEBELE = "NDB"; | |||
public static final String NDONGA = "NDG"; | |||
public static final String NEPALI = "NEP"; | |||
public static final String NEWARI = "NEW"; | |||
public static final String NAGARI = "NGR"; | |||
public static final String NORWAY_HOUSE_CREE = "NHC"; | |||
public static final String NISI = "NIS"; | |||
public static final String NIUEAN = "NIU"; | |||
public static final String NKOLE = "NKL"; | |||
public static final String NKO = "NKO"; | |||
public static final String DUTCH = "NLD"; | |||
public static final String NOGAI = "NOG"; | |||
public static final String NORWEGIAN = "NOR"; | |||
public static final String NORTHERN_SAMI = "NSM"; | |||
public static final String NORTHERN_TAI = "NTA"; | |||
public static final String ESPERANTO = "NTO"; | |||
public static final String NYNORSK = "NYN"; | |||
public static final String OCCITAN = "OCI"; | |||
public static final String OJI_CREE = "OCR"; | |||
public static final String OJIBWAY = "OJB"; | |||
public static final String ORIYA = "ORI"; | |||
public static final String OROMO = "ORO"; | |||
public static final String OSSETIAN = "OSS"; | |||
public static final String PALESTINIAN_ARAMAIC = "PAA"; | |||
public static final String PALI = "PAL"; | |||
public static final String PUNJABI = "PAN"; | |||
public static final String PALPA = "PAP"; | |||
public static final String PASHTO = "PAS"; | |||
public static final String POLYTONIC_GREEK = "PGR"; | |||
public static final String FILIPINO = "PIL"; | |||
public static final String PALAUNG = "PLG"; | |||
public static final String POLISH = "PLK"; | |||
public static final String PROVENCAL = "PRO"; | |||
public static final String PORTUGUESE = "PTG"; | |||
public static final String CHIN = "QIN"; | |||
public static final String RAJASTHANI = "RAJ"; | |||
public static final String R_CREE = "RCR"; | |||
public static final String RUSSIAN_BURIAT = "RBU"; | |||
public static final String RIANG = "RIA"; | |||
public static final String RHAETO_ROMANIC = "RMS"; | |||
public static final String ROMANIAN = "ROM"; | |||
public static final String ROMANY = "ROY"; | |||
public static final String RUSYN = "RSY"; | |||
public static final String RUANDA = "RUA"; | |||
public static final String RUSSIAN = "RUS"; | |||
public static final String SADRI = "SAD"; | |||
public static final String SANSKRIT = "SAN"; | |||
public static final String SANTALI = "SAT"; | |||
public static final String SAYISI = "SAY"; | |||
public static final String SEKOTA = "SEK"; | |||
public static final String SELKUP = "SEL"; | |||
public static final String SANGO = "SGO"; | |||
public static final String SHAN = "SHN"; | |||
public static final String SIBE = "SIB"; | |||
public static final String SIDAMO = "SID"; | |||
public static final String SILTE_GURAGE = "SIG"; | |||
public static final String SKOLT_SAMI = "SKS"; | |||
public static final String SLOVAK = "SKY"; | |||
public static final String SLAVEY = "SLA"; | |||
public static final String SLOVENIAN = "SLV"; | |||
public static final String SOMALI = "SML"; | |||
public static final String SAMOAN = "SMO"; | |||
public static final String SENA = "SNA"; | |||
public static final String SINDHI = "SND"; | |||
public static final String SINHALESE = "SNH"; | |||
public static final String SONINKE = "SNK"; | |||
public static final String SODO_GURAGE = "SOG"; | |||
public static final String SOTHO = "SOT"; | |||
public static final String ALBANIAN = "SQI"; | |||
public static final String SERBIAN = "SRB"; | |||
public static final String SARAIKI = "SRK"; | |||
public static final String SERER = "SRR"; | |||
public static final String SOUTH_SLAVEY = "SSL"; | |||
public static final String SOUTHERN_SAMI = "SSM"; | |||
public static final String SURI = "SUR"; | |||
public static final String SVAN = "SVA"; | |||
public static final String SWEDISH = "SVE"; | |||
public static final String SWADAYA_ARAMAIC = "SWA"; | |||
public static final String SWAHILI = "SWK"; | |||
public static final String SWAZI = "SWZ"; | |||
public static final String SUTU = "SXT"; | |||
public static final String SYRIAC = "SYR"; | |||
public static final String TABASARAN = "TAB"; | |||
public static final String TAJIKI = "TAJ"; | |||
public static final String TAMIL = "TAM"; | |||
public static final String TATAR = "TAT"; | |||
public static final String TH_CREE = "TCR"; | |||
public static final String TELUGU = "TEL"; | |||
public static final String TONGAN = "TGN"; | |||
public static final String TIGRE = "TGR"; | |||
public static final String TIGRINYA = "TGY"; | |||
public static final String THAI = "THA"; | |||
public static final String TAHITIAN = "THT"; | |||
public static final String TIBETAN = "TIB"; | |||
public static final String TURKMEN = "TKM"; | |||
public static final String TEMNE = "TMN"; | |||
public static final String TSWANA = "TNA"; | |||
public static final String TUNDRA_NENETS = "TNE"; | |||
public static final String TONGA = "TNG"; | |||
public static final String TODO = "TOD"; | |||
public static final String TURKISH = "TRK"; | |||
public static final String TSONGA = "TSG"; | |||
public static final String TUROYO_ARAMAIC = "TUA"; | |||
public static final String TULU = "TUL"; | |||
public static final String TUVIN = "TUV"; | |||
public static final String TWI = "TWI"; | |||
public static final String UDMURT = "UDM"; | |||
public static final String UKRAINIAN = "UKR"; | |||
public static final String URDU = "URD"; | |||
public static final String UPPER_SORBIAN = "USB"; | |||
public static final String UYGHUR = "UYG"; | |||
public static final String UZBEK = "UZB"; | |||
public static final String VENDA = "VEN"; | |||
public static final String VIETNAMESE = "VIT"; | |||
public static final String WA = "WA"; | |||
public static final String WAGDI = "WAG"; | |||
public static final String WEST_CREE = "WCR"; | |||
public static final String WELSH = "WEL"; | |||
public static final String WILDCARD = "*"; | |||
public static final String WOLOF = "WLF"; | |||
public static final String TAI_LUE = "XBD"; | |||
public static final String XHOSA = "XHS"; | |||
public static final String SAKHA = "YAK"; | |||
public static final String YORUBA = "YBA"; | |||
public static final String Y_CREE = "YCR"; | |||
public static final String YI_CLASSIC = "YIC"; | |||
public static final String YI_MODERN = "YIM"; | |||
public static final String CHINESE_HONG_KONG_SAR = "ZHH"; | |||
public static final String CHINESE_PHONETIC = "ZHP"; | |||
public static final String CHINESE_SIMPLIFIED = "ZHS"; | |||
public static final String CHINESE_TRADITIONAL = "ZHT"; | |||
public static final String ZANDE = "ZND"; | |||
public static final String ZULU = "ZUL"; | |||
public static boolean isDefault(String language) { | |||
return (language != null) && language.equals(DEFAULT); | |||
} | |||
public static boolean isWildCard(String language) { | |||
return (language != null) && language.equals(WILDCARD); | |||
} | |||
private OTFLanguage() { | |||
} | |||
} |
@@ -0,0 +1,154 @@ | |||
/* | |||
* 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$ */ | |||
package org.apache.fop.complexscripts.fonts; | |||
/** | |||
* <p>Script tags defined by OTF specification. Note that this set and their | |||
* values do not correspond with ISO 15924 or Unicode Script names.</p> | |||
* | |||
* <p>This work was originally authored by Glenn Adams (gadams@apache.org).</p> | |||
*/ | |||
public final class OTFScript { | |||
public static final String ARABIC = "arab"; | |||
public static final String ARMENIAN = "armn"; | |||
public static final String AVESTAN = "avst"; | |||
public static final String BALINESE = "bali"; | |||
public static final String BAMUM = "bamu"; | |||
public static final String BATAK = "batk"; | |||
public static final String BENGALI = "beng"; | |||
public static final String BENGALI_V2 = "bng2"; | |||
public static final String BOPOMOFO = "bopo"; | |||
public static final String BRAILLE = "brai"; | |||
public static final String BRAHMI = "brah"; | |||
public static final String BUGINESE = "bugi"; | |||
public static final String BUHID = "buhd"; | |||
public static final String BYZANTINE_MUSIC = "byzm"; | |||
public static final String CANADIAN_SYLLABICS = "cans"; | |||
public static final String CARIAN = "cari"; | |||
public static final String CHAKMA = "cakm"; | |||
public static final String CHAM = "cham"; | |||
public static final String CHEROKEE = "cher"; | |||
public static final String CJK_IDEOGRAPHIC = "hani"; | |||
public static final String COPTIC = "copt"; | |||
public static final String CYPRIOT_SYLLABARY = "cprt"; | |||
public static final String CYRILLIC = "cyrl"; | |||
public static final String DEFAULT = "DFLT"; | |||
public static final String DESERET = "dsrt"; | |||
public static final String DEVANAGARI = "deva"; | |||
public static final String DEVANAGARI_V2 = "dev2"; | |||
public static final String EGYPTIAN_HEIROGLYPHS = "egyp"; | |||
public static final String ETHIOPIC = "ethi"; | |||
public static final String GEORGIAN = "geor"; | |||
public static final String GLAGOLITIC = "glag"; | |||
public static final String GOTHIC = "goth"; | |||
public static final String GREEK = "grek"; | |||
public static final String GUJARATI = "gujr"; | |||
public static final String GUJARATI_V2 = "gjr2"; | |||
public static final String GURMUKHI = "guru"; | |||
public static final String GURMUKHI_V2 = "gur2"; | |||
public static final String HANGUL = "hang"; | |||
public static final String HANGUL_JAMO = "jamo"; | |||
public static final String HANUNOO = "hano"; | |||
public static final String HEBREW = "hebr"; | |||
public static final String HIRAGANA = "kana"; | |||
public static final String IMPERIAL_ARAMAIC = "armi"; | |||
public static final String INSCRIPTIONAL_PAHLAVI = "phli"; | |||
public static final String INSCRIPTIONAL_PARTHIAN = "prti"; | |||
public static final String JAVANESE = "java"; | |||
public static final String KAITHI = "kthi"; | |||
public static final String KANNADA = "knda"; | |||
public static final String KANNADA_V2 = "knd2"; | |||
public static final String KATAKANA = "kana"; | |||
public static final String KAYAH_LI = "kali"; | |||
public static final String KHAROSTHI = "khar"; | |||
public static final String KHMER = "khmr"; | |||
public static final String LAO = "lao"; | |||
public static final String LATIN = "latn"; | |||
public static final String LEPCHA = "lepc"; | |||
public static final String LIMBU = "limb"; | |||
public static final String LINEAR_B = "linb"; | |||
public static final String LISU = "lisu"; | |||
public static final String LYCIAN = "lyci"; | |||
public static final String LYDIAN = "lydi"; | |||
public static final String MALAYALAM = "mlym"; | |||
public static final String MALAYALAM_V2 = "mlm2"; | |||
public static final String MANDAIC = "mand"; | |||
public static final String MATHEMATICAL_ALPHANUMERIC_SYMBOLS = "math"; | |||
public static final String MEITEI = "mtei"; | |||
public static final String MEROITIC_CURSIVE = "merc"; | |||
public static final String MEROITIC_HIEROGLYPHS = "mero"; | |||
public static final String MONGOLIAN = "mong"; | |||
public static final String MUSICAL_SYMBOLS = "musc"; | |||
public static final String MYANMAR = "mymr"; | |||
public static final String NEW_TAI_LUE = "talu"; | |||
public static final String NKO = "nko"; | |||
public static final String OGHAM = "ogam"; | |||
public static final String OL_CHIKI = "olck"; | |||
public static final String OLD_ITALIC = "ital"; | |||
public static final String OLD_PERSIAN_CUNEIFORM = "xpeo"; | |||
public static final String OLD_SOUTH_ARABIAN = "sarb"; | |||
public static final String OLD_TURKIC = "orkh"; | |||
public static final String ORIYA = "orya"; | |||
public static final String ORIYA_V2 = "ory2"; | |||
public static final String OSMANYA = "osma"; | |||
public static final String PHAGS_PA = "phag"; | |||
public static final String PHOENICIAN = "phnx"; | |||
public static final String REJANG = "rjng"; | |||
public static final String RUNIC = "runr"; | |||
public static final String SAMARITAN = "samr"; | |||
public static final String SAURASHTRA = "saur"; | |||
public static final String SHARADA = "shrd"; | |||
public static final String SHAVIAN = "shaw"; | |||
public static final String SINHALA = "sinh"; | |||
public static final String SORA_SOMPENG = "sora"; | |||
public static final String SUMERO_AKKADIAN_CUNEIFORM = "xsux"; | |||
public static final String SUNDANESE = "sund"; | |||
public static final String SYLOTI_NAGRI = "sylo"; | |||
public static final String SYRIAC = "syrc"; | |||
public static final String TAGALOG = "tglg"; | |||
public static final String TAGBANWA = "tagb"; | |||
public static final String TAI_LE = "tale"; | |||
public static final String TAI_THAM = "lana"; | |||
public static final String TAI_VIET = "tavt"; | |||
public static final String TAKRI = "takr"; | |||
public static final String TAMIL = "taml"; | |||
public static final String TAMIL_V2 = "tml2"; | |||
public static final String TELUGU = "telu"; | |||
public static final String TELUGU_V2 = "tel2"; | |||
public static final String THAANA = "thaa"; | |||
public static final String THAI = "thai"; | |||
public static final String TIBETAN = "tibt"; | |||
public static final String TIFINAGH = "tfng"; | |||
public static final String UGARITIC_CUNEIFORM = "ugar"; | |||
public static final String VAI = "vai"; | |||
public static final String WILDCARD = "*"; | |||
public static final String YI = "yi"; | |||
public static boolean isDefault(String script) { | |||
return (script != null) && script.equals(DEFAULT); | |||
} | |||
public static boolean isWildCard(String script) { | |||
return (script != null) && script.equals(DEFAULT); | |||
} | |||
private OTFScript() { | |||
} | |||
} |
@@ -160,6 +160,11 @@ public class Font implements Substitutable, Positionable { | |||
return metric.hasKerningInfo(); | |||
} | |||
/** @return true if the font has feature (i.e., at least one lookup matches) */ | |||
public boolean hasFeature(int tableType, String script, String language, String feature) { | |||
return metric.hasFeature(tableType, script, language, feature); | |||
} | |||
/** | |||
* Returns the font's kerning table | |||
* @return the kerning table |
@@ -135,8 +135,8 @@ public interface FontMetrics { | |||
Rectangle getBoundingBox(int glyphIndex, int size); | |||
/** | |||
* Indicates if the font has kering information. | |||
* @return True, if kerning is available. | |||
* Indicates if the font has kerning information. | |||
* @return true if kerning is available. | |||
*/ | |||
boolean hasKerningInfo(); | |||
@@ -180,4 +180,14 @@ public interface FontMetrics { | |||
*/ | |||
int getStrikeoutThickness(int size); | |||
/** | |||
* Determine if metrics supports specific feature in specified font table. | |||
* | |||
* @param tableType type of table (GSUB, GPOS, ...), see GlyphTable.GLYPH_TABLE_TYPE_* | |||
* @param script to qualify feature lookup | |||
* @param language to qualify feature lookup | |||
* @param feature to test | |||
* @return true if feature supported (and has at least one lookup) | |||
*/ | |||
boolean hasFeature(int tableType, String script, String language, String feature); | |||
} |
@@ -25,6 +25,7 @@ import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.complexscripts.fonts.GlyphPositioningTable; | |||
import org.apache.fop.complexscripts.fonts.GlyphTable; | |||
import org.apache.fop.complexscripts.util.CharScript; | |||
import org.apache.fop.traits.MinOptMax; | |||
import org.apache.fop.util.CharUtilities; | |||
@@ -128,15 +129,14 @@ public class GlyphMapping { | |||
CharSequence mcs = font.performSubstitution(ics, script, language, associations); | |||
// 4. compute glyph position adjustments on (substituted) characters. | |||
int[][] gpa; | |||
int[][] gpa = null; | |||
if (font.performsPositioning()) { | |||
// handle GPOS adjustments | |||
gpa = font.performPositioning(mcs, script, language); | |||
} else if (font.hasKerning()) { | |||
} | |||
if (useKerningAdjustments(font, script, language)) { | |||
// handle standard (non-GPOS) kerning adjustments | |||
gpa = getKerningAdjustments(mcs, font); | |||
} else { | |||
gpa = null; | |||
gpa = getKerningAdjustments(mcs, font, gpa); | |||
} | |||
// 5. reorder combining marks so that they precede (within the mapped char sequence) the | |||
@@ -166,6 +166,10 @@ public class GlyphMapping { | |||
associations); | |||
} | |||
private static boolean useKerningAdjustments(final Font font, String script, String language) { | |||
return font.hasKerning() && !font.hasFeature(GlyphTable.GLYPH_TABLE_TYPE_POSITIONING, script, language, "kern"); | |||
} | |||
/** | |||
* Given a mapped character sequence MCS, obtain glyph position adjustments from the | |||
* font's kerning data. | |||
@@ -174,7 +178,7 @@ public class GlyphMapping { | |||
* @param font applicable font | |||
* @return glyph position adjustments (or null if no kerning) | |||
*/ | |||
private static int[][] getKerningAdjustments(CharSequence mcs, final Font font) { | |||
private static int[][] getKerningAdjustments(CharSequence mcs, final Font font, int[][] gpa) { | |||
int nc = mcs.length(); | |||
// extract kerning array | |||
int[] ka = new int[nc]; // kerning array | |||
@@ -196,10 +200,12 @@ public class GlyphMapping { | |||
} | |||
// if non-zero kerning, then create and return glyph position adjustment array | |||
if (hasKerning) { | |||
int[][] gpa = new int[nc][4]; | |||
if (gpa == null) { | |||
gpa = new int[nc][4]; | |||
} | |||
for (int i = 0, n = nc; i < n; i++) { | |||
if (i > 0) { | |||
gpa [i - 1][GlyphPositioningTable.Value.IDX_X_ADVANCE] = ka[i]; | |||
gpa [i - 1][GlyphPositioningTable.Value.IDX_X_ADVANCE] += ka[i]; | |||
} | |||
} | |||
return gpa; |
@@ -317,6 +317,12 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable, | |||
return realFont.getKerningInfo(); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean hasFeature(int tableType, String script, String language, String feature) { | |||
load(true); | |||
return realFont.hasFeature(tableType, script, language, feature); | |||
} | |||
// ---- FontDescriptor interface ---- | |||
/** | |||
* {@inheritDoc} |
@@ -35,6 +35,7 @@ import org.apache.fop.apps.io.InternalResourceResolver; | |||
import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable; | |||
import org.apache.fop.complexscripts.fonts.GlyphPositioningTable; | |||
import org.apache.fop.complexscripts.fonts.GlyphSubstitutionTable; | |||
import org.apache.fop.complexscripts.fonts.GlyphTable; | |||
import org.apache.fop.complexscripts.fonts.Positionable; | |||
import org.apache.fop.complexscripts.fonts.Substitutable; | |||
import org.apache.fop.complexscripts.util.GlyphSequence; | |||
@@ -651,6 +652,21 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl | |||
return cb; | |||
} | |||
@Override | |||
public boolean hasFeature(int tableType, String script, String language, String feature) { | |||
GlyphTable table; | |||
if (tableType == GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION) { | |||
table = getGSUB(); | |||
} else if (tableType == GlyphTable.GLYPH_TABLE_TYPE_POSITIONING) { | |||
table = getGPOS(); | |||
} else if (tableType == GlyphTable.GLYPH_TABLE_TYPE_DEFINITION) { | |||
table = getGDEF(); | |||
} else { | |||
table = null; | |||
} | |||
return (table != null) && table.hasFeature(script, language, feature); | |||
} | |||
public Map<Integer, Integer> getWidthsMap() { | |||
return null; | |||
} |
@@ -103,6 +103,11 @@ public abstract class Typeface implements FontMetrics { | |||
return getAscender(size); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean hasFeature(int tableType, String script, String language, String feature) { | |||
return false; | |||
} | |||
/** | |||
* Sets the font event listener that can be used to receive events about particular events | |||
* in this class. |
@@ -0,0 +1,388 @@ | |||
/* | |||
* 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$ */ | |||
package org.apache.fop.complexscripts.layout; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import javax.xml.parsers.ParserConfigurationException; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.dom.DOMResult; | |||
import javax.xml.transform.dom.DOMSource; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.sax.TransformerHandler; | |||
import org.junit.BeforeClass; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.junit.runners.Parameterized; | |||
import org.junit.runners.Parameterized.Parameters; | |||
import org.w3c.dom.Document; | |||
import org.w3c.dom.Element; | |||
import org.w3c.dom.NamedNodeMap; | |||
import org.w3c.dom.Node; | |||
import org.w3c.dom.NodeList; | |||
import org.xml.sax.ContentHandler; | |||
import org.xml.sax.SAXException; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.io.filefilter.AndFileFilter; | |||
import org.apache.commons.io.filefilter.IOFileFilter; | |||
import org.apache.commons.io.filefilter.NameFileFilter; | |||
import org.apache.commons.io.filefilter.PrefixFileFilter; | |||
import org.apache.commons.io.filefilter.SuffixFileFilter; | |||
import org.apache.commons.io.filefilter.TrueFileFilter; | |||
import org.apache.fop.DebugHelper; | |||
import org.apache.fop.apps.EnvironmentProfile; | |||
import org.apache.fop.apps.EnvironmentalProfileFactory; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.Fop; | |||
import org.apache.fop.apps.FopConfBuilder; | |||
import org.apache.fop.apps.FopConfParser; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.FopFactoryBuilder; | |||
import org.apache.fop.apps.FormattingResults; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.apps.PDFRendererConfBuilder; | |||
import org.apache.fop.apps.io.ResourceResolverFactory; | |||
import org.apache.fop.area.AreaTreeModel; | |||
import org.apache.fop.area.AreaTreeParser; | |||
import org.apache.fop.area.RenderPagesModel; | |||
import org.apache.fop.events.Event; | |||
import org.apache.fop.events.EventListener; | |||
import org.apache.fop.events.model.EventSeverity; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.intermediate.IFTester; | |||
import org.apache.fop.intermediate.TestAssistant; | |||
import org.apache.fop.layoutengine.ElementListCollector; | |||
import org.apache.fop.layoutengine.LayoutEngineCheck; | |||
import org.apache.fop.layoutengine.LayoutEngineChecksFactory; | |||
import org.apache.fop.layoutengine.LayoutResult; | |||
import org.apache.fop.layoutengine.TestFilesConfiguration; | |||
import org.apache.fop.layoutmgr.ElementListObserver; | |||
import org.apache.fop.render.Renderer; | |||
import org.apache.fop.render.intermediate.IFContext; | |||
import org.apache.fop.render.intermediate.IFRenderer; | |||
import org.apache.fop.render.intermediate.IFSerializer; | |||
import org.apache.fop.render.xml.XMLRenderer; | |||
import org.apache.fop.util.ConsoleEventListenerForTests; | |||
import org.apache.fop.util.DelegatingContentHandler; | |||
// CSOFF: LineLengthCheck | |||
/** | |||
* Test complex script layout (end-to-end) functionality. | |||
*/ | |||
@RunWith(Parameterized.class) | |||
public class ComplexScriptsLayoutTestCase { | |||
private static final boolean DEBUG = false; | |||
private static final String AREA_TREE_OUTPUT_DIRECTORY = "build/test-results/complexscripts"; | |||
private static File areaTreeOutputDir; | |||
private TestAssistant testAssistant = new TestAssistant(); | |||
private LayoutEngineChecksFactory layoutEngineChecksFactory = new LayoutEngineChecksFactory(); | |||
private TestFilesConfiguration testConfig; | |||
private File testFile; | |||
private IFTester ifTester; | |||
private TransformerFactory tfactory = TransformerFactory.newInstance(); | |||
public ComplexScriptsLayoutTestCase(TestFilesConfiguration testConfig, File testFile) { | |||
this.testConfig = testConfig; | |||
this.testFile = testFile; | |||
this.ifTester = new IFTester(tfactory, areaTreeOutputDir); | |||
} | |||
@Parameters | |||
public static Collection<Object[]> getParameters() throws IOException { | |||
return getTestFiles(); | |||
} | |||
@BeforeClass | |||
public static void makeDirAndRegisterDebugHelper() throws IOException { | |||
DebugHelper.registerStandardElementListObservers(); | |||
areaTreeOutputDir = new File(AREA_TREE_OUTPUT_DIRECTORY); | |||
if (!areaTreeOutputDir.mkdirs() && !areaTreeOutputDir.exists()) { | |||
throw new IOException("Failed to create the AT output directory at " + AREA_TREE_OUTPUT_DIRECTORY); | |||
} | |||
} | |||
@Test | |||
public void runTest() throws TransformerException, SAXException, IOException, ParserConfigurationException { | |||
DOMResult domres = new DOMResult(); | |||
ElementListCollector elCollector = new ElementListCollector(); | |||
ElementListObserver.addObserver(elCollector); | |||
Fop fop; | |||
FopFactory effFactory; | |||
EventsChecker eventsChecker = new EventsChecker(new ConsoleEventListenerForTests(testFile.getName(), EventSeverity.WARN)); | |||
try { | |||
Document testDoc = testAssistant.loadTestCase(testFile); | |||
effFactory = getFopFactory(testConfig, testDoc); | |||
// Setup Transformer to convert the testcase XML to XSL-FO | |||
Transformer transformer = testAssistant.getTestcase2FOStylesheet().newTransformer(); | |||
Source src = new DOMSource(testDoc); | |||
// Setup Transformer to convert the area tree to a DOM | |||
TransformerHandler athandler; | |||
athandler = testAssistant.getTransformerFactory().newTransformerHandler(); | |||
athandler.setResult(domres); | |||
// Setup FOP for area tree rendering | |||
FOUserAgent ua = effFactory.newFOUserAgent(); | |||
ua.getEventBroadcaster().addEventListener(eventsChecker); | |||
XMLRenderer atrenderer = new XMLRenderer(ua); | |||
Renderer targetRenderer = ua.getRendererFactory().createRenderer(ua, MimeConstants.MIME_PDF); | |||
atrenderer.mimicRenderer(targetRenderer); | |||
atrenderer.setContentHandler(athandler); | |||
ua.setRendererOverride(atrenderer); | |||
fop = effFactory.newFop(ua); | |||
SAXResult fores = new SAXResult(fop.getDefaultHandler()); | |||
transformer.transform(src, fores); | |||
} finally { | |||
ElementListObserver.removeObserver(elCollector); | |||
} | |||
Document doc = (Document)domres.getNode(); | |||
if (areaTreeOutputDir != null) { | |||
testAssistant.saveDOM(doc, new File(areaTreeOutputDir, testFile.getName() + ".at.xml")); | |||
} | |||
FormattingResults results = fop.getResults(); | |||
LayoutResult result = new LayoutResult(doc, elCollector, results); | |||
checkAll(effFactory, testFile, result, eventsChecker); | |||
} | |||
private FopFactory getFopFactory(TestFilesConfiguration testConfig, Document testDoc) throws SAXException, IOException { | |||
EnvironmentProfile profile = EnvironmentalProfileFactory.createRestrictedIO( | |||
testConfig.getTestDirectory().getParentFile().toURI(), | |||
ResourceResolverFactory.createDefaultResourceResolver()); | |||
InputStream confStream = | |||
new FopConfBuilder().setStrictValidation(true) | |||
.setFontBaseURI("test/resources/fonts/ttf/") | |||
.startRendererConfig(PDFRendererConfBuilder.class) | |||
.startFontsConfig() | |||
.startFont(null, "DejaVuLGCSerif.ttf") | |||
.addTriplet("DejaVu LGC Serif", "normal", "normal") | |||
.endFont() | |||
.endFontConfig() | |||
.endRendererConfig().build(); | |||
FopFactoryBuilder builder = | |||
new FopConfParser(confStream, new File(".").toURI(), profile).getFopFactoryBuilder(); | |||
// builder.setStrictFOValidation(isStrictValidation(testDoc)); | |||
// builder.getFontManager().setBase14KerningEnabled(isBase14KerningEnabled(testDoc)); | |||
return builder.build(); | |||
} | |||
private void checkAll(FopFactory fopFactory, File testFile, LayoutResult result, EventsChecker eventsChecker) throws TransformerException { | |||
Element testRoot = testAssistant.getTestRoot(testFile); | |||
NodeList nodes; | |||
nodes = testRoot.getElementsByTagName("at-checks"); | |||
if (nodes.getLength() > 0) { | |||
Element atChecks = (Element)nodes.item(0); | |||
doATChecks(atChecks, result); | |||
} | |||
nodes = testRoot.getElementsByTagName("if-checks"); | |||
if (nodes.getLength() > 0) { | |||
Element ifChecks = (Element)nodes.item(0); | |||
Document ifDocument = createIF(fopFactory, testFile, result.getAreaTree()); | |||
ifTester.doIFChecks(testFile.getName(), ifChecks, ifDocument); | |||
} | |||
nodes = testRoot.getElementsByTagName("event-checks"); | |||
if (nodes.getLength() > 0) { | |||
Element eventChecks = (Element) nodes.item(0); | |||
doEventChecks(eventChecks, eventsChecker); | |||
} | |||
eventsChecker.emitUncheckedEvents(); | |||
} | |||
private Document createIF(FopFactory fopFactory, File testFile, Document areaTreeXML) throws TransformerException { | |||
try { | |||
FOUserAgent ua = fopFactory.newFOUserAgent(); | |||
ua.getEventBroadcaster().addEventListener(new ConsoleEventListenerForTests(testFile.getName(), EventSeverity.WARN)); | |||
IFRenderer ifRenderer = new IFRenderer(ua); | |||
IFSerializer serializer = new IFSerializer(new IFContext(ua)); | |||
DOMResult result = new DOMResult(); | |||
serializer.setResult(result); | |||
ifRenderer.setDocumentHandler(serializer); | |||
ua.setRendererOverride(ifRenderer); | |||
FontInfo fontInfo = new FontInfo(); | |||
//Construct the AreaTreeModel that will received the individual pages | |||
final AreaTreeModel treeModel = new RenderPagesModel(ua, null, fontInfo, null); | |||
//Iterate over all intermediate files | |||
AreaTreeParser parser = new AreaTreeParser(); | |||
ContentHandler handler = parser.getContentHandler(treeModel, ua); | |||
DelegatingContentHandler proxy = new DelegatingContentHandler() { | |||
public void endDocument() throws SAXException { | |||
super.endDocument(); | |||
treeModel.endDocument(); | |||
} | |||
}; | |||
proxy.setDelegateContentHandler(handler); | |||
Transformer transformer = tfactory.newTransformer(); | |||
transformer.transform(new DOMSource(areaTreeXML), new SAXResult(proxy)); | |||
return (Document)result.getNode(); | |||
} catch (Exception e) { | |||
throw new TransformerException("Error while generating intermediate format file: " + e.getMessage(), e); | |||
} | |||
} | |||
private void doATChecks(Element checksRoot, LayoutResult result) { | |||
List<LayoutEngineCheck> checks = layoutEngineChecksFactory.createCheckList(checksRoot); | |||
if (checks.size() == 0) { | |||
throw new RuntimeException("No available area tree check"); | |||
} | |||
for (LayoutEngineCheck check : checks) { | |||
check.check(result); | |||
} | |||
} | |||
private void doEventChecks(Element eventChecks, EventsChecker eventsChecker) { | |||
NodeList events = eventChecks.getElementsByTagName("event"); | |||
for (int i = 0; i < events.getLength(); i++) { | |||
Element event = (Element) events.item(i); | |||
NamedNodeMap attributes = event.getAttributes(); | |||
Map<String, String> params = new HashMap<String, String>(); | |||
String key = null; | |||
for (int j = 0; j < attributes.getLength(); j++) { | |||
Node attribute = attributes.item(j); | |||
String name = attribute.getNodeName(); | |||
String value = attribute.getNodeValue(); | |||
if ("key".equals(name)) { | |||
key = value; | |||
} else { | |||
params.put(name, value); | |||
} | |||
} | |||
if (key == null) { | |||
throw new RuntimeException("An event element must have a \"key\" attribute"); | |||
} | |||
eventsChecker.checkEvent(key, params); | |||
} | |||
} | |||
private static Collection<Object[]> getTestFiles(TestFilesConfiguration testConfig) { | |||
File mainDir = testConfig.getTestDirectory(); | |||
IOFileFilter filter; | |||
String single = testConfig.getSingleTest(); | |||
String startsWith = testConfig.getStartsWith(); | |||
if (single != null) { | |||
filter = new NameFileFilter(single); | |||
} else if (startsWith != null) { | |||
filter = new PrefixFileFilter(startsWith); | |||
filter = new AndFileFilter(filter, new SuffixFileFilter(testConfig.getFileSuffix())); | |||
} else { | |||
filter = new SuffixFileFilter(testConfig.getFileSuffix()); | |||
} | |||
String testset = testConfig.getTestSet(); | |||
Collection<File> files = FileUtils.listFiles(new File(mainDir, testset), filter, TrueFileFilter.INSTANCE); | |||
if (testConfig.hasPrivateTests()) { | |||
Collection<File> privateFiles = | |||
FileUtils.listFiles(new File(mainDir, "private-testcases"), filter, TrueFileFilter.INSTANCE); | |||
files.addAll(privateFiles); | |||
} | |||
Collection<Object[]> parametersForJUnit4 = new ArrayList<Object[]>(); | |||
int index = 0; | |||
for (File f : files) { | |||
parametersForJUnit4.add(new Object[] { testConfig, f }); | |||
if (DEBUG) { | |||
System.out.println(String.format("%3d %s", index++, f)); | |||
} | |||
} | |||
return parametersForJUnit4; | |||
} | |||
private static Collection<Object[]> getTestFiles() { | |||
String testSet = System.getProperty("fop.complexscripts.testset"); | |||
testSet = (testSet != null ? testSet : "standard") + "-testcases"; | |||
return getTestFiles(testSet); | |||
} | |||
private static Collection<Object[]> getTestFiles(String testSetName) { | |||
TestFilesConfiguration.Builder builder = new TestFilesConfiguration.Builder(); | |||
builder.testDir("test/resources/complexscripts/layout") | |||
.singleProperty("fop.complexscripts.single") | |||
.startsWithProperty("fop.complexscripts.starts-with") | |||
.suffix(".xml") | |||
.testSet(testSetName) | |||
.privateTestsProperty("fop.complexscripts.private"); | |||
return getTestFiles(builder.build()); | |||
} | |||
private static class EventsChecker implements EventListener { | |||
private final List<Event> events = new ArrayList<Event>(); | |||
private final EventListener defaultListener; | |||
public EventsChecker(EventListener fallbackListener) { | |||
this.defaultListener = fallbackListener; | |||
} | |||
public void processEvent(Event event) { | |||
events.add(event); | |||
} | |||
public void checkEvent(String expectedKey, Map<String, String> expectedParams) { | |||
boolean eventFound = false; | |||
for (Iterator<Event> iter = events.iterator(); !eventFound && iter.hasNext();) { | |||
Event event = iter.next(); | |||
if (event.getEventKey().equals(expectedKey)) { | |||
eventFound = true; | |||
iter.remove(); | |||
checkParameters(event, expectedParams); | |||
} | |||
} | |||
if (!eventFound) { | |||
fail("Event did not occur but was expected to: " + expectedKey + expectedParams); | |||
} | |||
} | |||
private void checkParameters(Event event, Map<String, String> expectedParams) { | |||
Map<String, Object> actualParams = event.getParams(); | |||
for (Map.Entry<String, String> expectedParam : expectedParams.entrySet()) { | |||
assertTrue("Event \"" + event.getEventKey() | |||
+ "\" is missing parameter \"" + expectedParam.getKey() + '"', | |||
actualParams.containsKey(expectedParam.getKey())); | |||
assertEquals("Event \"" + event.getEventKey() | |||
+ "\" has wrong value for parameter \"" + expectedParam.getKey() + "\";", | |||
actualParams.get(expectedParam.getKey()).toString(), | |||
expectedParam.getValue()); | |||
} | |||
} | |||
public void emitUncheckedEvents() { | |||
for (Event event : events) { | |||
defaultListener.processEvent(event); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,32 @@ | |||
/* | |||
* 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$ */ | |||
package org.apache.fop.complexscripts.layout; | |||
import org.junit.runner.RunWith; | |||
import org.junit.runners.Suite; | |||
import org.junit.runners.Suite.SuiteClasses; | |||
/** | |||
* Test suite for running complex script layout tests under JUnit control. | |||
*/ | |||
@RunWith(Suite.class) | |||
@SuiteClasses(ComplexScriptsLayoutTestCase.class) | |||
public class ComplexScriptsLayoutTestSuite { | |||
} |
@@ -116,14 +116,12 @@ public class TestAssistant { | |||
} | |||
public FopFactory getFopFactory(Document testDoc) { | |||
boolean base14KerningEnabled = isBase14KerningEnabled(testDoc); | |||
boolean strictValidation = isStrictValidation(testDoc); | |||
EnvironmentProfile envProfile = EnvironmentalProfileFactory.createRestrictedIO( | |||
testDir.getParentFile().toURI(), | |||
ResourceResolverFactory.createDefaultResourceResolver()); | |||
FopFactoryBuilder builder = new FopFactoryBuilder(envProfile); | |||
builder.setStrictFOValidation(strictValidation); | |||
builder.getFontManager().setBase14KerningEnabled(base14KerningEnabled); | |||
builder.setStrictFOValidation(isStrictValidation(testDoc)); | |||
builder.getFontManager().setBase14KerningEnabled(isBase14KerningEnabled(testDoc)); | |||
return builder.build(); | |||
} | |||
@@ -26,9 +26,9 @@ import org.apache.fop.check.ChecksFactory; | |||
/** | |||
* A factory class for creating {@link LayoutEngineCheck} instances. | |||
*/ | |||
final class LayoutEngineChecksFactory extends ChecksFactory<LayoutEngineCheck> { | |||
public final class LayoutEngineChecksFactory extends ChecksFactory<LayoutEngineCheck> { | |||
LayoutEngineChecksFactory() { | |||
public LayoutEngineChecksFactory() { | |||
registerCheckFactory("true", new CheckFactory<LayoutEngineCheck>() { | |||
public LayoutEngineCheck createCheck(Element element) { |
@@ -0,0 +1,43 @@ | |||
<?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$ --> | |||
<testcase> | |||
<info> | |||
<p> | |||
Test fix for https://issues.apache.org/jira/browse/FOP-2213. | |||
</p> | |||
</info> | |||
<fo> | |||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||
<fo:layout-master-set> | |||
<fo:simple-page-master master-name="page" | |||
page-height="300pt" page-width="400pt" margin="10pt"> | |||
<fo:region-body display-align="center"/> | |||
</fo:simple-page-master> | |||
</fo:layout-master-set> | |||
<fo:page-sequence master-reference="page"> | |||
<fo:flow flow-name="xsl-region-body"> | |||
<fo:block font-size="200pt" text-align="center" font-family="DejaVu LGC Serif">Y.</fo:block> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
</fo:root> | |||
</fo> | |||
<checks> | |||
<eval expected="2 Z2 -25600 Z5" xpath="(//word)[1]/@position-adjust"/> | |||
</checks> | |||
</testcase> |
@@ -0,0 +1,53 @@ | |||
<?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$ --> | |||
<!-- This stylesheet extracts the checks from the testcase so the list of checks can be built in Java code. --> | |||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||
<xsl:variable name="basic-checks" select="document('basic-checks.xml')/checks/*" /> | |||
<xsl:template match="testcase"> | |||
<checks> | |||
<xsl:apply-templates select="checks"/> | |||
<xsl:apply-templates select="if-checks"/> | |||
<xsl:apply-templates select="event-checks"/> | |||
</checks> | |||
</xsl:template> | |||
<xsl:template match="checks"> | |||
<at-checks> | |||
<xsl:copy-of select="$basic-checks" /> | |||
<xsl:copy-of select="*" /> | |||
</at-checks> | |||
</xsl:template> | |||
<xsl:template match="if-checks"> | |||
<if-checks> | |||
<xsl:copy-of select="*"/> | |||
</if-checks> | |||
</xsl:template> | |||
<xsl:template match="event-checks"> | |||
<event-checks> | |||
<xsl:copy-of select="*"/> | |||
</event-checks> | |||
</xsl:template> | |||
<xsl:template match="text()" /> | |||
</xsl:stylesheet> |
@@ -0,0 +1,62 @@ | |||
<?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$ --> | |||
<!-- This stylesheet extracts the FO part from the testcase so it can be passed to FOP for layout. --> | |||
<!-- | |||
Variable substitution: | |||
For any attribute value that starts with a "##" the stylesheet looks for an element with the variable | |||
name under /testcase/variables, ex. "##img" looks for /testcase/variables/img and uses its element | |||
value as subsitution value. | |||
--> | |||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||
<xsl:template match="testcase"> | |||
<xsl:apply-templates select="fo/*" mode="copy"/> | |||
</xsl:template> | |||
<xsl:template match="node()" mode="copy"> | |||
<xsl:copy> | |||
<xsl:apply-templates select="@*|node()" mode="copy"/> | |||
</xsl:copy> | |||
</xsl:template> | |||
<xsl:template match="@*" mode="copy"> | |||
<xsl:choose> | |||
<xsl:when test="starts-with(., '##')"> | |||
<!-- variable substitution --> | |||
<xsl:variable name="nodename" select="name()"/> | |||
<xsl:variable name="varname" select="substring(., 3)"/> | |||
<xsl:choose> | |||
<xsl:when test="boolean(//variables/child::*[local-name() = $varname])"> | |||
<xsl:attribute name="{name(.)}"> | |||
<xsl:value-of select="//variables/child::*[local-name() = $varname]"/> | |||
</xsl:attribute> | |||
</xsl:when> | |||
<xsl:otherwise> | |||
<!-- if variable isn't defined, just copy --> | |||
<xsl:copy-of select="." /> | |||
</xsl:otherwise> | |||
</xsl:choose> | |||
</xsl:when> | |||
<xsl:otherwise> | |||
<xsl:copy-of select="." /> | |||
</xsl:otherwise> | |||
</xsl:choose> | |||
</xsl:template> | |||
</xsl:stylesheet> |