From: Glenn Adams Date: Tue, 9 Sep 2014 23:43:58 +0000 (+0000) Subject: FOP-2213 use kern table when no GPOS kern lookups are present X-Git-Tag: fop-2_0~56 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=6300064cb5a8b81d91c4a105f74315fd11ada39d;p=xmlgraphics-fop.git FOP-2213 use kern table when no GPOS kern lookups are present 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-ffa450edef68 --- diff --git a/build.xml b/build.xml index e1899926e..e5d9278d0 100644 --- a/build.xml +++ b/build.xml @@ -898,9 +898,12 @@ list of possible build targets. + + + + junit-complexscripts, junit-complexscripts-layout"/> 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))) { diff --git a/src/java/org/apache/fop/complexscripts/fonts/OTFLanguage.java b/src/java/org/apache/fop/complexscripts/fonts/OTFLanguage.java new file mode 100644 index 000000000..49f67df4e --- /dev/null +++ b/src/java/org/apache/fop/complexscripts/fonts/OTFLanguage.java @@ -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; + +/** + *

Language system tags defined by OTF specification. Note that this set and their + * values do not correspond with ISO639* or any other language registry.

+ * + *

This work was originally authored by Glenn Adams (gadams@apache.org).

+ */ +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() { + } +} diff --git a/src/java/org/apache/fop/complexscripts/fonts/OTFScript.java b/src/java/org/apache/fop/complexscripts/fonts/OTFScript.java new file mode 100644 index 000000000..a43f1c5fb --- /dev/null +++ b/src/java/org/apache/fop/complexscripts/fonts/OTFScript.java @@ -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; + +/** + *

Script tags defined by OTF specification. Note that this set and their + * values do not correspond with ISO 15924 or Unicode Script names.

+ * + *

This work was originally authored by Glenn Adams (gadams@apache.org).

+ */ +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() { + } +} diff --git a/src/java/org/apache/fop/fonts/Font.java b/src/java/org/apache/fop/fonts/Font.java index 296d2ef8e..305e8f78a 100644 --- a/src/java/org/apache/fop/fonts/Font.java +++ b/src/java/org/apache/fop/fonts/Font.java @@ -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 diff --git a/src/java/org/apache/fop/fonts/FontMetrics.java b/src/java/org/apache/fop/fonts/FontMetrics.java index ed59cf5af..4b1fb1f1f 100644 --- a/src/java/org/apache/fop/fonts/FontMetrics.java +++ b/src/java/org/apache/fop/fonts/FontMetrics.java @@ -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); } diff --git a/src/java/org/apache/fop/fonts/GlyphMapping.java b/src/java/org/apache/fop/fonts/GlyphMapping.java index 8c80eeb7c..59bf9f148 100644 --- a/src/java/org/apache/fop/fonts/GlyphMapping.java +++ b/src/java/org/apache/fop/fonts/GlyphMapping.java @@ -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; diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java index acce1e0f9..fb0d8f06f 100644 --- a/src/java/org/apache/fop/fonts/LazyFont.java +++ b/src/java/org/apache/fop/fonts/LazyFont.java @@ -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} diff --git a/src/java/org/apache/fop/fonts/MultiByteFont.java b/src/java/org/apache/fop/fonts/MultiByteFont.java index 718a14fb2..5b2f62a26 100644 --- a/src/java/org/apache/fop/fonts/MultiByteFont.java +++ b/src/java/org/apache/fop/fonts/MultiByteFont.java @@ -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 getWidthsMap() { return null; } diff --git a/src/java/org/apache/fop/fonts/Typeface.java b/src/java/org/apache/fop/fonts/Typeface.java index 571c402bf..3232d7605 100644 --- a/src/java/org/apache/fop/fonts/Typeface.java +++ b/src/java/org/apache/fop/fonts/Typeface.java @@ -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. diff --git a/test/java/org/apache/fop/complexscripts/layout/ComplexScriptsLayoutTestCase.java b/test/java/org/apache/fop/complexscripts/layout/ComplexScriptsLayoutTestCase.java new file mode 100644 index 000000000..01dbaea57 --- /dev/null +++ b/test/java/org/apache/fop/complexscripts/layout/ComplexScriptsLayoutTestCase.java @@ -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 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 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 params = new HashMap(); + 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 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 files = FileUtils.listFiles(new File(mainDir, testset), filter, TrueFileFilter.INSTANCE); + if (testConfig.hasPrivateTests()) { + Collection privateFiles = + FileUtils.listFiles(new File(mainDir, "private-testcases"), filter, TrueFileFilter.INSTANCE); + files.addAll(privateFiles); + } + Collection parametersForJUnit4 = new ArrayList(); + 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 getTestFiles() { + String testSet = System.getProperty("fop.complexscripts.testset"); + testSet = (testSet != null ? testSet : "standard") + "-testcases"; + return getTestFiles(testSet); + } + + private static Collection 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 events = new ArrayList(); + 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 expectedParams) { + boolean eventFound = false; + for (Iterator 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 expectedParams) { + Map actualParams = event.getParams(); + for (Map.Entry 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); + } + } + } + +} diff --git a/test/java/org/apache/fop/complexscripts/layout/ComplexScriptsLayoutTestSuite.java b/test/java/org/apache/fop/complexscripts/layout/ComplexScriptsLayoutTestSuite.java new file mode 100644 index 000000000..e55ead635 --- /dev/null +++ b/test/java/org/apache/fop/complexscripts/layout/ComplexScriptsLayoutTestSuite.java @@ -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 { +} diff --git a/test/java/org/apache/fop/intermediate/TestAssistant.java b/test/java/org/apache/fop/intermediate/TestAssistant.java index 2b138de55..d13f88959 100644 --- a/test/java/org/apache/fop/intermediate/TestAssistant.java +++ b/test/java/org/apache/fop/intermediate/TestAssistant.java @@ -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(); } diff --git a/test/java/org/apache/fop/layoutengine/LayoutEngineChecksFactory.java b/test/java/org/apache/fop/layoutengine/LayoutEngineChecksFactory.java index bea54c5f8..9883a9a74 100644 --- a/test/java/org/apache/fop/layoutengine/LayoutEngineChecksFactory.java +++ b/test/java/org/apache/fop/layoutengine/LayoutEngineChecksFactory.java @@ -26,9 +26,9 @@ import org.apache.fop.check.ChecksFactory; /** * A factory class for creating {@link LayoutEngineCheck} instances. */ -final class LayoutEngineChecksFactory extends ChecksFactory { +public final class LayoutEngineChecksFactory extends ChecksFactory { - LayoutEngineChecksFactory() { + public LayoutEngineChecksFactory() { registerCheckFactory("true", new CheckFactory() { public LayoutEngineCheck createCheck(Element element) { diff --git a/test/resources/complexscripts/layout/standard-testcases/inline_kerning_jira2213.xml b/test/resources/complexscripts/layout/standard-testcases/inline_kerning_jira2213.xml new file mode 100644 index 000000000..8eb4dc0c2 --- /dev/null +++ b/test/resources/complexscripts/layout/standard-testcases/inline_kerning_jira2213.xml @@ -0,0 +1,43 @@ + + + + + +

+ Test fix for https://issues.apache.org/jira/browse/FOP-2213. +

+
+ + + + + + + + + + Y. + + + + + + + +
diff --git a/test/resources/complexscripts/layout/testcase2checks.xsl b/test/resources/complexscripts/layout/testcase2checks.xsl new file mode 100644 index 000000000..25dfcc810 --- /dev/null +++ b/test/resources/complexscripts/layout/testcase2checks.xsl @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/resources/complexscripts/layout/testcase2fo.xsl b/test/resources/complexscripts/layout/testcase2fo.xsl new file mode 100644 index 000000000..522f53fa7 --- /dev/null +++ b/test/resources/complexscripts/layout/testcase2fo.xsl @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +