From f782538e9310c88f96c89c1d48102a1b74946f1a Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Sun, 1 Jun 2014 23:18:03 +0100 Subject: [PATCH] bug 1014639 - part 2 - use IrishCasing in nsCaseTransformTextRunFactory::TransformString to provide correct Irish uppercasing. r=smontagu --- content/base/src/nsGkAtomList.h | 3 +- layout/generic/nsTextRunTransformations.cpp | 70 ++++++++++++++++++++- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index c7ad63de0e11..ca15e67032f7 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -2031,8 +2031,9 @@ GK_ATOM(x_symbol, "x-symbol") GK_ATOM(az, "az") GK_ATOM(ba, "ba") GK_ATOM(crh, "crh") -GK_ATOM(nl, "nl") GK_ATOM(el, "el") +GK_ATOM(ga_ie, "ga-ie") +GK_ATOM(nl, "nl") // Names for editor transactions GK_ATOM(TypingTxnName, "Typing") diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp index d5328cc874a1..db955571a382 100644 --- a/layout/generic/nsTextRunTransformations.cpp +++ b/layout/generic/nsTextRunTransformations.cpp @@ -18,6 +18,7 @@ #include "nsIPersistentProperties2.h" #include "nsNetUtil.h" #include "GreekCasing.h" +#include "IrishCasing.h" // Unicode characters needing special casing treatment in tr/az languages #define LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE 0x0130 @@ -225,9 +226,10 @@ GetParametersForInner(nsTransformedTextRun* aTextRun, uint32_t* aFlags, // same setting here, if the behavior is shared by other languages. enum LanguageSpecificCasingBehavior { eLSCB_None, // default non-lang-specific behavior - eLSCB_Turkish, // preserve dotted/dotless-i distinction in uppercase eLSCB_Dutch, // treat "ij" digraph as a unit for capitalization - eLSCB_Greek // strip accent when uppercasing Greek vowels + eLSCB_Greek, // strip accent when uppercasing Greek vowels + eLSCB_Irish, // keep prefix letters as lowercase when uppercasing Irish + eLSCB_Turkish // preserve dotted/dotless-i distinction in uppercase }; static LanguageSpecificCasingBehavior @@ -246,6 +248,9 @@ GetCasingFor(const nsIAtom* aLang) if (aLang == nsGkAtoms::el) { return eLSCB_Greek; } + if (aLang == nsGkAtoms::ga_ie) { + return eLSCB_Irish; + } return eLSCB_None; } @@ -279,6 +284,8 @@ nsCaseTransformTextRunFactory::TransformString( LanguageSpecificCasingBehavior languageSpecificCasing = GetCasingFor(lang); mozilla::GreekCasing::State greekState; + mozilla::IrishCasing::State irishState; + uint32_t irishMark = uint32_t(-1); // location of possible prefix letter(s) for (uint32_t i = 0; i < length; ++i) { uint32_t ch = str[i]; @@ -293,11 +300,14 @@ nsCaseTransformTextRunFactory::TransformString( lang = styleContext->StyleFont()->mLanguage; languageSpecificCasing = GetCasingFor(lang); greekState.Reset(); + irishState.Reset(); + irishMark = uint32_t(-1); } } int extraChars = 0; const mozilla::unicode::MultiCharMapping *mcm; + bool inhibitBreakBefore = false; // have we just deleted preceding hyphen? if (NS_IS_HIGH_SURROGATE(ch) && i < length - 1 && NS_IS_LOW_SURROGATE(str[i + 1])) { @@ -401,6 +411,59 @@ nsCaseTransformTextRunFactory::TransformString( break; } + if (languageSpecificCasing == eLSCB_Irish) { + bool mark; + uint8_t action; + ch = mozilla::IrishCasing::UpperCase(ch, irishState, mark, action); + if (mark) { + irishMark = aConvertedString.Length(); + break; + } else if (action) { + nsString& str = aConvertedString; // shorthand + switch (action) { + case 1: + // lowercase a single prefix letter + NS_ASSERTION(str.Length() > 0 && irishMark < str.Length(), + "bad irishMark!"); + str.SetCharAt(ToLowerCase(str[irishMark]), irishMark); + irishMark = uint32_t(-1); + break; + case 2: + // lowercase two prefix letters (immediately before current pos) + NS_ASSERTION(str.Length() >= 2 && irishMark == str.Length() - 2, + "bad irishMark!"); + str.SetCharAt(ToLowerCase(str[irishMark]), irishMark); + str.SetCharAt(ToLowerCase(str[irishMark + 1]), irishMark + 1); + irishMark = uint32_t(-1); + break; + case 3: + // lowercase one prefix letter, and delete following hyphen + // (which must be the immediately-preceding char) + NS_ASSERTION(str.Length() >= 2 && irishMark == str.Length() - 2, + "bad irishMark!"); + str.Replace(irishMark, 2, ToLowerCase(str[irishMark])); + aDeletedCharsArray[irishMark + 1] = true; + // Remove the trailing entries (corresponding to the deleted hyphen) + // from the auxiliary arrays. + aCharsToMergeArray.SetLength(aCharsToMergeArray.Length() - 1); + if (aTextRun) { + aStyleArray->SetLength(aStyleArray->Length() - 1); + aCanBreakBeforeArray->SetLength(aCanBreakBeforeArray->Length() - 1); + inhibitBreakBefore = true; + } + mergeNeeded = true; + irishMark = uint32_t(-1); + break; + } + // ch has been set to the uppercase for current char; + // No need to check for SpecialUpper here as none of the characters + // that could trigger an Irish casing action have special mappings. + break; + } + // If we didn't have any special action to perform, fall through + // to check for special uppercase (ß) + } + mcm = mozilla::unicode::SpecialUpper(ch); if (mcm) { int j = 0; @@ -468,7 +531,8 @@ nsCaseTransformTextRunFactory::TransformString( aCharsToMergeArray.AppendElement(false); if (aTextRun) { aStyleArray->AppendElement(styleContext); - aCanBreakBeforeArray->AppendElement(aTextRun->CanBreakLineBefore(i)); + aCanBreakBeforeArray->AppendElement(inhibitBreakBefore ? false : + aTextRun->CanBreakLineBefore(i)); } if (IS_IN_BMP(ch)) {