12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "CounterStyleManager.h"
- #include "mozilla/ArenaObjectID.h"
- #include "mozilla/ArrayUtils.h"
- #include "mozilla/CheckedInt.h"
- #include "mozilla/MathAlgorithms.h"
- #include "mozilla/Types.h"
- #include "mozilla/WritingModes.h"
- #include "nsCSSRules.h"
- #include "nsString.h"
- #include "nsStyleSet.h"
- #include "nsTArray.h"
- #include "nsTHashtable.h"
- #include "nsUnicodeProperties.h"
- #include "mozilla/StyleSetHandle.h"
- #include "mozilla/StyleSetHandleInlines.h"
- namespace mozilla {
- struct AdditiveSymbol
- {
- CounterValue weight;
- nsString symbol;
- };
- struct NegativeType
- {
- nsString before, after;
- };
- struct PadType
- {
- int32_t width;
- nsString symbol;
- };
- // This limitation will be applied to some systems, and pad descriptor.
- // Any initial representation generated by symbolic or additive which is
- // longer than this limitation will be dropped. If any pad is longer
- // than this, the whole counter text will be dropped as well.
- // The spec requires user agents to support at least 60 Unicode code-
- // points for counter text. However, this constant only limits the
- // length in 16-bit units. So it has to be at least 120, since code-
- // points outside the BMP will need 2 16-bit units.
- #define LENGTH_LIMIT 150
- static bool
- GetCyclicCounterText(CounterValue aOrdinal,
- nsSubstring& aResult,
- const nsTArray<nsString>& aSymbols)
- {
- MOZ_ASSERT(aSymbols.Length() >= 1,
- "No symbol available for cyclic counter.");
- auto n = aSymbols.Length();
- CounterValue index = (aOrdinal - 1) % n;
- aResult = aSymbols[index >= 0 ? index : index + n];
- return true;
- }
- static bool
- GetFixedCounterText(CounterValue aOrdinal,
- nsSubstring& aResult,
- CounterValue aStart,
- const nsTArray<nsString>& aSymbols)
- {
- CounterValue index = aOrdinal - aStart;
- if (index >= 0 && index < CounterValue(aSymbols.Length())) {
- aResult = aSymbols[index];
- return true;
- } else {
- return false;
- }
- }
- static bool
- GetSymbolicCounterText(CounterValue aOrdinal,
- nsSubstring& aResult,
- const nsTArray<nsString>& aSymbols)
- {
- MOZ_ASSERT(aSymbols.Length() >= 1,
- "No symbol available for symbolic counter.");
- MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal.");
- if (aOrdinal == 0) {
- return false;
- }
- aResult.Truncate();
- auto n = aSymbols.Length();
- const nsString& symbol = aSymbols[(aOrdinal - 1) % n];
- size_t len = (aOrdinal + n - 1) / n;
- auto symbolLength = symbol.Length();
- if (symbolLength > 0) {
- if (len > LENGTH_LIMIT || symbolLength > LENGTH_LIMIT ||
- len * symbolLength > LENGTH_LIMIT) {
- return false;
- }
- for (size_t i = 0; i < len; ++i) {
- aResult.Append(symbol);
- }
- }
- return true;
- }
- static bool
- GetAlphabeticCounterText(CounterValue aOrdinal,
- nsSubstring& aResult,
- const nsTArray<nsString>& aSymbols)
- {
- MOZ_ASSERT(aSymbols.Length() >= 2,
- "Too few symbols for alphabetic counter.");
- MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal.");
- if (aOrdinal == 0) {
- return false;
- }
- auto n = aSymbols.Length();
- // The precise length of this array should be
- // ceil(log((double) aOrdinal / n * (n - 1) + 1) / log(n)).
- // The max length is slightly smaller than which defined below.
- AutoTArray<int32_t, std::numeric_limits<CounterValue>::digits> indexes;
- while (aOrdinal > 0) {
- --aOrdinal;
- indexes.AppendElement(aOrdinal % n);
- aOrdinal /= n;
- }
- aResult.Truncate();
- for (auto i = indexes.Length(); i > 0; --i) {
- aResult.Append(aSymbols[indexes[i - 1]]);
- }
- return true;
- }
- static bool
- GetNumericCounterText(CounterValue aOrdinal,
- nsSubstring& aResult,
- const nsTArray<nsString>& aSymbols)
- {
- MOZ_ASSERT(aSymbols.Length() >= 2,
- "Too few symbols for numeric counter.");
- MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal.");
- if (aOrdinal == 0) {
- aResult = aSymbols[0];
- return true;
- }
- auto n = aSymbols.Length();
- AutoTArray<int32_t, std::numeric_limits<CounterValue>::digits> indexes;
- while (aOrdinal > 0) {
- indexes.AppendElement(aOrdinal % n);
- aOrdinal /= n;
- }
- aResult.Truncate();
- for (auto i = indexes.Length(); i > 0; --i) {
- aResult.Append(aSymbols[indexes[i - 1]]);
- }
- return true;
- }
- static bool
- GetAdditiveCounterText(CounterValue aOrdinal,
- nsSubstring& aResult,
- const nsTArray<AdditiveSymbol>& aSymbols)
- {
- MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal.");
- if (aOrdinal == 0) {
- const AdditiveSymbol& last = aSymbols.LastElement();
- if (last.weight == 0) {
- aResult = last.symbol;
- return true;
- }
- return false;
- }
- aResult.Truncate();
- size_t length = 0;
- for (size_t i = 0, iEnd = aSymbols.Length(); i < iEnd; ++i) {
- const AdditiveSymbol& symbol = aSymbols[i];
- if (symbol.weight == 0) {
- break;
- }
- CounterValue times = aOrdinal / symbol.weight;
- if (times > 0) {
- auto symbolLength = symbol.symbol.Length();
- if (symbolLength > 0) {
- length += times * symbolLength;
- if (times > LENGTH_LIMIT ||
- symbolLength > LENGTH_LIMIT ||
- length > LENGTH_LIMIT) {
- return false;
- }
- for (CounterValue j = 0; j < times; ++j) {
- aResult.Append(symbol.symbol);
- }
- }
- aOrdinal -= times * symbol.weight;
- }
- }
- return aOrdinal == 0;
- }
- static bool
- DecimalToText(CounterValue aOrdinal, nsSubstring& aResult)
- {
- aResult.AppendInt(aOrdinal);
- return true;
- }
- // We know cjk-ideographic need 31 characters to display 99,999,999,999,999,999
- // georgian needs 6 at most
- // armenian needs 12 at most
- // hebrew may need more...
- #define NUM_BUF_SIZE 34
- enum CJKIdeographicLang {
- CHINESE, KOREAN, JAPANESE
- };
- struct CJKIdeographicData {
- char16_t digit[10];
- char16_t unit[3];
- char16_t unit10K[2];
- uint8_t lang;
- bool informal;
- };
- static const CJKIdeographicData gDataJapaneseInformal = {
- { // digit
- 0x3007, 0x4e00, 0x4e8c, 0x4e09, 0x56db,
- 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d
- },
- { 0x5341, 0x767e, 0x5343 }, // unit
- { 0x4e07, 0x5104 }, // unit10K
- JAPANESE, // lang
- true // informal
- };
- static const CJKIdeographicData gDataJapaneseFormal = {
- { // digit
- 0x96f6, 0x58f1, 0x5f10, 0x53c2, 0x56db,
- 0x4f0d, 0x516d, 0x4e03, 0x516b, 0x4e5d
- },
- { 0x62fe, 0x767e, 0x9621 }, // unit
- { 0x842c, 0x5104 }, // unit10K
- JAPANESE, // lang
- false // informal
- };
- static const CJKIdeographicData gDataKoreanHangulFormal = {
- { // digit
- 0xc601, 0xc77c, 0xc774, 0xc0bc, 0xc0ac,
- 0xc624, 0xc721, 0xce60, 0xd314, 0xad6c
- },
- { 0xc2ed, 0xbc31, 0xcc9c }, // unit
- { 0xb9cc, 0xc5b5 }, // unit10K
- KOREAN, // lang
- false // informal
- };
- static const CJKIdeographicData gDataKoreanHanjaInformal = {
- { // digit
- 0x96f6, 0x4e00, 0x4e8c, 0x4e09, 0x56db,
- 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d
- },
- { 0x5341, 0x767e, 0x5343 }, // unit
- { 0x842c, 0x5104 }, // unit10K
- KOREAN, // lang
- true // informal
- };
- static const CJKIdeographicData gDataKoreanHanjaFormal = {
- { // digit
- 0x96f6, 0x58f9, 0x8cb3, 0x53c3, 0x56db,
- 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d
- },
- { 0x62fe, 0x767e, 0x4edf }, // unit
- { 0x842c, 0x5104 }, // unit10K
- KOREAN, // lang
- false // informal
- };
- static const CJKIdeographicData gDataSimpChineseInformal = {
- { // digit
- 0x96f6, 0x4e00, 0x4e8c, 0x4e09, 0x56db,
- 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d
- },
- { 0x5341, 0x767e, 0x5343 }, // unit
- { 0x4e07, 0x4ebf }, // unit10K
- CHINESE, // lang
- true // informal
- };
- static const CJKIdeographicData gDataSimpChineseFormal = {
- { // digit
- 0x96f6, 0x58f9, 0x8d30, 0x53c1, 0x8086,
- 0x4f0d, 0x9646, 0x67d2, 0x634c, 0x7396
- },
- { 0x62fe, 0x4f70, 0x4edf }, // unit
- { 0x4e07, 0x4ebf }, // unit10K
- CHINESE, // lang
- false // informal
- };
- static const CJKIdeographicData gDataTradChineseInformal = {
- { // digit
- 0x96f6, 0x4e00, 0x4e8c, 0x4e09, 0x56db,
- 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d
- },
- { 0x5341, 0x767e, 0x5343 }, // unit
- { 0x842c, 0x5104 }, // unit10K
- CHINESE, // lang
- true // informal
- };
- static const CJKIdeographicData gDataTradChineseFormal = {
- { // digit
- 0x96f6, 0x58f9, 0x8cb3, 0x53c3, 0x8086,
- 0x4f0d, 0x9678, 0x67d2, 0x634c, 0x7396
- },
- { 0x62fe, 0x4f70, 0x4edf }, // unit
- { 0x842c, 0x5104 }, // unit10K
- CHINESE, // lang
- false // informal
- };
- static bool
- CJKIdeographicToText(CounterValue aOrdinal, nsSubstring& aResult,
- const CJKIdeographicData& data)
- {
- NS_ASSERTION(aOrdinal >= 0, "Only accept non-negative ordinal");
- char16_t buf[NUM_BUF_SIZE];
- int32_t idx = NUM_BUF_SIZE;
- int32_t pos = 0;
- bool needZero = (aOrdinal == 0);
- int32_t unitidx = 0, unit10Kidx = 0;
- do {
- unitidx = pos % 4;
- if (unitidx == 0) {
- unit10Kidx = pos / 4;
- }
- auto cur = static_cast<MakeUnsigned<CounterValue>::Type>(aOrdinal) % 10;
- if (cur == 0) {
- if (needZero) {
- needZero = false;
- buf[--idx] = data.digit[0];
- }
- } else {
- if (data.lang == CHINESE) {
- needZero = true;
- }
- if (unit10Kidx != 0) {
- if (data.lang == KOREAN && idx != NUM_BUF_SIZE) {
- buf[--idx] = ' ';
- }
- buf[--idx] = data.unit10K[unit10Kidx - 1];
- }
- if (unitidx != 0) {
- buf[--idx] = data.unit[unitidx - 1];
- }
- if (cur != 1) {
- buf[--idx] = data.digit[cur];
- } else {
- bool needOne = true;
- if (data.informal) {
- switch (data.lang) {
- case CHINESE:
- if (unitidx == 1 &&
- (aOrdinal == 1 || (pos > 4 && aOrdinal % 1000 == 1))) {
- needOne = false;
- }
- break;
- case JAPANESE:
- if (unitidx > 0 &&
- (unitidx != 3 || (pos == 3 && aOrdinal == 1))) {
- needOne = false;
- }
- break;
- case KOREAN:
- if (unitidx > 0 || (pos == 4 && (aOrdinal % 1000) == 1)) {
- needOne = false;
- }
- break;
- }
- }
- if (needOne) {
- buf[--idx] = data.digit[1];
- }
- }
- unit10Kidx = 0;
- }
- aOrdinal /= 10;
- pos++;
- } while (aOrdinal > 0);
- aResult.Assign(buf + idx, NUM_BUF_SIZE - idx);
- return true;
- }
- #define HEBREW_GERESH 0x05F3
- static const char16_t gHebrewDigit[22] =
- {
- // 1 2 3 4 5 6 7 8 9
- 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8,
- // 10 20 30 40 50 60 70 80 90
- 0x05D9, 0x05DB, 0x05DC, 0x05DE, 0x05E0, 0x05E1, 0x05E2, 0x05E4, 0x05E6,
- // 100 200 300 400
- 0x05E7, 0x05E8, 0x05E9, 0x05EA
- };
- static bool
- HebrewToText(CounterValue aOrdinal, nsSubstring& aResult)
- {
- if (aOrdinal < 1 || aOrdinal > 999999) {
- return false;
- }
- bool outputSep = false;
- nsAutoString allText, thousandsGroup;
- do {
- thousandsGroup.Truncate();
- int32_t n3 = aOrdinal % 1000;
- // Process digit for 100 - 900
- for(int32_t n1 = 400; n1 > 0; )
- {
- if( n3 >= n1)
- {
- n3 -= n1;
- thousandsGroup.Append(gHebrewDigit[(n1/100)-1+18]);
- } else {
- n1 -= 100;
- } // if
- } // for
- // Process digit for 10 - 90
- int32_t n2;
- if( n3 >= 10 )
- {
- // Special process for 15 and 16
- if(( 15 == n3 ) || (16 == n3)) {
- // Special rule for religious reason...
- // 15 is represented by 9 and 6, not 10 and 5
- // 16 is represented by 9 and 7, not 10 and 6
- n2 = 9;
- thousandsGroup.Append(gHebrewDigit[ n2 - 1]);
- } else {
- n2 = n3 - (n3 % 10);
- thousandsGroup.Append(gHebrewDigit[(n2/10)-1+9]);
- } // if
- n3 -= n2;
- } // if
- // Process digit for 1 - 9
- if ( n3 > 0)
- thousandsGroup.Append(gHebrewDigit[n3-1]);
- if (outputSep)
- thousandsGroup.Append((char16_t)HEBREW_GERESH);
- if (allText.IsEmpty())
- allText = thousandsGroup;
- else
- allText = thousandsGroup + allText;
- aOrdinal /= 1000;
- outputSep = true;
- } while (aOrdinal >= 1);
- aResult = allText;
- return true;
- }
- // Convert ordinal to Ethiopic numeric representation.
- // The detail is available at http://www.ethiopic.org/Numerals/
- // The algorithm used here is based on the pseudo-code put up there by
- // Daniel Yacob <yacob@geez.org>.
- // Another reference is Unicode 3.0 standard section 11.1.
- #define ETHIOPIC_ONE 0x1369
- #define ETHIOPIC_TEN 0x1372
- #define ETHIOPIC_HUNDRED 0x137B
- #define ETHIOPIC_TEN_THOUSAND 0x137C
- static bool
- EthiopicToText(CounterValue aOrdinal, nsSubstring& aResult)
- {
- if (aOrdinal < 1) {
- return false;
- }
- nsAutoString asciiNumberString; // decimal string representation of ordinal
- DecimalToText(aOrdinal, asciiNumberString);
- uint8_t asciiStringLength = asciiNumberString.Length();
- // If number length is odd, add a leading "0"
- // the leading "0" preconditions the string to always have the
- // leading tens place populated, this avoids a check within the loop.
- // If we didn't add the leading "0", decrement asciiStringLength so
- // it will be equivalent to a zero-based index in both cases.
- if (asciiStringLength & 1) {
- asciiNumberString.Insert(NS_LITERAL_STRING("0"), 0);
- } else {
- asciiStringLength--;
- }
- aResult.Truncate();
- // Iterate from the highest digits to lowest
- // indexFromLeft indexes digits (0 = most significant)
- // groupIndexFromRight indexes pairs of digits (0 = least significant)
- for (uint8_t indexFromLeft = 0, groupIndexFromRight = asciiStringLength >> 1;
- indexFromLeft <= asciiStringLength;
- indexFromLeft += 2, groupIndexFromRight--) {
- uint8_t tensValue = asciiNumberString.CharAt(indexFromLeft) & 0x0F;
- uint8_t unitsValue = asciiNumberString.CharAt(indexFromLeft + 1) & 0x0F;
- uint8_t groupValue = tensValue * 10 + unitsValue;
- bool oddGroup = (groupIndexFromRight & 1);
- // we want to clear ETHIOPIC_ONE when it is superfluous
- if (aOrdinal > 1 &&
- groupValue == 1 && // one without a leading ten
- (oddGroup || indexFromLeft == 0)) { // preceding (100) or leading the sequence
- unitsValue = 0;
- }
- // put it all together...
- if (tensValue) {
- // map onto Ethiopic "tens":
- aResult.Append((char16_t) (tensValue + ETHIOPIC_TEN - 1));
- }
- if (unitsValue) {
- //map onto Ethiopic "units":
- aResult.Append((char16_t) (unitsValue + ETHIOPIC_ONE - 1));
- }
- // Add a separator for all even groups except the last,
- // and for odd groups with non-zero value.
- if (oddGroup) {
- if (groupValue) {
- aResult.Append((char16_t) ETHIOPIC_HUNDRED);
- }
- } else {
- if (groupIndexFromRight) {
- aResult.Append((char16_t) ETHIOPIC_TEN_THOUSAND);
- }
- }
- }
- return true;
- }
- static uint8_t
- GetDefaultSpeakAsForSystem(uint8_t aSystem)
- {
- MOZ_ASSERT(aSystem != NS_STYLE_COUNTER_SYSTEM_EXTENDS,
- "Extends system does not have static default speak-as");
- switch (aSystem) {
- case NS_STYLE_COUNTER_SYSTEM_ALPHABETIC:
- return NS_STYLE_COUNTER_SPEAKAS_SPELL_OUT;
- case NS_STYLE_COUNTER_SYSTEM_CYCLIC:
- return NS_STYLE_COUNTER_SPEAKAS_BULLETS;
- default:
- return NS_STYLE_COUNTER_SPEAKAS_NUMBERS;
- }
- }
- static bool
- SystemUsesNegativeSign(uint8_t aSystem)
- {
- MOZ_ASSERT(aSystem != NS_STYLE_COUNTER_SYSTEM_EXTENDS,
- "Cannot check this for extending style");
- switch (aSystem) {
- case NS_STYLE_COUNTER_SYSTEM_SYMBOLIC:
- case NS_STYLE_COUNTER_SYSTEM_ALPHABETIC:
- case NS_STYLE_COUNTER_SYSTEM_NUMERIC:
- case NS_STYLE_COUNTER_SYSTEM_ADDITIVE:
- return true;
- default:
- return false;
- }
- }
- class BuiltinCounterStyle : public CounterStyle
- {
- public:
- friend class CounterStyleManager;
- // will be initialized by CounterStyleManager::InitializeBuiltinCounterStyles
- constexpr BuiltinCounterStyle()
- : CounterStyle(NS_STYLE_LIST_STYLE_NONE)
- {
- }
- protected:
- constexpr explicit BuiltinCounterStyle(int32_t aStyle)
- : CounterStyle(aStyle)
- {
- }
- public:
- virtual void GetStyleName(nsSubstring& aResult) override;
- virtual void GetPrefix(nsSubstring& aResult) override;
- virtual void GetSuffix(nsSubstring& aResult) override;
- virtual void GetSpokenCounterText(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsSubstring& aResult,
- bool& aIsBullet) override;
- virtual bool IsBullet() override;
- virtual void GetNegative(NegativeType& aResult) override;
- virtual bool IsOrdinalInRange(CounterValue aOrdinal) override;
- virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) override;
- virtual void GetPad(PadType& aResult) override;
- virtual CounterStyle* GetFallback() override;
- virtual uint8_t GetSpeakAs() override;
- virtual bool UseNegativeSign() override;
- virtual bool GetInitialCounterText(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsSubstring& aResult,
- bool& aIsRTL) override;
- // Builtin counter style does not need refcount at all
- NS_IMETHOD_(MozExternalRefCountType) AddRef() override { return 2; }
- NS_IMETHOD_(MozExternalRefCountType) Release() override { return 2; }
- };
- /* virtual */ void
- BuiltinCounterStyle::GetStyleName(nsSubstring& aResult)
- {
- MOZ_ASSERT(mStyle != NS_STYLE_LIST_STYLE_CUSTOM);
- const nsAFlatCString& str =
- nsCSSProps::ValueToKeyword(mStyle, nsCSSProps::kListStyleKTable);
- MOZ_ASSERT(!str.IsEmpty());
- aResult.Assign(NS_ConvertUTF8toUTF16(str));
- }
- /* virtual */ void
- BuiltinCounterStyle::GetPrefix(nsSubstring& aResult)
- {
- aResult.Truncate();
- }
- /* virtual */ void
- BuiltinCounterStyle::GetSuffix(nsSubstring& aResult)
- {
- switch (mStyle) {
- case NS_STYLE_LIST_STYLE_NONE:
- aResult.Truncate();
- break;
- case NS_STYLE_LIST_STYLE_DISC:
- case NS_STYLE_LIST_STYLE_CIRCLE:
- case NS_STYLE_LIST_STYLE_SQUARE:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_CLOSED:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_OPEN:
- case NS_STYLE_LIST_STYLE_ETHIOPIC_NUMERIC:
- aResult = ' ';
- break;
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_FORMAL:
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_FORMAL:
- case NS_STYLE_LIST_STYLE_JAPANESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_JAPANESE_FORMAL:
- aResult = 0x3001;
- break;
- case NS_STYLE_LIST_STYLE_KOREAN_HANGUL_FORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_INFORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_FORMAL:
- aResult.AssignLiteral(u", ");
- break;
- default:
- aResult.AssignLiteral(u". ");
- break;
- }
- }
- static const char16_t kDiscCharacter = 0x2022;
- static const char16_t kCircleCharacter = 0x25e6;
- static const char16_t kSquareCharacter = 0x25fe;
- static const char16_t kRightPointingCharacter = 0x25b8;
- static const char16_t kLeftPointingCharacter = 0x25c2;
- static const char16_t kDownPointingCharacter = 0x25be;
- /* virtual */ void
- BuiltinCounterStyle::GetSpokenCounterText(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsSubstring& aResult,
- bool& aIsBullet)
- {
- switch (mStyle) {
- case NS_STYLE_LIST_STYLE_NONE:
- case NS_STYLE_LIST_STYLE_DISC:
- case NS_STYLE_LIST_STYLE_CIRCLE:
- case NS_STYLE_LIST_STYLE_SQUARE:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_CLOSED:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_OPEN: {
- // Same as the initial representation
- bool isRTL;
- GetInitialCounterText(aOrdinal, aWritingMode, aResult, isRTL);
- aIsBullet = true;
- break;
- }
- default:
- CounterStyle::GetSpokenCounterText(
- aOrdinal, aWritingMode, aResult, aIsBullet);
- break;
- }
- }
- /* virtual */ bool
- BuiltinCounterStyle::IsBullet()
- {
- switch (mStyle) {
- case NS_STYLE_LIST_STYLE_DISC:
- case NS_STYLE_LIST_STYLE_CIRCLE:
- case NS_STYLE_LIST_STYLE_SQUARE:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_CLOSED:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_OPEN:
- return true;
- default:
- return false;
- }
- }
- static const char16_t gJapaneseNegative[] = {
- 0x30de, 0x30a4, 0x30ca, 0x30b9, 0x0000
- };
- static const char16_t gKoreanNegative[] = {
- 0xb9c8, 0xc774, 0xb108, 0xc2a4, 0x0020, 0x0000
- };
- static const char16_t gSimpChineseNegative[] = {
- 0x8d1f, 0x0000
- };
- static const char16_t gTradChineseNegative[] = {
- 0x8ca0, 0x0000
- };
- /* virtual */ void
- BuiltinCounterStyle::GetNegative(NegativeType& aResult)
- {
- switch (mStyle) {
- case NS_STYLE_LIST_STYLE_JAPANESE_FORMAL:
- case NS_STYLE_LIST_STYLE_JAPANESE_INFORMAL:
- aResult.before = gJapaneseNegative;
- break;
- case NS_STYLE_LIST_STYLE_KOREAN_HANGUL_FORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_INFORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_FORMAL:
- aResult.before = gKoreanNegative;
- break;
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_FORMAL:
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_INFORMAL:
- aResult.before = gSimpChineseNegative;
- break;
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_FORMAL:
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_INFORMAL:
- aResult.before = gTradChineseNegative;
- break;
- default:
- aResult.before.AssignLiteral(u"-");
- }
- aResult.after.Truncate();
- }
- /* virtual */ bool
- BuiltinCounterStyle::IsOrdinalInRange(CounterValue aOrdinal)
- {
- switch (mStyle) {
- default:
- // cyclic
- case NS_STYLE_LIST_STYLE_NONE:
- case NS_STYLE_LIST_STYLE_DISC:
- case NS_STYLE_LIST_STYLE_CIRCLE:
- case NS_STYLE_LIST_STYLE_SQUARE:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_CLOSED:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_OPEN:
- // use DecimalToText
- case NS_STYLE_LIST_STYLE_DECIMAL:
- // use CJKIdeographicToText
- case NS_STYLE_LIST_STYLE_JAPANESE_FORMAL:
- case NS_STYLE_LIST_STYLE_JAPANESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_FORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_INFORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANGUL_FORMAL:
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_FORMAL:
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_FORMAL:
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_INFORMAL:
- return true;
- // use EthiopicToText
- case NS_STYLE_LIST_STYLE_ETHIOPIC_NUMERIC:
- return aOrdinal >= 1;
- // use HebrewToText
- case NS_STYLE_LIST_STYLE_HEBREW:
- return aOrdinal >= 1 && aOrdinal <= 999999;
- }
- }
- /* virtual */ bool
- BuiltinCounterStyle::IsOrdinalInAutoRange(CounterValue aOrdinal)
- {
- switch (mStyle) {
- // cyclic:
- case NS_STYLE_LIST_STYLE_NONE:
- case NS_STYLE_LIST_STYLE_DISC:
- case NS_STYLE_LIST_STYLE_CIRCLE:
- case NS_STYLE_LIST_STYLE_SQUARE:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_CLOSED:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_OPEN:
- // numeric:
- case NS_STYLE_LIST_STYLE_DECIMAL:
- return true;
- // additive:
- case NS_STYLE_LIST_STYLE_HEBREW:
- return aOrdinal >= 0;
- // complex predefined:
- case NS_STYLE_LIST_STYLE_JAPANESE_FORMAL:
- case NS_STYLE_LIST_STYLE_JAPANESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_FORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_INFORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANGUL_FORMAL:
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_FORMAL:
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_FORMAL:
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_ETHIOPIC_NUMERIC:
- return IsOrdinalInRange(aOrdinal);
- default:
- NS_NOTREACHED("Unknown counter style");
- return false;
- }
- }
- /* virtual */ void
- BuiltinCounterStyle::GetPad(PadType& aResult)
- {
- aResult.width = 0;
- aResult.symbol.Truncate();
- }
- /* virtual */ CounterStyle*
- BuiltinCounterStyle::GetFallback()
- {
- // Fallback of dependent builtin counter styles are handled in class
- // DependentBuiltinCounterStyle.
- return CounterStyleManager::GetDecimalStyle();
- }
- /* virtual */ uint8_t
- BuiltinCounterStyle::GetSpeakAs()
- {
- switch (mStyle) {
- case NS_STYLE_LIST_STYLE_NONE:
- case NS_STYLE_LIST_STYLE_DISC:
- case NS_STYLE_LIST_STYLE_CIRCLE:
- case NS_STYLE_LIST_STYLE_SQUARE:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_CLOSED:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_OPEN:
- return NS_STYLE_COUNTER_SPEAKAS_BULLETS;
- default:
- return NS_STYLE_COUNTER_SPEAKAS_NUMBERS;
- }
- }
- /* virtual */ bool
- BuiltinCounterStyle::UseNegativeSign()
- {
- switch (mStyle) {
- case NS_STYLE_LIST_STYLE_NONE:
- case NS_STYLE_LIST_STYLE_DISC:
- case NS_STYLE_LIST_STYLE_CIRCLE:
- case NS_STYLE_LIST_STYLE_SQUARE:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_CLOSED:
- case NS_STYLE_LIST_STYLE_DISCLOSURE_OPEN:
- return false;
- default:
- return true;
- }
- }
- /* virtual */ bool
- BuiltinCounterStyle::GetInitialCounterText(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsSubstring& aResult,
- bool& aIsRTL)
- {
- aIsRTL = false;
- switch (mStyle) {
- // used by counters & extends counter-style code only
- // XXX We really need to do this the same way we do list bullets.
- case NS_STYLE_LIST_STYLE_NONE:
- aResult.Truncate();
- return true;
- case NS_STYLE_LIST_STYLE_DISC:
- aResult.Assign(kDiscCharacter);
- return true;
- case NS_STYLE_LIST_STYLE_CIRCLE:
- aResult.Assign(kCircleCharacter);
- return true;
- case NS_STYLE_LIST_STYLE_SQUARE:
- aResult.Assign(kSquareCharacter);
- return true;
- case NS_STYLE_LIST_STYLE_DISCLOSURE_CLOSED:
- if (aWritingMode.IsVertical()) {
- aResult.Assign(kDownPointingCharacter);
- } else if (aWritingMode.IsBidiLTR()) {
- aResult.Assign(kRightPointingCharacter);
- } else {
- aResult.Assign(kLeftPointingCharacter);
- }
- return true;
- case NS_STYLE_LIST_STYLE_DISCLOSURE_OPEN:
- if (!aWritingMode.IsVertical()) {
- aResult.Assign(kDownPointingCharacter);
- } else if (aWritingMode.IsVerticalLR()) {
- aResult.Assign(kRightPointingCharacter);
- } else {
- aResult.Assign(kLeftPointingCharacter);
- }
- return true;
- case NS_STYLE_LIST_STYLE_DECIMAL:
- return DecimalToText(aOrdinal, aResult);
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_INFORMAL:
- return CJKIdeographicToText(aOrdinal, aResult, gDataTradChineseInformal);
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_FORMAL:
- return CJKIdeographicToText(aOrdinal, aResult, gDataTradChineseFormal);
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_INFORMAL:
- return CJKIdeographicToText(aOrdinal, aResult, gDataSimpChineseInformal);
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_FORMAL:
- return CJKIdeographicToText(aOrdinal, aResult, gDataSimpChineseFormal);
- case NS_STYLE_LIST_STYLE_JAPANESE_INFORMAL:
- return CJKIdeographicToText(aOrdinal, aResult, gDataJapaneseInformal);
- case NS_STYLE_LIST_STYLE_JAPANESE_FORMAL:
- return CJKIdeographicToText(aOrdinal, aResult, gDataJapaneseFormal);
- case NS_STYLE_LIST_STYLE_KOREAN_HANGUL_FORMAL:
- return CJKIdeographicToText(aOrdinal, aResult, gDataKoreanHangulFormal);
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_INFORMAL:
- return CJKIdeographicToText(aOrdinal, aResult, gDataKoreanHanjaInformal);
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_FORMAL:
- return CJKIdeographicToText(aOrdinal, aResult, gDataKoreanHanjaFormal);
- case NS_STYLE_LIST_STYLE_HEBREW:
- aIsRTL = true;
- return HebrewToText(aOrdinal, aResult);
- case NS_STYLE_LIST_STYLE_ETHIOPIC_NUMERIC:
- return EthiopicToText(aOrdinal, aResult);
- default:
- NS_NOTREACHED("Unknown builtin counter style");
- return false;
- }
- }
- class DependentBuiltinCounterStyle final : public BuiltinCounterStyle
- {
- private:
- ~DependentBuiltinCounterStyle() {}
- public:
- DependentBuiltinCounterStyle(int32_t aStyle, CounterStyleManager* aManager)
- : BuiltinCounterStyle(aStyle),
- mManager(aManager)
- {
- NS_ASSERTION(IsDependentStyle(), "Not a dependent builtin style");
- MOZ_ASSERT(!IsCustomStyle(), "Not a builtin style");
- }
- virtual CounterStyle* GetFallback() override;
- // DependentBuiltinCounterStyle is managed in the same way as
- // CustomCounterStyle.
- NS_IMETHOD_(MozExternalRefCountType) AddRef() override;
- NS_IMETHOD_(MozExternalRefCountType) Release() override;
- void* operator new(size_t sz, nsPresContext* aPresContext)
- {
- return aPresContext->PresShell()->AllocateByObjectID(
- eArenaObjectID_DependentBuiltinCounterStyle, sz);
- }
- private:
- void Destroy()
- {
- nsIPresShell* shell = mManager->PresContext()->PresShell();
- this->~DependentBuiltinCounterStyle();
- shell->FreeByObjectID(eArenaObjectID_DependentBuiltinCounterStyle, this);
- }
- CounterStyleManager* mManager;
- nsAutoRefCnt mRefCnt;
- NS_DECL_OWNINGTHREAD
- };
- NS_IMPL_ADDREF(DependentBuiltinCounterStyle)
- NS_IMPL_RELEASE_WITH_DESTROY(DependentBuiltinCounterStyle, Destroy())
- /* virtual */ CounterStyle*
- DependentBuiltinCounterStyle::GetFallback()
- {
- switch (GetStyle()) {
- case NS_STYLE_LIST_STYLE_JAPANESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_JAPANESE_FORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANGUL_FORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_INFORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_FORMAL:
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_FORMAL:
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_FORMAL:
- // These styles all have a larger range than cjk-decimal, so the
- // only case fallback is accessed is that they are extended.
- // Since extending styles will cache the data themselves, we need
- // not cache it here.
- return mManager->BuildCounterStyle(NS_LITERAL_STRING("cjk-decimal"));
- default:
- NS_NOTREACHED("Not a valid dependent builtin style");
- return BuiltinCounterStyle::GetFallback();
- }
- }
- class CustomCounterStyle final : public CounterStyle
- {
- private:
- ~CustomCounterStyle() {}
- public:
- CustomCounterStyle(const nsAString& aName,
- CounterStyleManager* aManager,
- nsCSSCounterStyleRule* aRule)
- : CounterStyle(NS_STYLE_LIST_STYLE_CUSTOM),
- mName(aName),
- mManager(aManager),
- mRule(aRule),
- mRuleGeneration(aRule->GetGeneration()),
- mSystem(aRule->GetSystem()),
- mFlags(0),
- mFallback(nullptr),
- mSpeakAsCounter(nullptr),
- mExtends(nullptr),
- mExtendsRoot(nullptr)
- {
- }
- // This method will clear all cached data in the style and update the
- // generation number of the rule. It should be called when the rule of
- // this style is changed.
- void ResetCachedData();
- // This method will reset all cached data which may depend on other
- // counter style. It will reset all pointers to other counter styles.
- // For counter style extends other, in addition, all fields will be
- // reset to uninitialized state. This method should be called when any
- // other counter style is added, removed, or changed.
- void ResetDependentData();
- nsCSSCounterStyleRule* GetRule() const { return mRule; }
- uint32_t GetRuleGeneration() const { return mRuleGeneration; }
- virtual void GetStyleName(nsSubstring& aResult) override;
- virtual void GetPrefix(nsSubstring& aResult) override;
- virtual void GetSuffix(nsSubstring& aResult) override;
- virtual void GetSpokenCounterText(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsSubstring& aResult,
- bool& aIsBullet) override;
- virtual bool IsBullet() override;
- virtual void GetNegative(NegativeType& aResult) override;
- virtual bool IsOrdinalInRange(CounterValue aOrdinal) override;
- virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) override;
- virtual void GetPad(PadType& aResult) override;
- virtual CounterStyle* GetFallback() override;
- virtual uint8_t GetSpeakAs() override;
- virtual bool UseNegativeSign() override;
- virtual void CallFallbackStyle(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsSubstring& aResult,
- bool& aIsRTL) override;
- virtual bool GetInitialCounterText(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsSubstring& aResult,
- bool& aIsRTL) override;
- bool IsExtendsSystem()
- {
- return mSystem == NS_STYLE_COUNTER_SYSTEM_EXTENDS;
- }
- // CustomCounterStyle should be reference-counted because it may be
- // dereferenced from the manager but still referenced by nodes and
- // frames before the style change is propagated.
- NS_IMETHOD_(MozExternalRefCountType) AddRef() override;
- NS_IMETHOD_(MozExternalRefCountType) Release() override;
- void* operator new(size_t sz, nsPresContext* aPresContext)
- {
- return aPresContext->PresShell()->AllocateByObjectID(
- eArenaObjectID_CustomCounterStyle, sz);
- }
- private:
- void Destroy()
- {
- nsIPresShell* shell = mManager->PresContext()->PresShell();
- this->~CustomCounterStyle();
- shell->FreeByObjectID(eArenaObjectID_CustomCounterStyle, this);
- }
- const nsTArray<nsString>& GetSymbols();
- const nsTArray<AdditiveSymbol>& GetAdditiveSymbols();
- // The speak-as values of counter styles may form a loop, and the
- // loops may have complex interaction with the loop formed by
- // extending. To solve this problem, the computation of speak-as is
- // divided into two phases:
- // 1. figure out the raw value, by ComputeRawSpeakAs, and
- // 2. eliminate loop, by ComputeSpeakAs.
- // See comments before the definitions of these methods for details.
- uint8_t GetSpeakAsAutoValue();
- void ComputeRawSpeakAs(uint8_t& aSpeakAs,
- CounterStyle*& aSpeakAsCounter);
- CounterStyle* ComputeSpeakAs();
- CounterStyle* ComputeExtends();
- CounterStyle* GetExtends();
- CounterStyle* GetExtendsRoot();
- nsString mName;
- // CounterStyleManager should always overlive any CounterStyle as it
- // is owned by nsPresContext, and will be released after all nodes and
- // frames are released.
- CounterStyleManager* mManager;
- RefPtr<nsCSSCounterStyleRule> mRule;
- uint32_t mRuleGeneration;
- uint8_t mSystem;
- // GetSpeakAs will ensure that private member mSpeakAs is initialized before used
- MOZ_INIT_OUTSIDE_CTOR uint8_t mSpeakAs;
- enum {
- // loop detection
- FLAG_EXTENDS_VISITED = 1 << 0,
- FLAG_EXTENDS_LOOP = 1 << 1,
- FLAG_SPEAKAS_VISITED = 1 << 2,
- FLAG_SPEAKAS_LOOP = 1 << 3,
- // field status
- FLAG_NEGATIVE_INITED = 1 << 4,
- FLAG_PREFIX_INITED = 1 << 5,
- FLAG_SUFFIX_INITED = 1 << 6,
- FLAG_PAD_INITED = 1 << 7,
- FLAG_SPEAKAS_INITED = 1 << 8,
- };
- uint16_t mFlags;
- // Fields below will be initialized when necessary.
- nsTArray<nsString> mSymbols;
- nsTArray<AdditiveSymbol> mAdditiveSymbols;
- NegativeType mNegative;
- nsString mPrefix, mSuffix;
- PadType mPad;
- // CounterStyleManager will guarantee that none of the pointers below
- // refers to a freed CounterStyle. There are two possible cases where
- // the manager will release its reference to a CounterStyle: 1. the
- // manager itself is released, 2. a rule is invalidated. In the first
- // case, all counter style are removed from the manager, and should
- // also have been dereferenced from other objects. All styles will be
- // released all together. In the second case, CounterStyleManager::
- // NotifyRuleChanged will guarantee that all pointers will be reset
- // before any CounterStyle is released.
- CounterStyle* mFallback;
- // This field refers to the last counter in a speak-as chain.
- // That counter must not speak as another counter.
- CounterStyle* mSpeakAsCounter;
- CounterStyle* mExtends;
- // This field refers to the last counter in the extends chain. The
- // counter must be either a builtin style or a style whose system is
- // not 'extends'.
- CounterStyle* mExtendsRoot;
- nsAutoRefCnt mRefCnt;
- NS_DECL_OWNINGTHREAD
- };
- NS_IMPL_ADDREF(CustomCounterStyle)
- NS_IMPL_RELEASE_WITH_DESTROY(CustomCounterStyle, Destroy())
- void
- CustomCounterStyle::ResetCachedData()
- {
- mSymbols.Clear();
- mAdditiveSymbols.Clear();
- mFlags &= ~(FLAG_NEGATIVE_INITED |
- FLAG_PREFIX_INITED |
- FLAG_SUFFIX_INITED |
- FLAG_PAD_INITED |
- FLAG_SPEAKAS_INITED);
- mFallback = nullptr;
- mSpeakAsCounter = nullptr;
- mExtends = nullptr;
- mExtendsRoot = nullptr;
- mRuleGeneration = mRule->GetGeneration();
- }
- void
- CustomCounterStyle::ResetDependentData()
- {
- mFlags &= ~FLAG_SPEAKAS_INITED;
- mSpeakAsCounter = nullptr;
- mFallback = nullptr;
- mExtends = nullptr;
- mExtendsRoot = nullptr;
- if (IsExtendsSystem()) {
- mFlags &= ~(FLAG_NEGATIVE_INITED |
- FLAG_PREFIX_INITED |
- FLAG_SUFFIX_INITED |
- FLAG_PAD_INITED);
- }
- }
- /* virtual */ void
- CustomCounterStyle::GetStyleName(nsSubstring& aResult)
- {
- aResult.Assign(mName);
- }
- /* virtual */ void
- CustomCounterStyle::GetPrefix(nsSubstring& aResult)
- {
- if (!(mFlags & FLAG_PREFIX_INITED)) {
- mFlags |= FLAG_PREFIX_INITED;
- const nsCSSValue& value = mRule->GetDesc(eCSSCounterDesc_Prefix);
- if (value.UnitHasStringValue()) {
- value.GetStringValue(mPrefix);
- } else if (IsExtendsSystem()) {
- GetExtends()->GetPrefix(mPrefix);
- } else {
- mPrefix.Truncate();
- }
- }
- aResult = mPrefix;
- }
- /* virtual */ void
- CustomCounterStyle::GetSuffix(nsSubstring& aResult)
- {
- if (!(mFlags & FLAG_SUFFIX_INITED)) {
- mFlags |= FLAG_SUFFIX_INITED;
- const nsCSSValue& value = mRule->GetDesc(eCSSCounterDesc_Suffix);
- if (value.UnitHasStringValue()) {
- value.GetStringValue(mSuffix);
- } else if (IsExtendsSystem()) {
- GetExtends()->GetSuffix(mSuffix);
- } else {
- mSuffix.AssignLiteral(u". ");
- }
- }
- aResult = mSuffix;
- }
- /* virtual */ void
- CustomCounterStyle::GetSpokenCounterText(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsSubstring& aResult,
- bool& aIsBullet)
- {
- if (GetSpeakAs() != NS_STYLE_COUNTER_SPEAKAS_OTHER) {
- CounterStyle::GetSpokenCounterText(
- aOrdinal, aWritingMode, aResult, aIsBullet);
- } else {
- MOZ_ASSERT(mSpeakAsCounter,
- "mSpeakAsCounter should have been initialized.");
- mSpeakAsCounter->GetSpokenCounterText(
- aOrdinal, aWritingMode, aResult, aIsBullet);
- }
- }
- /* virtual */ bool
- CustomCounterStyle::IsBullet()
- {
- switch (mSystem) {
- case NS_STYLE_COUNTER_SYSTEM_CYCLIC:
- // Only use ::-moz-list-bullet for cyclic system
- return true;
- case NS_STYLE_COUNTER_SYSTEM_EXTENDS:
- return GetExtendsRoot()->IsBullet();
- default:
- return false;
- }
- }
- /* virtual */ void
- CustomCounterStyle::GetNegative(NegativeType& aResult)
- {
- if (!(mFlags & FLAG_NEGATIVE_INITED)) {
- mFlags |= FLAG_NEGATIVE_INITED;
- const nsCSSValue& value = mRule->GetDesc(eCSSCounterDesc_Negative);
- switch (value.GetUnit()) {
- case eCSSUnit_Ident:
- case eCSSUnit_String:
- value.GetStringValue(mNegative.before);
- mNegative.after.Truncate();
- break;
- case eCSSUnit_Pair: {
- const nsCSSValuePair& pair = value.GetPairValue();
- pair.mXValue.GetStringValue(mNegative.before);
- pair.mYValue.GetStringValue(mNegative.after);
- break;
- }
- default: {
- if (IsExtendsSystem()) {
- GetExtends()->GetNegative(mNegative);
- } else {
- mNegative.before.AssignLiteral(u"-");
- mNegative.after.Truncate();
- }
- }
- }
- }
- aResult = mNegative;
- }
- static inline bool
- IsRangeValueInfinite(const nsCSSValue& aValue)
- {
- return aValue.GetUnit() == eCSSUnit_Enumerated &&
- aValue.GetIntValue() == NS_STYLE_COUNTER_RANGE_INFINITE;
- }
- /* virtual */ bool
- CustomCounterStyle::IsOrdinalInRange(CounterValue aOrdinal)
- {
- const nsCSSValue& value = mRule->GetDesc(eCSSCounterDesc_Range);
- if (value.GetUnit() == eCSSUnit_PairList) {
- for (const nsCSSValuePairList* item = value.GetPairListValue();
- item != nullptr; item = item->mNext) {
- const nsCSSValue& lowerBound = item->mXValue;
- const nsCSSValue& upperBound = item->mYValue;
- if ((IsRangeValueInfinite(lowerBound) ||
- aOrdinal >= lowerBound.GetIntValue()) &&
- (IsRangeValueInfinite(upperBound) ||
- aOrdinal <= upperBound.GetIntValue())) {
- return true;
- }
- }
- return false;
- } else if (IsExtendsSystem() && value.GetUnit() == eCSSUnit_None) {
- // Only use the range of extended style when 'range' is not specified.
- return GetExtends()->IsOrdinalInRange(aOrdinal);
- }
- return IsOrdinalInAutoRange(aOrdinal);
- }
- /* virtual */ bool
- CustomCounterStyle::IsOrdinalInAutoRange(CounterValue aOrdinal)
- {
- switch (mSystem) {
- case NS_STYLE_COUNTER_SYSTEM_CYCLIC:
- case NS_STYLE_COUNTER_SYSTEM_NUMERIC:
- case NS_STYLE_COUNTER_SYSTEM_FIXED:
- return true;
- case NS_STYLE_COUNTER_SYSTEM_ALPHABETIC:
- case NS_STYLE_COUNTER_SYSTEM_SYMBOLIC:
- return aOrdinal >= 1;
- case NS_STYLE_COUNTER_SYSTEM_ADDITIVE:
- return aOrdinal >= 0;
- case NS_STYLE_COUNTER_SYSTEM_EXTENDS:
- return GetExtendsRoot()->IsOrdinalInAutoRange(aOrdinal);
- default:
- NS_NOTREACHED("Invalid system for computing auto value.");
- return false;
- }
- }
- /* virtual */ void
- CustomCounterStyle::GetPad(PadType& aResult)
- {
- if (!(mFlags & FLAG_PAD_INITED)) {
- mFlags |= FLAG_PAD_INITED;
- const nsCSSValue& value = mRule->GetDesc(eCSSCounterDesc_Pad);
- if (value.GetUnit() == eCSSUnit_Pair) {
- const nsCSSValuePair& pair = value.GetPairValue();
- mPad.width = pair.mXValue.GetIntValue();
- pair.mYValue.GetStringValue(mPad.symbol);
- } else if (IsExtendsSystem()) {
- GetExtends()->GetPad(mPad);
- } else {
- mPad.width = 0;
- mPad.symbol.Truncate();
- }
- }
- aResult = mPad;
- }
- /* virtual */ CounterStyle*
- CustomCounterStyle::GetFallback()
- {
- if (!mFallback) {
- const nsCSSValue& value = mRule->GetDesc(eCSSCounterDesc_Fallback);
- if (value.UnitHasStringValue()) {
- mFallback = mManager->BuildCounterStyle(
- nsDependentString(value.GetStringBufferValue()));
- } else if (IsExtendsSystem()) {
- mFallback = GetExtends()->GetFallback();
- } else {
- mFallback = CounterStyleManager::GetDecimalStyle();
- }
- }
- return mFallback;
- }
- /* virtual */ uint8_t
- CustomCounterStyle::GetSpeakAs()
- {
- if (!(mFlags & FLAG_SPEAKAS_INITED)) {
- ComputeSpeakAs();
- }
- return mSpeakAs;
- }
- /* virtual */ bool
- CustomCounterStyle::UseNegativeSign()
- {
- if (mSystem == NS_STYLE_COUNTER_SYSTEM_EXTENDS) {
- return GetExtendsRoot()->UseNegativeSign();
- }
- return SystemUsesNegativeSign(mSystem);
- }
- /* virtual */ void
- CustomCounterStyle::CallFallbackStyle(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsSubstring& aResult,
- bool& aIsRTL)
- {
- CounterStyle* fallback = GetFallback();
- // If it recursively falls back to this counter style again,
- // it will then fallback to decimal to break the loop.
- mFallback = CounterStyleManager::GetDecimalStyle();
- fallback->GetCounterText(aOrdinal, aWritingMode, aResult, aIsRTL);
- mFallback = fallback;
- }
- /* virtual */ bool
- CustomCounterStyle::GetInitialCounterText(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsSubstring& aResult,
- bool& aIsRTL)
- {
- switch (mSystem) {
- case NS_STYLE_COUNTER_SYSTEM_CYCLIC:
- return GetCyclicCounterText(aOrdinal, aResult, GetSymbols());
- case NS_STYLE_COUNTER_SYSTEM_FIXED: {
- int32_t start = mRule->GetSystemArgument().GetIntValue();
- return GetFixedCounterText(aOrdinal, aResult, start, GetSymbols());
- }
- case NS_STYLE_COUNTER_SYSTEM_SYMBOLIC:
- return GetSymbolicCounterText(aOrdinal, aResult, GetSymbols());
- case NS_STYLE_COUNTER_SYSTEM_ALPHABETIC:
- return GetAlphabeticCounterText(aOrdinal, aResult, GetSymbols());
- case NS_STYLE_COUNTER_SYSTEM_NUMERIC:
- return GetNumericCounterText(aOrdinal, aResult, GetSymbols());
- case NS_STYLE_COUNTER_SYSTEM_ADDITIVE:
- return GetAdditiveCounterText(aOrdinal, aResult, GetAdditiveSymbols());
- case NS_STYLE_COUNTER_SYSTEM_EXTENDS:
- return GetExtendsRoot()->
- GetInitialCounterText(aOrdinal, aWritingMode, aResult, aIsRTL);
- default:
- NS_NOTREACHED("Invalid system.");
- return false;
- }
- }
- const nsTArray<nsString>&
- CustomCounterStyle::GetSymbols()
- {
- if (mSymbols.IsEmpty()) {
- const nsCSSValue& values = mRule->GetDesc(eCSSCounterDesc_Symbols);
- for (const nsCSSValueList* item = values.GetListValue();
- item; item = item->mNext) {
- nsString* symbol = mSymbols.AppendElement();
- item->mValue.GetStringValue(*symbol);
- }
- mSymbols.Compact();
- }
- return mSymbols;
- }
- const nsTArray<AdditiveSymbol>&
- CustomCounterStyle::GetAdditiveSymbols()
- {
- if (mAdditiveSymbols.IsEmpty()) {
- const nsCSSValue& values = mRule->GetDesc(eCSSCounterDesc_AdditiveSymbols);
- for (const nsCSSValuePairList* item = values.GetPairListValue();
- item; item = item->mNext) {
- AdditiveSymbol* symbol = mAdditiveSymbols.AppendElement();
- symbol->weight = item->mXValue.GetIntValue();
- item->mYValue.GetStringValue(symbol->symbol);
- }
- mAdditiveSymbols.Compact();
- }
- return mAdditiveSymbols;
- }
- // This method is used to provide the computed value for 'auto'.
- uint8_t
- CustomCounterStyle::GetSpeakAsAutoValue()
- {
- uint8_t system = mSystem;
- if (IsExtendsSystem()) {
- CounterStyle* root = GetExtendsRoot();
- if (!root->IsCustomStyle()) {
- // It is safe to call GetSpeakAs on non-custom style.
- return root->GetSpeakAs();
- }
- system = static_cast<CustomCounterStyle*>(root)->mSystem;
- }
- return GetDefaultSpeakAsForSystem(system);
- }
- // This method corresponds to the first stage of computation of the
- // value of speak-as. It will extract the value from the rule and
- // possibly recursively call itself on the extended style to figure
- // out the raw value. To keep things clear, this method is designed to
- // have no side effects (but functions it calls may still affect other
- // fields in the style.)
- void
- CustomCounterStyle::ComputeRawSpeakAs(uint8_t& aSpeakAs,
- CounterStyle*& aSpeakAsCounter)
- {
- NS_ASSERTION(!(mFlags & FLAG_SPEAKAS_INITED),
- "ComputeRawSpeakAs is called with speak-as inited.");
- const nsCSSValue& value = mRule->GetDesc(eCSSCounterDesc_SpeakAs);
- switch (value.GetUnit()) {
- case eCSSUnit_Auto:
- aSpeakAs = GetSpeakAsAutoValue();
- break;
- case eCSSUnit_Enumerated:
- aSpeakAs = value.GetIntValue();
- break;
- case eCSSUnit_Ident:
- aSpeakAs = NS_STYLE_COUNTER_SPEAKAS_OTHER;
- aSpeakAsCounter = mManager->BuildCounterStyle(
- nsDependentString(value.GetStringBufferValue()));
- break;
- case eCSSUnit_Null: {
- if (!IsExtendsSystem()) {
- aSpeakAs = GetSpeakAsAutoValue();
- } else {
- CounterStyle* extended = GetExtends();
- if (!extended->IsCustomStyle()) {
- // It is safe to call GetSpeakAs on non-custom style.
- aSpeakAs = extended->GetSpeakAs();
- } else {
- CustomCounterStyle* custom =
- static_cast<CustomCounterStyle*>(extended);
- if (!(custom->mFlags & FLAG_SPEAKAS_INITED)) {
- custom->ComputeRawSpeakAs(aSpeakAs, aSpeakAsCounter);
- } else {
- aSpeakAs = custom->mSpeakAs;
- aSpeakAsCounter = custom->mSpeakAsCounter;
- }
- }
- }
- break;
- }
- default:
- NS_NOTREACHED("Invalid speak-as value");
- }
- }
- // This method corresponds to the second stage of getting speak-as
- // related values. It will recursively figure out the final value of
- // mSpeakAs and mSpeakAsCounter. This method returns nullptr if the
- // caller is in a loop, and the root counter style in the chain
- // otherwise. It use the same loop detection algorithm as
- // CustomCounterStyle::ComputeExtends, see comments before that
- // method for more details.
- CounterStyle*
- CustomCounterStyle::ComputeSpeakAs()
- {
- if (mFlags & FLAG_SPEAKAS_INITED) {
- if (mSpeakAs == NS_STYLE_COUNTER_SPEAKAS_OTHER) {
- return mSpeakAsCounter;
- }
- return this;
- }
- if (mFlags & FLAG_SPEAKAS_VISITED) {
- // loop detected
- mFlags |= FLAG_SPEAKAS_LOOP;
- return nullptr;
- }
- CounterStyle* speakAsCounter;
- ComputeRawSpeakAs(mSpeakAs, speakAsCounter);
- bool inLoop = false;
- if (mSpeakAs != NS_STYLE_COUNTER_SPEAKAS_OTHER) {
- mSpeakAsCounter = nullptr;
- } else if (!speakAsCounter->IsCustomStyle()) {
- mSpeakAsCounter = speakAsCounter;
- } else {
- mFlags |= FLAG_SPEAKAS_VISITED;
- CounterStyle* target =
- static_cast<CustomCounterStyle*>(speakAsCounter)->ComputeSpeakAs();
- mFlags &= ~FLAG_SPEAKAS_VISITED;
- if (target) {
- NS_ASSERTION(!(mFlags & FLAG_SPEAKAS_LOOP),
- "Invalid state for speak-as loop detecting");
- mSpeakAsCounter = target;
- } else {
- mSpeakAs = GetSpeakAsAutoValue();
- mSpeakAsCounter = nullptr;
- if (mFlags & FLAG_SPEAKAS_LOOP) {
- mFlags &= ~FLAG_SPEAKAS_LOOP;
- } else {
- inLoop = true;
- }
- }
- }
- mFlags |= FLAG_SPEAKAS_INITED;
- if (inLoop) {
- return nullptr;
- }
- return mSpeakAsCounter ? mSpeakAsCounter : this;
- }
- // This method will recursively figure out mExtends in the whole chain.
- // It will return nullptr if the caller is in a loop, and return this
- // otherwise. To detect the loop, this method marks the style VISITED
- // before the recursive call. When a VISITED style is reached again, the
- // loop is detected, and flag LOOP will be marked on the first style in
- // loop. mExtends of all counter styles in loop will be set to decimal
- // according to the spec.
- CounterStyle*
- CustomCounterStyle::ComputeExtends()
- {
- if (!IsExtendsSystem() || mExtends) {
- return this;
- }
- if (mFlags & FLAG_EXTENDS_VISITED) {
- // loop detected
- mFlags |= FLAG_EXTENDS_LOOP;
- return nullptr;
- }
- const nsCSSValue& value = mRule->GetSystemArgument();
- CounterStyle* nextCounter = mManager->BuildCounterStyle(
- nsDependentString(value.GetStringBufferValue()));
- CounterStyle* target = nextCounter;
- if (nextCounter->IsCustomStyle()) {
- mFlags |= FLAG_EXTENDS_VISITED;
- target = static_cast<CustomCounterStyle*>(nextCounter)->ComputeExtends();
- mFlags &= ~FLAG_EXTENDS_VISITED;
- }
- if (target) {
- NS_ASSERTION(!(mFlags & FLAG_EXTENDS_LOOP),
- "Invalid state for extends loop detecting");
- mExtends = nextCounter;
- return this;
- } else {
- mExtends = CounterStyleManager::GetDecimalStyle();
- if (mFlags & FLAG_EXTENDS_LOOP) {
- mFlags &= ~FLAG_EXTENDS_LOOP;
- return this;
- } else {
- return nullptr;
- }
- }
- }
- CounterStyle*
- CustomCounterStyle::GetExtends()
- {
- if (!mExtends) {
- // Any extends loop will be eliminated in the method below.
- ComputeExtends();
- }
- return mExtends;
- }
- CounterStyle*
- CustomCounterStyle::GetExtendsRoot()
- {
- if (!mExtendsRoot) {
- CounterStyle* extended = GetExtends();
- mExtendsRoot = extended;
- if (extended->IsCustomStyle()) {
- CustomCounterStyle* custom = static_cast<CustomCounterStyle*>(extended);
- if (custom->IsExtendsSystem()) {
- // This will make mExtendsRoot in the whole extends chain be
- // set recursively, which could save work when part of a chain
- // is shared by multiple counter styles.
- mExtendsRoot = custom->GetExtendsRoot();
- }
- }
- }
- return mExtendsRoot;
- }
- AnonymousCounterStyle::AnonymousCounterStyle(const nsSubstring& aContent)
- : CounterStyle(NS_STYLE_LIST_STYLE_CUSTOM)
- , mSingleString(true)
- , mSystem(NS_STYLE_COUNTER_SYSTEM_CYCLIC)
- {
- mSymbols.SetCapacity(1);
- mSymbols.AppendElement(aContent);
- }
- AnonymousCounterStyle::AnonymousCounterStyle(const nsCSSValue::Array* aParams)
- : CounterStyle(NS_STYLE_LIST_STYLE_CUSTOM)
- , mSingleString(false)
- , mSystem(aParams->Item(0).GetIntValue())
- {
- for (const nsCSSValueList* item = aParams->Item(1).GetListValue();
- item; item = item->mNext) {
- item->mValue.GetStringValue(*mSymbols.AppendElement());
- }
- mSymbols.Compact();
- }
- /* virtual */ void
- AnonymousCounterStyle::GetStyleName(nsAString& aResult)
- {
- aResult.Truncate();
- }
- /* virtual */ void
- AnonymousCounterStyle::GetPrefix(nsAString& aResult)
- {
- aResult.Truncate();
- }
- /* virtual */ void
- AnonymousCounterStyle::GetSuffix(nsAString& aResult)
- {
- if (IsSingleString()) {
- aResult.Truncate();
- } else {
- aResult = ' ';
- }
- }
- /* virtual */ bool
- AnonymousCounterStyle::IsBullet()
- {
- switch (mSystem) {
- case NS_STYLE_COUNTER_SYSTEM_CYCLIC:
- // Only use ::-moz-list-bullet for cyclic system
- return true;
- default:
- return false;
- }
- }
- /* virtual */ void
- AnonymousCounterStyle::GetNegative(NegativeType& aResult)
- {
- aResult.before.AssignLiteral(u"-");
- aResult.after.Truncate();
- }
- /* virtual */ bool
- AnonymousCounterStyle::IsOrdinalInRange(CounterValue aOrdinal)
- {
- switch (mSystem) {
- case NS_STYLE_COUNTER_SYSTEM_CYCLIC:
- case NS_STYLE_COUNTER_SYSTEM_NUMERIC:
- case NS_STYLE_COUNTER_SYSTEM_FIXED:
- return true;
- case NS_STYLE_COUNTER_SYSTEM_ALPHABETIC:
- case NS_STYLE_COUNTER_SYSTEM_SYMBOLIC:
- return aOrdinal >= 1;
- default:
- NS_NOTREACHED("Invalid system.");
- return false;
- }
- }
- /* virtual */ bool
- AnonymousCounterStyle::IsOrdinalInAutoRange(CounterValue aOrdinal)
- {
- return AnonymousCounterStyle::IsOrdinalInRange(aOrdinal);
- }
- /* virtual */ void
- AnonymousCounterStyle::GetPad(PadType& aResult)
- {
- aResult.width = 0;
- aResult.symbol.Truncate();
- }
- /* virtual */ CounterStyle*
- AnonymousCounterStyle::GetFallback()
- {
- return CounterStyleManager::GetDecimalStyle();
- }
- /* virtual */ uint8_t
- AnonymousCounterStyle::GetSpeakAs()
- {
- return GetDefaultSpeakAsForSystem(mSystem);
- }
- /* virtual */ bool
- AnonymousCounterStyle::UseNegativeSign()
- {
- return SystemUsesNegativeSign(mSystem);
- }
- /* virtual */ bool
- AnonymousCounterStyle::GetInitialCounterText(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsAString& aResult,
- bool& aIsRTL)
- {
- switch (mSystem) {
- case NS_STYLE_COUNTER_SYSTEM_CYCLIC:
- return GetCyclicCounterText(aOrdinal, aResult, mSymbols);
- case NS_STYLE_COUNTER_SYSTEM_FIXED:
- return GetFixedCounterText(aOrdinal, aResult, 1, mSymbols);
- case NS_STYLE_COUNTER_SYSTEM_SYMBOLIC:
- return GetSymbolicCounterText(aOrdinal, aResult, mSymbols);
- case NS_STYLE_COUNTER_SYSTEM_ALPHABETIC:
- return GetAlphabeticCounterText(aOrdinal, aResult, mSymbols);
- case NS_STYLE_COUNTER_SYSTEM_NUMERIC:
- return GetNumericCounterText(aOrdinal, aResult, mSymbols);
- default:
- NS_NOTREACHED("Invalid system.");
- return false;
- }
- }
- bool
- CounterStyle::IsDependentStyle() const
- {
- switch (mStyle) {
- // CustomCounterStyle
- case NS_STYLE_LIST_STYLE_CUSTOM:
- // DependentBuiltinCounterStyle
- case NS_STYLE_LIST_STYLE_JAPANESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_JAPANESE_FORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANGUL_FORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_INFORMAL:
- case NS_STYLE_LIST_STYLE_KOREAN_HANJA_FORMAL:
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_SIMP_CHINESE_FORMAL:
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_INFORMAL:
- case NS_STYLE_LIST_STYLE_TRAD_CHINESE_FORMAL:
- return true;
- // BuiltinCounterStyle
- default:
- return false;
- }
- }
- void
- CounterStyle::GetCounterText(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsSubstring& aResult,
- bool& aIsRTL)
- {
- bool success = IsOrdinalInRange(aOrdinal);
- aIsRTL = false;
- if (success) {
- // generate initial representation
- bool useNegativeSign = UseNegativeSign();
- nsAutoString initialText;
- CounterValue ordinal;
- if (!useNegativeSign) {
- ordinal = aOrdinal;
- } else {
- CheckedInt<CounterValue> absolute(Abs(aOrdinal));
- ordinal = absolute.isValid() ?
- absolute.value() : std::numeric_limits<CounterValue>::max();
- }
- success = GetInitialCounterText(
- ordinal, aWritingMode, initialText, aIsRTL);
- // add pad & negative, build the final result
- if (success) {
- PadType pad;
- GetPad(pad);
- // We have to calculate the difference here since suffix part of negative
- // sign may be appended to initialText later.
- int32_t diff = pad.width -
- unicode::CountGraphemeClusters(initialText.Data(),
- initialText.Length());
- aResult.Truncate();
- if (useNegativeSign && aOrdinal < 0) {
- NegativeType negative;
- GetNegative(negative);
- aResult.Append(negative.before);
- // There is nothing between the suffix part of negative and initial
- // representation, so we append it directly here.
- initialText.Append(negative.after);
- }
- if (diff > 0) {
- auto length = pad.symbol.Length();
- if (diff > LENGTH_LIMIT || length > LENGTH_LIMIT ||
- diff * length > LENGTH_LIMIT) {
- success = false;
- } else if (length > 0) {
- for (int32_t i = 0; i < diff; ++i) {
- aResult.Append(pad.symbol);
- }
- }
- }
- if (success) {
- aResult.Append(initialText);
- }
- }
- }
- if (!success) {
- CallFallbackStyle(aOrdinal, aWritingMode, aResult, aIsRTL);
- }
- }
- /* virtual */ void
- CounterStyle::GetSpokenCounterText(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsSubstring& aResult,
- bool& aIsBullet)
- {
- bool isRTL; // we don't care about direction for spoken text
- aIsBullet = false;
- switch (GetSpeakAs()) {
- case NS_STYLE_COUNTER_SPEAKAS_BULLETS:
- aResult.Assign(kDiscCharacter);
- aIsBullet = true;
- break;
- case NS_STYLE_COUNTER_SPEAKAS_NUMBERS:
- DecimalToText(aOrdinal, aResult);
- break;
- case NS_STYLE_COUNTER_SPEAKAS_SPELL_OUT:
- // we currently do not actually support 'spell-out',
- // so 'words' is used instead.
- case NS_STYLE_COUNTER_SPEAKAS_WORDS:
- GetCounterText(aOrdinal, WritingMode(), aResult, isRTL);
- break;
- case NS_STYLE_COUNTER_SPEAKAS_OTHER:
- // This should be processed by CustomCounterStyle
- NS_NOTREACHED("Invalid speak-as value");
- break;
- default:
- NS_NOTREACHED("Unknown speak-as value");
- break;
- }
- }
- /* virtual */ void
- CounterStyle::CallFallbackStyle(CounterValue aOrdinal,
- WritingMode aWritingMode,
- nsAString& aResult,
- bool& aIsRTL)
- {
- GetFallback()->GetCounterText(aOrdinal, aWritingMode, aResult, aIsRTL);
- }
- static BuiltinCounterStyle gBuiltinStyleTable[NS_STYLE_LIST_STYLE__MAX];
- CounterStyleManager::CounterStyleManager(nsPresContext* aPresContext)
- : mPresContext(aPresContext)
- {
- // Insert the static styles into cache table
- mCacheTable.Put(NS_LITERAL_STRING("none"), GetNoneStyle());
- mCacheTable.Put(NS_LITERAL_STRING("decimal"), GetDecimalStyle());
- }
- CounterStyleManager::~CounterStyleManager()
- {
- MOZ_ASSERT(!mPresContext, "Disconnect should have been called");
- }
- /* static */ void
- CounterStyleManager::InitializeBuiltinCounterStyles()
- {
- for (uint32_t i = 0; i < NS_STYLE_LIST_STYLE__MAX; ++i) {
- gBuiltinStyleTable[i].mStyle = i;
- }
- }
- void
- CounterStyleManager::Disconnect()
- {
- #ifdef DEBUG
- for (auto iter = mCacheTable.Iter(); !iter.Done(); iter.Next()) {
- CounterStyle* style = iter.UserData();
- style->AddRef();
- auto refcnt = style->Release();
- NS_ASSERTION(!style->IsDependentStyle() || refcnt == 1,
- "Counter style is still referenced by other objects.");
- }
- #endif
- mCacheTable.Clear();
- mPresContext = nullptr;
- }
- CounterStyle*
- CounterStyleManager::BuildCounterStyle(const nsSubstring& aName)
- {
- CounterStyle* data = mCacheTable.GetWeak(aName);
- if (data) {
- return data;
- }
- // It is intentional that the predefined names are case-insensitive
- // but the user-defined names case-sensitive.
- // XXXheycam ServoStyleSets do not support custom counter styles yet.
- StyleSetHandle styleSet = mPresContext->StyleSet();
- NS_ASSERTION(styleSet->IsGecko(),
- "stylo: ServoStyleSets do not support custom counter "
- "styles yet");
- nsCSSCounterStyleRule* rule = styleSet->IsGecko() ?
- styleSet->AsGecko()->CounterStyleRuleForName(aName) : nullptr;
- if (rule) {
- data = new (mPresContext) CustomCounterStyle(aName, this, rule);
- } else {
- int32_t type;
- nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aName);
- if (nsCSSProps::FindKeyword(keyword, nsCSSProps::kListStyleKTable, type)) {
- if (gBuiltinStyleTable[type].IsDependentStyle()) {
- data = new (mPresContext) DependentBuiltinCounterStyle(type, this);
- } else {
- data = GetBuiltinStyle(type);
- }
- }
- }
- if (!data) {
- data = GetDecimalStyle();
- }
- mCacheTable.Put(aName, data);
- return data;
- }
- /* static */ CounterStyle*
- CounterStyleManager::GetBuiltinStyle(int32_t aStyle)
- {
- MOZ_ASSERT(0 <= aStyle && aStyle < NS_STYLE_LIST_STYLE__MAX,
- "Require a valid builtin style constant");
- MOZ_ASSERT(!gBuiltinStyleTable[aStyle].IsDependentStyle(),
- "Cannot get dependent builtin style");
- return &gBuiltinStyleTable[aStyle];
- }
- bool
- CounterStyleManager::NotifyRuleChanged()
- {
- bool changed = false;
- nsTArray<RefPtr<CounterStyle>> kungFuDeathGrip;
- for (auto iter = mCacheTable.Iter(); !iter.Done(); iter.Next()) {
- RefPtr<CounterStyle>& style = iter.Data();
- bool toBeUpdated = false;
- bool toBeRemoved = false;
- // XXXheycam ServoStyleSets do not support custom counter styles yet.
- StyleSetHandle styleSet = mPresContext->StyleSet();
- NS_ASSERTION(styleSet->IsGecko(),
- "stylo: ServoStyleSets do not support custom counter "
- "styles yet");
- nsCSSCounterStyleRule* newRule = styleSet->IsGecko() ?
- styleSet->AsGecko()->CounterStyleRuleForName(iter.Key()) : nullptr;
- if (!newRule) {
- if (style->IsCustomStyle()) {
- toBeRemoved = true;
- }
- } else {
- if (!style->IsCustomStyle()) {
- toBeRemoved = true;
- } else {
- auto custom = static_cast<CustomCounterStyle*>(style.get());
- if (custom->GetRule() != newRule) {
- toBeRemoved = true;
- } else if (custom->GetRuleGeneration() != newRule->GetGeneration()) {
- toBeUpdated = true;
- custom->ResetCachedData();
- }
- }
- }
- changed = changed || toBeUpdated || toBeRemoved;
- if (toBeRemoved) {
- if (style->IsDependentStyle()) {
- if (style->IsCustomStyle()) {
- // Since |style| is being removed from mCacheTable, it won't be
- // visited by our post-removal iteration. So, we have to give it a
- // manual ResetDependentData() call. (This only really matters if
- // something else is holding a reference and keeping it alive.)
- static_cast<CustomCounterStyle*>(style.get())->ResetDependentData();
- }
- // The object has to be held here so that it will not be released
- // before all pointers that refer to it are reset. It will be released
- // when kungFuDeathGrip goes out of scope at the end of this function.
- kungFuDeathGrip.AppendElement(style);
- }
- iter.Remove();
- }
- }
- if (changed) {
- for (auto iter = mCacheTable.Iter(); !iter.Done(); iter.Next()) {
- CounterStyle* style = iter.UserData();
- if (style->IsCustomStyle()) {
- CustomCounterStyle* custom = static_cast<CustomCounterStyle*>(style);
- custom->ResetDependentData();
- }
- // There is no dependent data cached in DependentBuiltinCounterStyle
- // instances, so we don't need to reset their data.
- }
- }
- return changed;
- }
- } // namespace mozilla
|