Files
palemoon27/layout/style/Declaration.cpp
T
roytam1 fffeb135bb import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1040668 part 2 - Parse and compute text emphasis properties. r=dbaron (0fb79d4709)
- Bug 1040668 part 3 - Add helper function gfxTextRun::GetAdvanceForGlyph. r=jfkthame (f1cf02f5ff)
- Bug 1216427 - Tests for backspacing over a character with variation selector, and over Regional Indicator flag symbols. r=emk (18957bfe77)
- Bug 1216427 - part 1 - Ensure a character+VS sequence or a ligated Regional-Indicator flag symbol is deleted as a single unit when backspacing. r=emk (2776ff8f4a)
- Bug 1216427 - part 2 - Ensure mouse selection does not split up a Regional Indicator flag symbol. r=emk (58eb82e6a1)
- Bug 1040668 part 4 - Add helper function for ensuring a glyph is a complex glyph. r=jfkthame (ba17f7d0c4)
- Bug 1040668 part 5 - Avoid unnecessary allocation inside EnsureComplexGlyph helper function. r=jfkthame (4968a7c68e)
- Bug 1040668 part 6 - Add some specifier on gfxTextRun and gfxShapedWord so that compilers are able to reason out certain optimizations. r=jfkthame (69ca3eb959)
- Bug 1040668 part 7 - Add NO_EMPHASIS_MARK flag in CompressedGlyph. r=jfkthame (34e9d8a6a6)
- Bug 1227001 part 1 - Remove SetupBreakSinksFlags from BuildTextRunsScanner. r=jfkthame (520b1ba111)
- Bug 1227001 part 2 - Remove no longer used mExistingTextRun from BreaSink. r=jfkthame (201782a78c)
- Bug 1227001 part 3 - Remove no longer used mChangedBreaks from BreakSink. r=jfkthame (e754e2b13f)
- Bug 1040668 part 8 - Setup text emphasis for text run. r=jfkthame (376377180e)
- Bug 1040668 part 9 - Compute overflow from text-shadow after text decorations. r=dbaron (05c9bd08c2)
- Bug 1040668 part 10 - Implement emphasis mark rendering. r=jfkthame (4d270afca8)
- Bug 1040668 part 11 - Move line leadings adjusting code into a separate function in nsLineLayout. r=dholbert (fd4dd20ca5)
- Bug 1040668 part 12 - Add line leadings for emphasis marks if necessary. r=dholbert (138add5ff7)
- Bug 1040668 part 13 - Move first part of nsStyleFont::GetLanguage to nsPresContext::GetContentLanguage. r=dbaron (1e872d2a58)
- Bug 1040668 part 14 - Add helper function nsStyleUtil::MatchesLanguagePrefix for doing simple language matching. r=dbaron (9322a02369)
- Bug 1040668 part 15 - Make the default value of text-emphasis-position aware of the language. r=dbaron (6587c628da)
- Bug 1040668 part 16 - Add reftests for text-emphasis. r=dbaron (9940d65182)
- Bug 1040668 followup - Use monospace for text-emphasis reftests. rs=dbaron on a CLOSED TREE (fb7598c3ea)
- Bug 1040668 followup 2 - Disable failing reftests of text-emphasis on Windows XP. (7c3f24ac22)
- Bug 1040668 followup 3 - Wrap lang attribute mapping code in NS_STYLE_INHERIT_BIT test. r=dbaron (640e3b7b8f)
- Bug 1219145 - nsRefreshDriver::IsJankCritical(). r=hiro To refine its alerts, Performance Stats API needs to be able to know whether a long-running operation is actually causing user-visible jank in the current process. This patch introduces a trivial API that lets clients ask the refresh driver whether any kind of animation is ongoing. (7c0868d7c4)
- more missing XP theme stuff (637af0c6a0)
- Bug 1210261. Tick root refresh driver last. r=mattwoodrow (dae1a325fa)
- Bug 1221674 Part 2: Correct for negative content delay values. r=avih (9b9811c41c)
- Bug 1211334 - Check if presshell is still available after dispatching transition events; r=mats (8a044a462c)
- Bug 1211599 - Only allow whitelisted histograms to have > 100 buckets. r=nfroyd (d467e84130)
- Bug 1219733 - Allow a 'bug_numbers' field in Histograms.json entries. r=vladan (8e63a713ec)
- Bug 1222044 - Only allow lists of alert_emails r=vladan (1d5fcb009d)
- Bug 1168263 - Add a flags parameter to GetResultingTransformMatrix instead of using bools. r=roc (ec5224f9af)
- Bug 1168263 - Remove TransformRectOut since it's unused. r=roc (d20a79ae0e)
- Bug 1215406 - Part 1: Remove NS_STYLE_ANIMATION_DIRECTION_XXX and NS_STYLE_ANIMATION_FILL_MODE_XXX. r=heycam (4bd7f8116b)
- Bug 1215406 - Part 2: Change the types of direction and fillmode in StyleAnimation. r=heycam (e06323c81b)
- Bug 1215406 - Part 3: Change the types of direction and fillmode in AnimationTiming. r=heycam (e5454d3ea5)
- Bug 1215406 - Part 4: Add KeyframeEffectOptions. r=smaug Add KeyframeEffectOptions in KeyframeEffect.webidl (0ce3372fd1)
- Bug 1215406 - Part 5: Implement KeyframeEffectOptions in KeyframeEffectReadOnly constructor. r=birtles (a472e9ac5f)
- tch 2 - Use an enum class for NS_STYLE_BOX_SIZING_*. r=heycam (4897b7b8ff)
- Bug 1218195, mark MutationObserver as observing in all the nested DOM mutations, r=bz (48a4aa8a91)
- Bug 1172870 - Part 3 - Fix openWindow mochitest to work on e10s (574cc6fa4d)
- Bug 1223265 - Fix -Wunreachable-code and -Wimplicit-fallthrough warnings in dom/bindings and dom/ipc. r=khuey (9eab632140)
- Bug 1189195 - Fix PContentPermissionRequest shutdown () r=fabrice (6bc1a681f5)
- Bug 1210508 - Handle null OriginAttributes from JS-implemented nsILoadContext. r=me (2f71edb9d7)
- Bug 1224596 part 1. Add a version of WorkerMainThreadRunnable::Dispatch that takes an ErrorResult to report failure to dispatch on. r=khuey (e60a0fb115)
- Bug 1224596 part 2. Switch Navigator to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (d9298a4763)
- Bug 1224596 part 3. Make some WebSocket(Impl) methods whose return value is totally ignored void. r=khuey (1d04b52d44)
- Bug 1224596 part 4. Switch WebSocket to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (aa06e6417b)
- Bug 1224596 part 5. Switch nsPerformance to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (0303b7de09)
- Bug 1224596 part 6. Switch BroadcastChannel to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (feacc21f63)
- Bug 1224636. Fix some code in ImageBitmap that rejects a promise with an ErrorResult, then keeps trying to use that ErrorResult. r=kaku (89b769fe07)
- Bug 1224596 part 7. Switch ImageBitmap to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (e21b0a4a0a)
- Bug 1183954, Don't leak nsStructuredCloneContainer (use of 'auto' is error prone), r=leak (1a9b30f2ca)
- Bug 1114554 - Patch 9 - Fixed crash in b2g-desktop tests. r=nsm (6b12c6d121)
- Bug 1189090 - Rework the nsISupports implementation in the ScopeCheckingGetCallback and its subclasses; r=nsm (6bea544597)
- Bug 1187018 - Ensure feature is nulled out if it does not get added. r=khuey (9d7439498a)
- Bug 1224596 part 8. Switch Notification to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (03f0f6877f)
- Bug 1196079 - Always try to release Notification via normal WorkerRunnable first. r=wchen (c093253d6f)
- Bug 1203324 - disable notifications on serviceworkers. r=ehsan,wchen (aa39310dc1)
- Bug 1199901 - GetOrigin() fails cleanly instead of asserting principal. r=wchen (148c634a4f)
- Bug 1199901 - Clear mObserver when WorkerNotificationObserver is destroyed. r=wchen (6d5cd99183)
- Bug 1199901 - Bustage fix due to rebase. a=bustage (344bd62af5)
- Bug 1225470 Report a message to the console when a service worker waitUntil() is rejected. r=baku (610da2eec6)
- Bug 1217909 P1 Report service worker exceptions to controlled documents. r=catalinb (f8bd4677d5)
- Bug 1216566 - Fix a bug in nsIServiceWorkerManager.getAllRegistrations;r=catalinb (ed3e14ab43)
- Bug 1219205 - ServiceWorkerInfo should be an XPCOM object;r=catalinb (677a6f1ffd)
- Bug 1217909 P2 Track registering documents as weak reference so SWM can report errors to them. r=catalinb (4233dc3edc)
- Bug 1217909 P3 Refactor service worker register()/update() to reject only with SecurityErr or TypeErr. r=catalinb (c6891a7fae)
- Bug 1220740 - nsIServiceWorkerRegistrationInfo should emit an event when its scriptSpec property changes;r=amarchesini (5772bb5914)
- Bug 1207727 - Add WPT tests for service worker update algorithm. r=bkelly (a4812571a1)
- Bug 1217367 - Service workers update algorithm optimization. r=bkelly (e377debad1)
- Bug 1226479. Change ErrorResult::ThrowTypeError/ThrowRangeError to take string references, not pointers. r=mccr8 (0804899666)
- Bug 1224659 - Worker DataStore code should not use ErrorResult cross threads, r=bz (aef03b0fdd)
- Bug 1224596 part 9. Switch DataStore to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (1eb1c427f2)
- Bug 1224596 part 10. Switch DataStoreCursor to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (114af8021b)
- Bug 1224596 part 11. Switch WorkerNavigator to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (b2347a0c49)
- Bug 1224596 part 12. Switch ServiceWorkerRegistration to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (d1ff076836)
- Bug 1224596 part 13. Switch gfxUtils to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (a523997588)
- Bug 1224007 part 1. Rename ThrowMethodFailed to MaybeSetPendingException and make it an ErrorResult instance method. r=peterv (bdf0891f54)
- Bug 1224007 part 2. Make the various ErrorResult::Report* methods private, so consumers all go through MaybeSetPendingException and rename them to more clearly indicate what they're actually doing. r=peterv (48f483c153)
- Bug 1203151 - Allow disabling of screen wakelocks for video elements. r=baku (6bd9ff6916)
- Bug 1224007 part 4. Fix some cases in which ErrorResult instances are destroyed without doing anything useful with exceptions on them. r=peterv (e328785e5d)
- Bug 1224007 part 5. Get rid of ErrorResult::StealJSException. r=peterv (db19cfb31e)
- Bug 1224007 part 3. Push down WouldReportJSException into MaybeSetPendingException, since anyone calling the latter will propagate the JS exception as needed. r=peterv (1d3b7b415d)
- Bug 1224007 part 6. Change MaybeSetPendingException to set the ErrorResult state to "not failed", just like SuppressException and StealNSResult already do, and assert in the destructor that the ErrorResult is not Failed(). (a028838e8d)
- Bug 1213815 - Update URLSearchParams and URLUtils in webidl files, r=bz (28fb8f7de5)
- Bug 1213815 - dom/webidl/HTMLHyperlinkElementUtils and URL don't need to throw exceptions as we did before, r=bz (b13dc3bcb9)
- Bug 1224596 part 14. Switch URL to using the new WorkerMainThreadRunnable::Dispatch signature. r=baku (232677e50e)
- fix updating the backport (9e958da5ca)
- Bug 1224596 part 16. Switch Fetch to using the new WorkerMainThreadRunnable::Dispatch signature. r=bkelly (939e338f22)
- Bug 1224596 part 17. Remove the old WorkerMainThreadRunnable::Dispatch signature. r=khuey (5a70429ec8)
- Bug 1143575. Don't report negative frame delays. r=cpearce (7d8bc0f753)
- Bug 1187371 - Get rid of dom.broadcastChannel.enabled pref, r=bz (9335b7ae90)
- Bug 1196514 - remove dom.messagechannel.enabled pref, r=smaug (31e06119b4)
- Bug 1166356 - Properly detect double-caching in nsXULPrototypeCache; r=ehsan (29df9ffb2d)
- Bug 1168916 - Get rid of redundant pref callback in nsXULPrototypeCache; r=janv (9f37fff405)
- Bug 1139099: Dispatch DOMDocElementInserted to match the document-element-inserted observer notification. r=mrbkap (6565e4b924)
- Bug 1187068 - Tell the cycle collector about nsContentSink::mCSSLoader. r=heycam (4ae23eb26c)
- Bug 1172189 - Fix overflow in nsXULContentSink.cpp. r=ehsan (cc6330f5de)
- Bug 1126010 - XULContentSinkImpl::mParser should be an nsRefPtr. r=smaug (d6bb567692)
- Bug 1147946, part 7 - Remove trailing whitespace from nsXULContentSink.cpp. r=baku (cdcadbfeeb)
- Bug 1147946, part 1 - Tuck elses in nsXULContentSink.cpp. r=baku (26fd806676)
- Bug 1147946, part 2 - Move body of check inside prior if in XULContentSinkImpl::OpenScript(). r=baku (b509455bdb)
- Bug 1147946, part 3 - Eliminate unused case for non-JS scripting languages in XULContentSinkImpl::OpenScript(). r=baku (4136933cc2)
- Bug 1147946, part 4 - Use an early return in XULContentSinkImpl::OpenScript(). r=baku (c3e293474b)
- Bug 1147946, part 5 - Don't use the generic nsIProgrammingLanguage enum in XULContentSinkImpl::OpenScript(). r=baku (89a124e23f)
- Bug 1147946, part 6 - Remove some useless null checks on infallible new in XULContentSinkImpl. r=baku (1ac57e8c3a)
- Bug 1221351 P1 ServiceWorkerContainer and ServiceWorkerRegistration should not crash for null window owner. r=catalinb (1a72748632)
- Bug 1212867 - Node.isEqualNode() should ignore internal subsets; r=bzBug (99b166ffee)
- Bug 492933 - getElementsByTagName should match on localName not tagName, r=smaug (d0c6ceabf1)
- Bug 912470 part 1 - Implement Encoding Standard-compliant big5 decoder. r=emk. (c680b0ae9b)
- Bug 1170932: Test handling of unmapped characters in unicode-to-codepage encoders (ca36bcbd35)
- fix style (95a90bfe3a)
- Bug 1170794 - patch 2 - Improve the length check of the input in nsUnicode*::GetMaxLength, r=dveditz (aa864d656f)
- Bug 1170794 followup: Add 'override' annotations to Convert() & Reset() methods in intl/uconv. rs=ehsan (bb3e6e492e)
- Bug 1176462 - Remove nsTableDecoderSupport. r=smontagu (f4a86c44b3)
- Bug 1169248 - Fix GBK/GB18030 encoders. r=smontagu (ed946e1ee1)
- Bug 1155539 - Remove obsolete encoding decoder telemetry probes. r=emk. (44e15bfb40)
- Bug 912470 part 2 - Implement Encoding Standard-compliant big5 encoder. r=emk. (5cca2dc4a0)
- Bug 912470 addendum - Pass override static analysis. r=emk. (c163bffeb4)
- Bug 1170932: Improve error handling for the gbk encoder, r=emk (30e95b34a5)
- Bug 1202366 - Implement the encoder error mode "HTML" for nsFormSubmission without nsISaveAsCharset. r=NOT_emk. (ebc8b542dd)
- update manifest (6cc19172cc)
- Bug 1197309 - remove PR_snprintf calls in intl/; r=froydnj (79fcdfa845)
- Bug 1214619 - Remove nsISaveAsCharset as much as possible without breaking extensions in popular use. r=emk. (89b71b3d87)
- Bug 1214857. Store the document-is-HTML state directly in nsContentList instead of refetching from the node being matched. r=smaug (4c4fbf469e)
- Bug 1221351 P2 Add a web-platform-test to check for crash when calling .register() on closed window. r=catalinb (eeb30c1bba)
- Bug 1221351 P3 Fix test name in register-closed-window.https.html. a=testonly (5bfa840044)
- Bug 1224436: Remove enumerator usage in ServiceWorkerManager.cpp. r=njn (b8cb094d3c)
- Bug 1223716. Make HTMLCollection check for the element being HTML before checking for its name inside its named getter. r=bkelly (977e0bff5a)
- Bug 1180737 - Add update-test.py and update test to latest version. r=bkelly. (59faa36d5c)
- Bug 1217909 P4 Extend wpt tests to verify update() promise values for different script failures. r=catalinb (a2f7352a3a)
- Bug 1217909 P5 Add wpt test case for fetch event handlers that throw. r=catalinb (56a77f611c)
- Bug 1217909 P6 Fix wpt registration.https.html to expect TypeError for script evaluation errors. r=catalinb (3de8a45688)
- Bug 1217909 P7 Fix mochitest to expect TypeError when serviceWorker.register() rejects. r=catalinb (6e8841c41e)
- Bug 1217909 P8 Track navigation interceptions per scope in ServiceWorkerManager. r=catalinb (6705ba8337)
- Bug 1217909 P9 Report exceptions to windows performing an intercepted navigation. r=catalinb (52f9fece14)
- Bug 1217909 P10 Remove stale nsTArray when the last registering document for a scope is removed. r=catalinb (b739bcc3b2)
- Bug 1217909 P11 Only report errors to documents that are active and not in the bfcache. r=catalinb (5ffd633af2)
- Bug 1223378 Tighten service worker register() principal checks. r=baku (478785f2cc)
- Bug 1189685 - Part 1: Ensure that the state of all ServiceWorker instances is up to date when dispatching statechange events; r=bkelly (2bd9b78c58)
- Bug 1189685 - Part 2: Make synced-state.https.html pass; r=bkelly (029f942d8c)
- Bug 1220740 - nsIServiceWorkerRegistrationInfo should emit an event when its worker properties change;r=amarchesini (8243a3debc)
- Bug 1186856 ServiceWorker .register() should always stop current registration from uninstalling. r=jdm (ec7d6e0e7c)
- Bug 1224941 Don't crash during ServiceWorker life cycle event dispatch if window is gone. r=baku (a3f45af3e4)
- Bug 1180754 - Get serviceworkerobject-scripturl test passing. r=bkelly (c7979bef47)
- Bug 1201498 - Service worker update should compare scriptURL to worker URL without fragment, r=bkelly (914f630528)
- Bug 594505 - Remove obsolete comment since this bug has now been fixed. r=me DONTBUILD (44f3a15b91)
- Bug 1221840. Support repeating images in 1 axis. r=seth (449ea3e97e)
- const-var (5433688051)
- Bug 1574573 - Disambiguate a use of Handle in XPCShellEnvironment.cpp r=Ehsan (15b44177d1)
- clean up warnings (6e64313d0c)
2023-02-14 09:56:52 +08:00

1670 lines
61 KiB
C++

/* -*- Mode: C++; tab-width: 2; 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/. */
/*
* representation of a declaration block (or style attribute) in a CSS
* stylesheet
*/
#include "mozilla/ArrayUtils.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/css/Declaration.h"
#include "nsPrintfCString.h"
#include "gfxFontConstants.h"
#include "nsStyleUtil.h"
namespace mozilla {
namespace css {
NS_IMPL_QUERY_INTERFACE(ImportantStyleData, nsIStyleRule)
NS_IMPL_ADDREF_USING_AGGREGATOR(ImportantStyleData, Declaration())
NS_IMPL_RELEASE_USING_AGGREGATOR(ImportantStyleData, Declaration())
/* virtual */ void
ImportantStyleData::MapRuleInfoInto(nsRuleData* aRuleData)
{
Declaration()->MapImportantRuleInfoInto(aRuleData);
}
/* virtual */ bool
ImportantStyleData::MightMapInheritedStyleData()
{
return Declaration()->MapsImportantInheritedStyleData();
}
#ifdef DEBUG
/* virtual */ void
ImportantStyleData::List(FILE* out, int32_t aIndent) const
{
// Indent
nsAutoCString str;
for (int32_t index = aIndent; --index >= 0; ) {
str.AppendLiteral(" ");
}
str.AppendLiteral("! important rule\n");
fprintf_stderr(out, "%s", str.get());
}
#endif
Declaration::Declaration()
: mImmutable(false)
{
mContainer.mRaw = uintptr_t(0);
}
Declaration::Declaration(const Declaration& aCopy)
: mOrder(aCopy.mOrder),
mVariableOrder(aCopy.mVariableOrder),
mData(aCopy.mData ? aCopy.mData->Clone() : nullptr),
mImportantData(aCopy.mImportantData ?
aCopy.mImportantData->Clone() : nullptr),
mVariables(aCopy.mVariables ?
new CSSVariableDeclarations(*aCopy.mVariables) :
nullptr),
mImportantVariables(aCopy.mImportantVariables ?
new CSSVariableDeclarations(*aCopy.mImportantVariables) :
nullptr),
mImmutable(false)
{
mContainer.mRaw = uintptr_t(0);
}
Declaration::~Declaration()
{
}
NS_INTERFACE_MAP_BEGIN(Declaration)
if (aIID.Equals(NS_GET_IID(mozilla::css::Declaration))) {
*aInstancePtr = this;
NS_ADDREF_THIS();
return NS_OK;
}
else
NS_INTERFACE_MAP_ENTRY(nsIStyleRule)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStyleRule)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(Declaration)
NS_IMPL_RELEASE(Declaration)
/* virtual */ void
Declaration::MapRuleInfoInto(nsRuleData* aRuleData)
{
MOZ_ASSERT(mData, "must call only while compressed");
mData->MapRuleInfoInto(aRuleData);
if (mVariables) {
mVariables->MapRuleInfoInto(aRuleData);
}
}
/* virtual */ bool
Declaration::MightMapInheritedStyleData()
{
MOZ_ASSERT(mData, "must call only while compressed");
if (mVariables && mVariables->Count() != 0) {
return true;
}
return mData->HasInheritedStyleData();
}
bool
Declaration::MapsImportantInheritedStyleData() const
{
MOZ_ASSERT(mData, "must call only while compressed");
MOZ_ASSERT(HasImportantData(), "must only be called for Declarations with "
"important data");
if (mImportantVariables && mImportantVariables->Count() != 0) {
return true;
}
return mImportantData ? mImportantData->HasInheritedStyleData() : false;
}
void
Declaration::ValueAppended(nsCSSProperty aProperty)
{
MOZ_ASSERT(!mData && !mImportantData,
"should only be called while expanded");
MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty),
"shorthands forbidden");
// order IS important for CSS, so remove and add to the end
mOrder.RemoveElement(static_cast<uint32_t>(aProperty));
mOrder.AppendElement(static_cast<uint32_t>(aProperty));
}
void
Declaration::RemoveProperty(nsCSSProperty aProperty)
{
MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT);
nsCSSExpandedDataBlock data;
ExpandTo(&data);
MOZ_ASSERT(!mData && !mImportantData, "Expand didn't null things out");
if (nsCSSProps::IsShorthand(aProperty)) {
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty,
nsCSSProps::eEnabledForAllContent) {
data.ClearLonghandProperty(*p);
mOrder.RemoveElement(static_cast<uint32_t>(*p));
}
} else {
data.ClearLonghandProperty(aProperty);
mOrder.RemoveElement(static_cast<uint32_t>(aProperty));
}
CompressFrom(&data);
}
bool
Declaration::HasProperty(nsCSSProperty aProperty) const
{
MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_no_shorthands,
"property ID out of range");
nsCSSCompressedDataBlock *data = GetValueIsImportant(aProperty)
? mImportantData : mData;
const nsCSSValue *val = data->ValueFor(aProperty);
return !!val;
}
bool
Declaration::AppendValueToString(nsCSSProperty aProperty,
nsAString& aResult,
nsCSSValue::Serialization aSerialization) const
{
MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_no_shorthands,
"property ID out of range");
nsCSSCompressedDataBlock *data = GetValueIsImportant(aProperty)
? mImportantData : mData;
const nsCSSValue *val = data->ValueFor(aProperty);
if (!val) {
return false;
}
val->AppendToString(aProperty, aResult, aSerialization);
return true;
}
void
Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue) const
{
GetValue(aProperty, aValue, nsCSSValue::eNormalized);
}
void
Declaration::GetAuthoredValue(nsCSSProperty aProperty, nsAString& aValue) const
{
GetValue(aProperty, aValue, nsCSSValue::eAuthorSpecified);
}
void
Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue,
nsCSSValue::Serialization aSerialization) const
{
aValue.Truncate(0);
// simple properties are easy.
if (!nsCSSProps::IsShorthand(aProperty)) {
AppendValueToString(aProperty, aValue, aSerialization);
return;
}
// DOM Level 2 Style says (when describing CSS2Properties, although
// not CSSStyleDeclaration.getPropertyValue):
// However, if there is no shorthand declaration that could be added
// to the ruleset without changing in any way the rules already
// declared in the ruleset (i.e., by adding longhand rules that were
// previously not declared in the ruleset), then the empty string
// should be returned for the shorthand property.
// This means we need to check a number of cases:
// (1) Since a shorthand sets all sub-properties, if some of its
// subproperties were not specified, we must return the empty
// string.
// (2) Since 'inherit', 'initial' and 'unset' can only be specified
// as the values for entire properties, we need to return the
// empty string if some but not all of the subproperties have one
// of those values.
// (3) Since a single value only makes sense with or without
// !important, we return the empty string if some values are
// !important and some are not.
// Since we're doing this check for 'inherit' and 'initial' up front,
// we can also simplify the property serialization code by serializing
// those values up front as well.
//
// Additionally, if a shorthand property was set using a value with a
// variable reference and none of its component longhand properties were
// then overridden on the declaration, we return the token stream
// assigned to the shorthand.
const nsCSSValue* tokenStream = nullptr;
uint32_t totalCount = 0, importantCount = 0,
initialCount = 0, inheritCount = 0, unsetCount = 0,
matchingTokenStreamCount = 0, nonMatchingTokenStreamCount = 0;
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty,
nsCSSProps::eEnabledForAllContent) {
if (*p == eCSSProperty__x_system_font) {
// The system-font subproperty doesn't count.
continue;
}
++totalCount;
const nsCSSValue *val = mData->ValueFor(*p);
MOZ_ASSERT(!val || !mImportantData || !mImportantData->ValueFor(*p),
"can't be in both blocks");
if (!val && mImportantData) {
++importantCount;
val = mImportantData->ValueFor(*p);
}
if (!val) {
// Case (1) above: some subproperties not specified.
return;
}
if (val->GetUnit() == eCSSUnit_Inherit) {
++inheritCount;
} else if (val->GetUnit() == eCSSUnit_Initial) {
++initialCount;
} else if (val->GetUnit() == eCSSUnit_Unset) {
++unsetCount;
} else if (val->GetUnit() == eCSSUnit_TokenStream) {
if (val->GetTokenStreamValue()->mShorthandPropertyID == aProperty) {
tokenStream = val;
++matchingTokenStreamCount;
} else {
++nonMatchingTokenStreamCount;
}
}
}
if (importantCount != 0 && importantCount != totalCount) {
// Case (3), no consistent importance.
return;
}
if (initialCount == totalCount) {
// Simplify serialization below by serializing initial up-front.
nsCSSValue(eCSSUnit_Initial).AppendToString(eCSSProperty_UNKNOWN, aValue,
nsCSSValue::eNormalized);
return;
}
if (inheritCount == totalCount) {
// Simplify serialization below by serializing inherit up-front.
nsCSSValue(eCSSUnit_Inherit).AppendToString(eCSSProperty_UNKNOWN, aValue,
nsCSSValue::eNormalized);
return;
}
if (unsetCount == totalCount) {
// Simplify serialization below by serializing unset up-front.
nsCSSValue(eCSSUnit_Unset).AppendToString(eCSSProperty_UNKNOWN, aValue,
nsCSSValue::eNormalized);
return;
}
if (initialCount != 0 || inheritCount != 0 ||
unsetCount != 0 || nonMatchingTokenStreamCount != 0) {
// Case (2): partially initial, inherit, unset or token stream.
return;
}
if (tokenStream) {
if (matchingTokenStreamCount == totalCount) {
// Shorthand was specified using variable references and all of its
// longhand components were set by the shorthand.
aValue.Append(tokenStream->GetTokenStreamValue()->mTokenStream);
} else {
// In all other cases, serialize to the empty string.
}
return;
}
nsCSSCompressedDataBlock *data = importantCount ? mImportantData : mData;
switch (aProperty) {
case eCSSProperty_margin:
case eCSSProperty_padding:
case eCSSProperty_border_color:
case eCSSProperty_border_style:
case eCSSProperty_border_width: {
const nsCSSProperty* subprops =
nsCSSProps::SubpropertyEntryFor(aProperty);
MOZ_ASSERT(nsCSSProps::GetStringValue(subprops[0]).Find("-top") !=
kNotFound, "first subprop must be top");
MOZ_ASSERT(nsCSSProps::GetStringValue(subprops[1]).Find("-right") !=
kNotFound, "second subprop must be right");
MOZ_ASSERT(nsCSSProps::GetStringValue(subprops[2]).Find("-bottom") !=
kNotFound, "third subprop must be bottom");
MOZ_ASSERT(nsCSSProps::GetStringValue(subprops[3]).Find("-left") !=
kNotFound, "fourth subprop must be left");
const nsCSSValue* vals[4] = {
data->ValueFor(subprops[0]),
data->ValueFor(subprops[1]),
data->ValueFor(subprops[2]),
data->ValueFor(subprops[3])
};
nsCSSValue::AppendSidesShorthandToString(subprops, vals, aValue,
aSerialization);
break;
}
case eCSSProperty_border_radius:
case eCSSProperty__moz_outline_radius: {
const nsCSSProperty* subprops =
nsCSSProps::SubpropertyEntryFor(aProperty);
const nsCSSValue* vals[4] = {
data->ValueFor(subprops[0]),
data->ValueFor(subprops[1]),
data->ValueFor(subprops[2]),
data->ValueFor(subprops[3])
};
nsCSSValue::AppendBasicShapeRadiusToString(subprops, vals, aValue,
aSerialization);
break;
}
case eCSSProperty_border_image: {
// Even though there are some cases where we could omit
// 'border-image-source' (when it's none), it's probably not a
// good idea since it's likely to be confusing. It would also
// require adding the extra check that we serialize *something*.
AppendValueToString(eCSSProperty_border_image_source, aValue,
aSerialization);
bool sliceDefault = data->HasDefaultBorderImageSlice();
bool widthDefault = data->HasDefaultBorderImageWidth();
bool outsetDefault = data->HasDefaultBorderImageOutset();
if (!sliceDefault || !widthDefault || !outsetDefault) {
aValue.Append(char16_t(' '));
AppendValueToString(eCSSProperty_border_image_slice, aValue,
aSerialization);
if (!widthDefault || !outsetDefault) {
aValue.AppendLiteral(" /");
if (!widthDefault) {
aValue.Append(char16_t(' '));
AppendValueToString(eCSSProperty_border_image_width, aValue,
aSerialization);
}
if (!outsetDefault) {
aValue.AppendLiteral(" / ");
AppendValueToString(eCSSProperty_border_image_outset, aValue,
aSerialization);
}
}
}
bool repeatDefault = data->HasDefaultBorderImageRepeat();
if (!repeatDefault) {
aValue.Append(char16_t(' '));
AppendValueToString(eCSSProperty_border_image_repeat, aValue,
aSerialization);
}
break;
}
case eCSSProperty_border: {
// If we have a non-default value for any of the properties that
// this shorthand sets but cannot specify, we have to return the
// empty string.
if (data->ValueFor(eCSSProperty_border_image_source)->GetUnit() !=
eCSSUnit_None ||
!data->HasDefaultBorderImageSlice() ||
!data->HasDefaultBorderImageWidth() ||
!data->HasDefaultBorderImageOutset() ||
!data->HasDefaultBorderImageRepeat() ||
data->ValueFor(eCSSProperty_border_top_colors)->GetUnit() !=
eCSSUnit_None ||
data->ValueFor(eCSSProperty_border_right_colors)->GetUnit() !=
eCSSUnit_None ||
data->ValueFor(eCSSProperty_border_bottom_colors)->GetUnit() !=
eCSSUnit_None ||
data->ValueFor(eCSSProperty_border_left_colors)->GetUnit() !=
eCSSUnit_None) {
break;
}
const nsCSSProperty* subproptables[3] = {
nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color),
nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_style),
nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_width)
};
bool match = true;
for (const nsCSSProperty** subprops = subproptables,
**subprops_end = ArrayEnd(subproptables);
subprops < subprops_end; ++subprops) {
const nsCSSValue *firstSide = data->ValueFor((*subprops)[0]);
for (int32_t side = 1; side < 4; ++side) {
const nsCSSValue *otherSide =
data->ValueFor((*subprops)[side]);
if (*firstSide != *otherSide)
match = false;
}
}
if (!match) {
// We can't express what we have in the border shorthand
break;
}
// tweak aProperty and fall through
aProperty = eCSSProperty_border_top;
}
case eCSSProperty_border_top:
case eCSSProperty_border_right:
case eCSSProperty_border_bottom:
case eCSSProperty_border_left:
case eCSSProperty_border_inline_start:
case eCSSProperty_border_inline_end:
case eCSSProperty_border_block_start:
case eCSSProperty_border_block_end:
case eCSSProperty_column_rule:
case eCSSProperty_outline: {
const nsCSSProperty* subprops =
nsCSSProps::SubpropertyEntryFor(aProperty);
MOZ_ASSERT(StringEndsWith(nsCSSProps::GetStringValue(subprops[2]),
NS_LITERAL_CSTRING("-color")),
"third subprop must be the color property");
const nsCSSValue *colorValue = data->ValueFor(subprops[2]);
bool isMozUseTextColor =
colorValue->GetUnit() == eCSSUnit_Enumerated &&
colorValue->GetIntValue() == NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR;
if (!AppendValueToString(subprops[0], aValue, aSerialization) ||
!(aValue.Append(char16_t(' ')),
AppendValueToString(subprops[1], aValue, aSerialization)) ||
// Don't output a third value when it's -moz-use-text-color.
!(isMozUseTextColor ||
(aValue.Append(char16_t(' ')),
AppendValueToString(subprops[2], aValue, aSerialization)))) {
aValue.Truncate();
}
break;
}
case eCSSProperty_background: {
// We know from above that all subproperties were specified.
// However, we still can't represent that in the shorthand unless
// they're all lists of the same length. So if they're different
// lengths, we need to bail out.
// We also need to bail out if an item has background-clip and
// background-origin that are different and not the default
// values. (We omit them if they're both default.)
const nsCSSValueList *image =
data->ValueFor(eCSSProperty_background_image)->
GetListValue();
const nsCSSValuePairList *repeat =
data->ValueFor(eCSSProperty_background_repeat)->
GetPairListValue();
const nsCSSValueList *attachment =
data->ValueFor(eCSSProperty_background_attachment)->
GetListValue();
const nsCSSValueList *position =
data->ValueFor(eCSSProperty_background_position)->
GetListValue();
const nsCSSValueList *clip =
data->ValueFor(eCSSProperty_background_clip)->
GetListValue();
const nsCSSValueList *origin =
data->ValueFor(eCSSProperty_background_origin)->
GetListValue();
const nsCSSValuePairList *size =
data->ValueFor(eCSSProperty_background_size)->
GetPairListValue();
for (;;) {
// Serialize background-color at the beginning of the last item.
if (!image->mNext) {
AppendValueToString(eCSSProperty_background_color, aValue,
aSerialization);
aValue.Append(char16_t(' '));
}
image->mValue.AppendToString(eCSSProperty_background_image, aValue,
aSerialization);
aValue.Append(char16_t(' '));
repeat->mXValue.AppendToString(eCSSProperty_background_repeat, aValue,
aSerialization);
if (repeat->mYValue.GetUnit() != eCSSUnit_Null) {
repeat->mYValue.AppendToString(eCSSProperty_background_repeat, aValue,
aSerialization);
}
aValue.Append(char16_t(' '));
attachment->mValue.AppendToString(eCSSProperty_background_attachment,
aValue, aSerialization);
aValue.Append(char16_t(' '));
position->mValue.AppendToString(eCSSProperty_background_position,
aValue, aSerialization);
if (size->mXValue.GetUnit() != eCSSUnit_Auto ||
size->mYValue.GetUnit() != eCSSUnit_Auto) {
aValue.Append(char16_t(' '));
aValue.Append(char16_t('/'));
aValue.Append(char16_t(' '));
size->mXValue.AppendToString(eCSSProperty_background_size, aValue,
aSerialization);
aValue.Append(char16_t(' '));
size->mYValue.AppendToString(eCSSProperty_background_size, aValue,
aSerialization);
}
MOZ_ASSERT(clip->mValue.GetUnit() == eCSSUnit_Enumerated &&
origin->mValue.GetUnit() == eCSSUnit_Enumerated,
"should not have inherit/initial within list");
if (clip->mValue.GetIntValue() != NS_STYLE_BG_CLIP_BORDER ||
origin->mValue.GetIntValue() != NS_STYLE_BG_ORIGIN_PADDING) {
MOZ_ASSERT(nsCSSProps::kKeywordTableTable[
eCSSProperty_background_origin] ==
nsCSSProps::kBackgroundOriginKTable);
MOZ_ASSERT(nsCSSProps::kKeywordTableTable[
eCSSProperty_background_clip] ==
nsCSSProps::kBackgroundOriginKTable);
static_assert(NS_STYLE_BG_CLIP_BORDER ==
NS_STYLE_BG_ORIGIN_BORDER &&
NS_STYLE_BG_CLIP_PADDING ==
NS_STYLE_BG_ORIGIN_PADDING &&
NS_STYLE_BG_CLIP_CONTENT ==
NS_STYLE_BG_ORIGIN_CONTENT,
"bg-clip and bg-origin style constants must agree");
aValue.Append(char16_t(' '));
origin->mValue.AppendToString(eCSSProperty_background_origin, aValue,
aSerialization);
if (clip->mValue != origin->mValue) {
aValue.Append(char16_t(' '));
clip->mValue.AppendToString(eCSSProperty_background_clip, aValue,
aSerialization);
}
}
image = image->mNext;
repeat = repeat->mNext;
attachment = attachment->mNext;
position = position->mNext;
clip = clip->mNext;
origin = origin->mNext;
size = size->mNext;
if (!image) {
if (repeat || attachment || position || clip || origin || size) {
// Uneven length lists, so can't be serialized as shorthand.
aValue.Truncate();
return;
}
break;
}
if (!repeat || !attachment || !position || !clip || !origin || !size) {
// Uneven length lists, so can't be serialized as shorthand.
aValue.Truncate();
return;
}
aValue.Append(char16_t(','));
aValue.Append(char16_t(' '));
}
break;
}
case eCSSProperty_font: {
// systemFont might not be present; other values are guaranteed to be
// available based on the shorthand check at the beginning of the
// function, as long as the prop is enabled
const nsCSSValue *systemFont =
data->ValueFor(eCSSProperty__x_system_font);
const nsCSSValue *style =
data->ValueFor(eCSSProperty_font_style);
const nsCSSValue *weight =
data->ValueFor(eCSSProperty_font_weight);
const nsCSSValue *size =
data->ValueFor(eCSSProperty_font_size);
const nsCSSValue *lh =
data->ValueFor(eCSSProperty_line_height);
const nsCSSValue *family =
data->ValueFor(eCSSProperty_font_family);
const nsCSSValue *stretch =
data->ValueFor(eCSSProperty_font_stretch);
const nsCSSValue *sizeAdjust =
data->ValueFor(eCSSProperty_font_size_adjust);
const nsCSSValue *featureSettings =
data->ValueFor(eCSSProperty_font_feature_settings);
const nsCSSValue *languageOverride =
data->ValueFor(eCSSProperty_font_language_override);
const nsCSSValue *fontKerning =
data->ValueFor(eCSSProperty_font_kerning);
const nsCSSValue *fontSynthesis =
data->ValueFor(eCSSProperty_font_synthesis);
const nsCSSValue *fontVariantAlternates =
data->ValueFor(eCSSProperty_font_variant_alternates);
const nsCSSValue *fontVariantCaps =
data->ValueFor(eCSSProperty_font_variant_caps);
const nsCSSValue *fontVariantEastAsian =
data->ValueFor(eCSSProperty_font_variant_east_asian);
const nsCSSValue *fontVariantLigatures =
data->ValueFor(eCSSProperty_font_variant_ligatures);
const nsCSSValue *fontVariantNumeric =
data->ValueFor(eCSSProperty_font_variant_numeric);
const nsCSSValue *fontVariantPosition =
data->ValueFor(eCSSProperty_font_variant_position);
if (systemFont &&
systemFont->GetUnit() != eCSSUnit_None &&
systemFont->GetUnit() != eCSSUnit_Null) {
if (style->GetUnit() != eCSSUnit_System_Font ||
weight->GetUnit() != eCSSUnit_System_Font ||
size->GetUnit() != eCSSUnit_System_Font ||
lh->GetUnit() != eCSSUnit_System_Font ||
family->GetUnit() != eCSSUnit_System_Font ||
stretch->GetUnit() != eCSSUnit_System_Font ||
sizeAdjust->GetUnit() != eCSSUnit_System_Font ||
featureSettings->GetUnit() != eCSSUnit_System_Font ||
languageOverride->GetUnit() != eCSSUnit_System_Font ||
fontKerning->GetUnit() != eCSSUnit_System_Font ||
fontSynthesis->GetUnit() != eCSSUnit_System_Font ||
fontVariantAlternates->GetUnit() != eCSSUnit_System_Font ||
fontVariantCaps->GetUnit() != eCSSUnit_System_Font ||
fontVariantEastAsian->GetUnit() != eCSSUnit_System_Font ||
fontVariantLigatures->GetUnit() != eCSSUnit_System_Font ||
fontVariantNumeric->GetUnit() != eCSSUnit_System_Font ||
fontVariantPosition->GetUnit() != eCSSUnit_System_Font) {
// This can't be represented as a shorthand.
return;
}
systemFont->AppendToString(eCSSProperty__x_system_font, aValue,
aSerialization);
} else {
// properties reset by this shorthand property to their
// initial values but not represented in its syntax
if (sizeAdjust->GetUnit() != eCSSUnit_None ||
featureSettings->GetUnit() != eCSSUnit_Normal ||
languageOverride->GetUnit() != eCSSUnit_Normal ||
fontKerning->GetIntValue() != NS_FONT_KERNING_AUTO ||
fontSynthesis->GetUnit() != eCSSUnit_Enumerated ||
fontSynthesis->GetIntValue() !=
(NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE) ||
fontVariantAlternates->GetUnit() != eCSSUnit_Normal ||
fontVariantEastAsian->GetUnit() != eCSSUnit_Normal ||
fontVariantLigatures->GetUnit() != eCSSUnit_Normal ||
fontVariantNumeric->GetUnit() != eCSSUnit_Normal ||
fontVariantPosition->GetUnit() != eCSSUnit_Normal) {
return;
}
// only a normal or small-caps values of font-variant-caps can
// be represented in the font shorthand
if (fontVariantCaps->GetUnit() != eCSSUnit_Normal &&
(fontVariantCaps->GetUnit() != eCSSUnit_Enumerated ||
fontVariantCaps->GetIntValue() != NS_FONT_VARIANT_CAPS_SMALLCAPS)) {
return;
}
if (style->GetUnit() != eCSSUnit_Enumerated ||
style->GetIntValue() != NS_FONT_STYLE_NORMAL) {
style->AppendToString(eCSSProperty_font_style, aValue,
aSerialization);
aValue.Append(char16_t(' '));
}
if (fontVariantCaps->GetUnit() != eCSSUnit_Normal) {
fontVariantCaps->AppendToString(eCSSProperty_font_variant_caps, aValue,
aSerialization);
aValue.Append(char16_t(' '));
}
if (weight->GetUnit() != eCSSUnit_Enumerated ||
weight->GetIntValue() != NS_FONT_WEIGHT_NORMAL) {
weight->AppendToString(eCSSProperty_font_weight, aValue,
aSerialization);
aValue.Append(char16_t(' '));
}
if (stretch->GetUnit() != eCSSUnit_Enumerated ||
stretch->GetIntValue() != NS_FONT_STRETCH_NORMAL) {
stretch->AppendToString(eCSSProperty_font_stretch, aValue,
aSerialization);
aValue.Append(char16_t(' '));
}
size->AppendToString(eCSSProperty_font_size, aValue, aSerialization);
if (lh->GetUnit() != eCSSUnit_Normal) {
aValue.Append(char16_t('/'));
lh->AppendToString(eCSSProperty_line_height, aValue, aSerialization);
}
aValue.Append(char16_t(' '));
family->AppendToString(eCSSProperty_font_family, aValue,
aSerialization);
}
break;
}
case eCSSProperty_font_variant: {
const nsCSSProperty *subprops =
nsCSSProps::SubpropertyEntryFor(aProperty);
const nsCSSValue *fontVariantLigatures =
data->ValueFor(eCSSProperty_font_variant_ligatures);
// all subproperty values normal? system font?
bool normalLigs = true, normalNonLigs = true, systemFont = true,
hasSystem = false;
for (const nsCSSProperty *sp = subprops; *sp != eCSSProperty_UNKNOWN; sp++) {
const nsCSSValue *spVal = data->ValueFor(*sp);
bool isNormal = (spVal->GetUnit() == eCSSUnit_Normal);
if (*sp == eCSSProperty_font_variant_ligatures) {
normalLigs = normalLigs && isNormal;
} else {
normalNonLigs = normalNonLigs && isNormal;
}
bool isSystem = (spVal->GetUnit() == eCSSUnit_System_Font);
systemFont = systemFont && isSystem;
hasSystem = hasSystem || isSystem;
}
bool ligsNone =
fontVariantLigatures->GetUnit() == eCSSUnit_None;
// normal, none, or system font ==> single value
if ((normalLigs && normalNonLigs) ||
(normalNonLigs && ligsNone) ||
systemFont) {
fontVariantLigatures->AppendToString(eCSSProperty_font_variant_ligatures,
aValue,
aSerialization);
} else if (ligsNone || hasSystem) {
// ligatures none but other values are non-normal ==> empty
// at least one but not all values are system font ==> empty
return;
} else {
// iterate over and append non-normal values
bool appendSpace = false;
for (const nsCSSProperty *sp = subprops;
*sp != eCSSProperty_UNKNOWN; sp++) {
const nsCSSValue *spVal = data->ValueFor(*sp);
if (spVal && spVal->GetUnit() != eCSSUnit_Normal) {
if (appendSpace) {
aValue.Append(char16_t(' '));
} else {
appendSpace = true;
}
spVal->AppendToString(*sp, aValue, aSerialization);
}
}
}
break;
}
case eCSSProperty_list_style:
if (AppendValueToString(eCSSProperty_list_style_position, aValue,
aSerialization)) {
aValue.Append(char16_t(' '));
}
if (AppendValueToString(eCSSProperty_list_style_image, aValue,
aSerialization)) {
aValue.Append(char16_t(' '));
}
AppendValueToString(eCSSProperty_list_style_type, aValue,
aSerialization);
break;
case eCSSProperty_overflow: {
const nsCSSValue &xValue =
*data->ValueFor(eCSSProperty_overflow_x);
const nsCSSValue &yValue =
*data->ValueFor(eCSSProperty_overflow_y);
if (xValue == yValue)
xValue.AppendToString(eCSSProperty_overflow_x, aValue, aSerialization);
break;
}
case eCSSProperty_text_decoration: {
const nsCSSValue *decorationColor =
data->ValueFor(eCSSProperty_text_decoration_color);
const nsCSSValue *decorationStyle =
data->ValueFor(eCSSProperty_text_decoration_style);
MOZ_ASSERT(decorationStyle->GetUnit() == eCSSUnit_Enumerated,
"bad text-decoration-style unit");
AppendValueToString(eCSSProperty_text_decoration_line, aValue,
aSerialization);
if (decorationStyle->GetIntValue() !=
NS_STYLE_TEXT_DECORATION_STYLE_SOLID) {
aValue.Append(char16_t(' '));
AppendValueToString(eCSSProperty_text_decoration_style, aValue,
aSerialization);
}
if (decorationColor->GetUnit() != eCSSUnit_Enumerated ||
decorationColor->GetIntValue() != NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR) {
aValue.Append(char16_t(' '));
AppendValueToString(eCSSProperty_text_decoration_color, aValue,
aSerialization);
}
break;
}
case eCSSProperty_transition: {
const nsCSSValue *transProp =
data->ValueFor(eCSSProperty_transition_property);
const nsCSSValue *transDuration =
data->ValueFor(eCSSProperty_transition_duration);
const nsCSSValue *transTiming =
data->ValueFor(eCSSProperty_transition_timing_function);
const nsCSSValue *transDelay =
data->ValueFor(eCSSProperty_transition_delay);
MOZ_ASSERT(transDuration->GetUnit() == eCSSUnit_List ||
transDuration->GetUnit() == eCSSUnit_ListDep,
"bad t-duration unit");
MOZ_ASSERT(transTiming->GetUnit() == eCSSUnit_List ||
transTiming->GetUnit() == eCSSUnit_ListDep,
"bad t-timing unit");
MOZ_ASSERT(transDelay->GetUnit() == eCSSUnit_List ||
transDelay->GetUnit() == eCSSUnit_ListDep,
"bad t-delay unit");
const nsCSSValueList* dur = transDuration->GetListValue();
const nsCSSValueList* tim = transTiming->GetListValue();
const nsCSSValueList* del = transDelay->GetListValue();
if (transProp->GetUnit() == eCSSUnit_None ||
transProp->GetUnit() == eCSSUnit_All) {
// If any of the other three lists has more than one element,
// we can't use the shorthand.
if (!dur->mNext && !tim->mNext && !del->mNext) {
transProp->AppendToString(eCSSProperty_transition_property, aValue,
aSerialization);
aValue.Append(char16_t(' '));
dur->mValue.AppendToString(eCSSProperty_transition_duration,aValue,
aSerialization);
aValue.Append(char16_t(' '));
tim->mValue.AppendToString(eCSSProperty_transition_timing_function,
aValue, aSerialization);
aValue.Append(char16_t(' '));
del->mValue.AppendToString(eCSSProperty_transition_delay, aValue,
aSerialization);
aValue.Append(char16_t(' '));
} else {
aValue.Truncate();
}
} else {
MOZ_ASSERT(transProp->GetUnit() == eCSSUnit_List ||
transProp->GetUnit() == eCSSUnit_ListDep,
"bad t-prop unit");
const nsCSSValueList* pro = transProp->GetListValue();
for (;;) {
pro->mValue.AppendToString(eCSSProperty_transition_property,
aValue, aSerialization);
aValue.Append(char16_t(' '));
dur->mValue.AppendToString(eCSSProperty_transition_duration,
aValue, aSerialization);
aValue.Append(char16_t(' '));
tim->mValue.AppendToString(eCSSProperty_transition_timing_function,
aValue, aSerialization);
aValue.Append(char16_t(' '));
del->mValue.AppendToString(eCSSProperty_transition_delay,
aValue, aSerialization);
pro = pro->mNext;
dur = dur->mNext;
tim = tim->mNext;
del = del->mNext;
if (!pro || !dur || !tim || !del) {
break;
}
aValue.AppendLiteral(", ");
}
if (pro || dur || tim || del) {
// Lists not all the same length, can't use shorthand.
aValue.Truncate();
}
}
break;
}
case eCSSProperty_animation: {
const nsCSSProperty* subprops =
nsCSSProps::SubpropertyEntryFor(eCSSProperty_animation);
static const size_t numProps = 8;
MOZ_ASSERT(subprops[numProps] == eCSSProperty_UNKNOWN,
"unexpected number of subproperties");
const nsCSSValue* values[numProps];
const nsCSSValueList* lists[numProps];
for (uint32_t i = 0; i < numProps; ++i) {
values[i] = data->ValueFor(subprops[i]);
MOZ_ASSERT(values[i]->GetUnit() == eCSSUnit_List ||
values[i]->GetUnit() == eCSSUnit_ListDep,
"bad a-duration unit");
lists[i] = values[i]->GetListValue();
}
for (;;) {
// We must serialize 'animation-name' last in case it has
// a value that conflicts with one of the other keyword properties.
MOZ_ASSERT(subprops[numProps - 1] == eCSSProperty_animation_name,
"animation-name must be last");
bool done = false;
for (uint32_t i = 0;;) {
lists[i]->mValue.AppendToString(subprops[i], aValue, aSerialization);
lists[i] = lists[i]->mNext;
if (!lists[i]) {
done = true;
}
if (++i == numProps) {
break;
}
aValue.Append(char16_t(' '));
}
if (done) {
break;
}
aValue.AppendLiteral(", ");
}
for (uint32_t i = 0; i < numProps; ++i) {
if (lists[i]) {
// Lists not all the same length, can't use shorthand.
aValue.Truncate();
break;
}
}
break;
}
case eCSSProperty_marker: {
const nsCSSValue &endValue =
*data->ValueFor(eCSSProperty_marker_end);
const nsCSSValue &midValue =
*data->ValueFor(eCSSProperty_marker_mid);
const nsCSSValue &startValue =
*data->ValueFor(eCSSProperty_marker_start);
if (endValue == midValue && midValue == startValue)
AppendValueToString(eCSSProperty_marker_end, aValue, aSerialization);
break;
}
case eCSSProperty_columns: {
// Two values, column-count and column-width, separated by a space.
const nsCSSProperty* subprops =
nsCSSProps::SubpropertyEntryFor(aProperty);
AppendValueToString(subprops[0], aValue, aSerialization);
aValue.Append(char16_t(' '));
AppendValueToString(subprops[1], aValue, aSerialization);
break;
}
case eCSSProperty_flex: {
// flex-grow, flex-shrink, flex-basis, separated by single space
const nsCSSProperty* subprops =
nsCSSProps::SubpropertyEntryFor(aProperty);
AppendValueToString(subprops[0], aValue, aSerialization);
aValue.Append(char16_t(' '));
AppendValueToString(subprops[1], aValue, aSerialization);
aValue.Append(char16_t(' '));
AppendValueToString(subprops[2], aValue, aSerialization);
break;
}
case eCSSProperty_flex_flow: {
// flex-direction, flex-wrap, separated by single space
const nsCSSProperty* subprops =
nsCSSProps::SubpropertyEntryFor(aProperty);
MOZ_ASSERT(subprops[2] == eCSSProperty_UNKNOWN,
"must have exactly two subproperties");
AppendValueToString(subprops[0], aValue, aSerialization);
aValue.Append(char16_t(' '));
AppendValueToString(subprops[1], aValue, aSerialization);
break;
}
case eCSSProperty_grid_row:
case eCSSProperty_grid_column: {
// grid-{row,column}-start, grid-{row,column}-end, separated by a slash
const nsCSSProperty* subprops =
nsCSSProps::SubpropertyEntryFor(aProperty);
MOZ_ASSERT(subprops[2] == eCSSProperty_UNKNOWN,
"must have exactly two subproperties");
// TODO: should we simplify when possible?
AppendValueToString(subprops[0], aValue, aSerialization);
aValue.AppendLiteral(" / ");
AppendValueToString(subprops[1], aValue, aSerialization);
break;
}
case eCSSProperty_grid_area: {
const nsCSSProperty* subprops =
nsCSSProps::SubpropertyEntryFor(aProperty);
MOZ_ASSERT(subprops[4] == eCSSProperty_UNKNOWN,
"must have exactly four subproperties");
// TODO: should we simplify when possible?
AppendValueToString(subprops[0], aValue, aSerialization);
aValue.AppendLiteral(" / ");
AppendValueToString(subprops[1], aValue, aSerialization);
aValue.AppendLiteral(" / ");
AppendValueToString(subprops[2], aValue, aSerialization);
aValue.AppendLiteral(" / ");
AppendValueToString(subprops[3], aValue, aSerialization);
break;
}
// This can express either grid-template-{areas,columns,rows}
// or grid-auto-{flow,columns,rows}, but not both.
case eCSSProperty_grid: {
const nsCSSValue& columnGapValue =
*data->ValueFor(eCSSProperty_grid_column_gap);
if (columnGapValue.GetUnit() != eCSSUnit_Pixel ||
columnGapValue.GetFloatValue() != 0.0f) {
return; // Not serializable, bail.
}
const nsCSSValue& rowGapValue =
*data->ValueFor(eCSSProperty_grid_row_gap);
if (rowGapValue.GetUnit() != eCSSUnit_Pixel ||
rowGapValue.GetFloatValue() != 0.0f) {
return; // Not serializable, bail.
}
const nsCSSValue& areasValue =
*data->ValueFor(eCSSProperty_grid_template_areas);
const nsCSSValue& columnsValue =
*data->ValueFor(eCSSProperty_grid_template_columns);
const nsCSSValue& rowsValue =
*data->ValueFor(eCSSProperty_grid_template_rows);
const nsCSSValue& autoFlowValue =
*data->ValueFor(eCSSProperty_grid_auto_flow);
const nsCSSValue& autoColumnsValue =
*data->ValueFor(eCSSProperty_grid_auto_columns);
const nsCSSValue& autoRowsValue =
*data->ValueFor(eCSSProperty_grid_auto_rows);
if (areasValue.GetUnit() == eCSSUnit_None &&
columnsValue.GetUnit() == eCSSUnit_None &&
rowsValue.GetUnit() == eCSSUnit_None) {
AppendValueToString(eCSSProperty_grid_auto_flow,
aValue, aSerialization);
aValue.Append(char16_t(' '));
AppendValueToString(eCSSProperty_grid_auto_columns,
aValue, aSerialization);
aValue.AppendLiteral(" / ");
AppendValueToString(eCSSProperty_grid_auto_rows,
aValue, aSerialization);
break;
} else if (!(autoFlowValue.GetUnit() == eCSSUnit_Enumerated &&
autoFlowValue.GetIntValue() == NS_STYLE_GRID_AUTO_FLOW_ROW &&
autoColumnsValue.GetUnit() == eCSSUnit_Auto &&
autoRowsValue.GetUnit() == eCSSUnit_Auto)) {
// Not serializable, bail.
return;
}
// Fall through to eCSSProperty_grid_template
}
case eCSSProperty_grid_template: {
const nsCSSValue& areasValue =
*data->ValueFor(eCSSProperty_grid_template_areas);
const nsCSSValue& columnsValue =
*data->ValueFor(eCSSProperty_grid_template_columns);
const nsCSSValue& rowsValue =
*data->ValueFor(eCSSProperty_grid_template_rows);
if (areasValue.GetUnit() == eCSSUnit_None) {
AppendValueToString(eCSSProperty_grid_template_columns,
aValue, aSerialization);
aValue.AppendLiteral(" / ");
AppendValueToString(eCSSProperty_grid_template_rows,
aValue, aSerialization);
break;
}
if (columnsValue.GetUnit() == eCSSUnit_List ||
columnsValue.GetUnit() == eCSSUnit_ListDep) {
const nsCSSValueList* columnsItem = columnsValue.GetListValue();
if (columnsItem->mValue.GetUnit() == eCSSUnit_Enumerated &&
columnsItem->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) {
// We have "grid-template-areas:[something]; grid-template-columns:subgrid"
// which isn't a value that the shorthand can express. Bail.
return;
}
}
if (rowsValue.GetUnit() != eCSSUnit_List &&
rowsValue.GetUnit() != eCSSUnit_ListDep) {
// We have "grid-template-areas:[something]; grid-template-rows:none"
// which isn't a value that the shorthand can express. Bail.
return;
}
const nsCSSValueList* rowsItem = rowsValue.GetListValue();
if (rowsItem->mValue.GetUnit() == eCSSUnit_Enumerated &&
rowsItem->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) {
// We have "grid-template-areas:[something]; grid-template-rows:subgrid"
// which isn't a value that the shorthand can express. Bail.
return;
}
const GridTemplateAreasValue* areas = areasValue.GetGridTemplateAreas();
uint32_t nRowItems = 0;
while (rowsItem) {
nRowItems++;
rowsItem = rowsItem->mNext;
}
MOZ_ASSERT(nRowItems % 2 == 1, "expected an odd number of items");
if ((nRowItems - 1) / 2 != areas->NRows()) {
// Not serializable, bail.
return;
}
if (columnsValue.GetUnit() != eCSSUnit_None) {
AppendValueToString(eCSSProperty_grid_template_columns,
aValue, aSerialization);
aValue.AppendLiteral(" / ");
}
rowsItem = rowsValue.GetListValue();
uint32_t row = 0;
for (;;) {
bool addSpaceSeparator = true;
nsCSSUnit unit = rowsItem->mValue.GetUnit();
if (unit == eCSSUnit_Null) {
// Empty or omitted <line-names>. Serializes to nothing.
addSpaceSeparator = false; // Avoid a double space.
} else if (unit == eCSSUnit_List || unit == eCSSUnit_ListDep) {
// Non-empty <line-names>
aValue.Append('[');
rowsItem->mValue.AppendToString(eCSSProperty_grid_template_rows,
aValue, aSerialization);
aValue.Append(']');
} else {
nsStyleUtil::AppendEscapedCSSString(areas->mTemplates[row++], aValue);
aValue.Append(char16_t(' '));
// <track-size>
rowsItem->mValue.AppendToString(eCSSProperty_grid_template_rows,
aValue, aSerialization);
if (rowsItem->mNext &&
rowsItem->mNext->mValue.GetUnit() == eCSSUnit_Null &&
!rowsItem->mNext->mNext) {
// Break out of the loop early to avoid a trailing space.
break;
}
}
rowsItem = rowsItem->mNext;
if (!rowsItem) {
break;
}
if (addSpaceSeparator) {
aValue.Append(char16_t(' '));
}
}
break;
}
case eCSSProperty_grid_gap: {
const nsCSSProperty* subprops =
nsCSSProps::SubpropertyEntryFor(aProperty);
MOZ_ASSERT(subprops[2] == eCSSProperty_UNKNOWN,
"must have exactly two subproperties");
nsAutoString val1, val2;
AppendValueToString(subprops[0], val1, aSerialization);
AppendValueToString(subprops[1], val2, aSerialization);
if (val1 == val2) {
aValue.Append(val1);
} else {
aValue.Append(val1);
aValue.Append(' ');
aValue.Append(val2);
}
break;
}
case eCSSProperty_text_emphasis: {
const nsCSSValue* emphasisStyle =
data->ValueFor(eCSSProperty_text_emphasis_style);
const nsCSSValue* emphasisColor =
data->ValueFor(eCSSProperty_text_emphasis_color);
bool isDefaultColor = emphasisColor->GetUnit() == eCSSUnit_EnumColor &&
emphasisColor->GetIntValue() == NS_COLOR_CURRENTCOLOR;
if (emphasisStyle->GetUnit() != eCSSUnit_None || isDefaultColor) {
AppendValueToString(eCSSProperty_text_emphasis_style,
aValue, aSerialization);
if (!isDefaultColor) {
aValue.Append(char16_t(' '));
}
}
if (!isDefaultColor) {
AppendValueToString(eCSSProperty_text_emphasis_color,
aValue, aSerialization);
}
break;
}
case eCSSProperty__moz_transform: {
// shorthands that are just aliases with different parsing rules
const nsCSSProperty* subprops =
nsCSSProps::SubpropertyEntryFor(aProperty);
MOZ_ASSERT(subprops[1] == eCSSProperty_UNKNOWN,
"must have exactly one subproperty");
AppendValueToString(subprops[0], aValue, aSerialization);
break;
}
case eCSSProperty_scroll_snap_type: {
const nsCSSValue& xValue =
*data->ValueFor(eCSSProperty_scroll_snap_type_x);
const nsCSSValue& yValue =
*data->ValueFor(eCSSProperty_scroll_snap_type_y);
if (xValue == yValue) {
AppendValueToString(eCSSProperty_scroll_snap_type_x, aValue,
aSerialization);
}
// If scroll-snap-type-x and scroll-snap-type-y are not equal,
// we don't have a shorthand that can express. Bail.
break;
}
case eCSSProperty_all:
// If we got here, then we didn't have all "inherit" or "initial" or
// "unset" values for all of the longhand property components of 'all'.
// There is no other possible value that is valid for all properties,
// so serialize as the empty string.
break;
default:
MOZ_ASSERT(false, "no other shorthands");
break;
}
}
bool
Declaration::GetValueIsImportant(const nsAString& aProperty) const
{
nsCSSProperty propID =
nsCSSProps::LookupProperty(aProperty, nsCSSProps::eIgnoreEnabledState);
if (propID == eCSSProperty_UNKNOWN) {
return false;
}
if (propID == eCSSPropertyExtra_variable) {
const nsSubstring& variableName =
Substring(aProperty, CSS_CUSTOM_NAME_PREFIX_LENGTH);
return GetVariableValueIsImportant(variableName);
}
return GetValueIsImportant(propID);
}
bool
Declaration::GetValueIsImportant(nsCSSProperty aProperty) const
{
if (!mImportantData)
return false;
// Calling ValueFor is inefficient, but we can assume '!important' is rare.
if (!nsCSSProps::IsShorthand(aProperty)) {
return mImportantData->ValueFor(aProperty) != nullptr;
}
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty,
nsCSSProps::eEnabledForAllContent) {
if (*p == eCSSProperty__x_system_font) {
// The system_font subproperty doesn't count.
continue;
}
if (!mImportantData->ValueFor(*p)) {
return false;
}
}
return true;
}
void
Declaration::AppendPropertyAndValueToString(nsCSSProperty aProperty,
nsAutoString& aValue,
nsAString& aResult) const
{
MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT,
"property enum out of range");
MOZ_ASSERT((aProperty < eCSSProperty_COUNT_no_shorthands) == aValue.IsEmpty(),
"aValue should be given for shorthands but not longhands");
AppendASCIItoUTF16(nsCSSProps::GetStringValue(aProperty), aResult);
aResult.AppendLiteral(": ");
if (aValue.IsEmpty())
AppendValueToString(aProperty, aResult, nsCSSValue::eNormalized);
else
aResult.Append(aValue);
if (GetValueIsImportant(aProperty)) {
aResult.AppendLiteral(" ! important");
}
aResult.AppendLiteral("; ");
}
void
Declaration::AppendVariableAndValueToString(const nsAString& aName,
nsAString& aResult) const
{
aResult.AppendLiteral("--");
aResult.Append(aName);
CSSVariableDeclarations::Type type;
nsString value;
bool important;
if (mImportantVariables && mImportantVariables->Get(aName, type, value)) {
important = true;
} else {
MOZ_ASSERT(mVariables);
MOZ_ASSERT(mVariables->Has(aName));
mVariables->Get(aName, type, value);
important = false;
}
switch (type) {
case CSSVariableDeclarations::eTokenStream:
if (value.IsEmpty()) {
aResult.Append(':');
} else {
aResult.AppendLiteral(": ");
aResult.Append(value);
}
break;
case CSSVariableDeclarations::eInitial:
aResult.AppendLiteral("initial");
break;
case CSSVariableDeclarations::eInherit:
aResult.AppendLiteral("inherit");
break;
case CSSVariableDeclarations::eUnset:
aResult.AppendLiteral("unset");
break;
default:
MOZ_ASSERT(false, "unexpected variable value type");
}
if (important) {
aResult.AppendLiteral("! important");
}
aResult.AppendLiteral("; ");
}
void
Declaration::ToString(nsAString& aString) const
{
// Someone cares about this declaration's contents, so don't let it
// change from under them. See e.g. bug 338679.
SetImmutable();
nsCSSCompressedDataBlock *systemFontData =
GetValueIsImportant(eCSSProperty__x_system_font) ? mImportantData : mData;
const nsCSSValue *systemFont =
systemFontData->ValueFor(eCSSProperty__x_system_font);
const bool haveSystemFont = systemFont &&
systemFont->GetUnit() != eCSSUnit_None &&
systemFont->GetUnit() != eCSSUnit_Null;
bool didSystemFont = false;
int32_t count = mOrder.Length();
int32_t index;
nsAutoTArray<nsCSSProperty, 16> shorthandsUsed;
for (index = 0; index < count; index++) {
nsCSSProperty property = GetPropertyAt(index);
if (property == eCSSPropertyExtra_variable) {
uint32_t variableIndex = mOrder[index] - eCSSProperty_COUNT;
AppendVariableAndValueToString(mVariableOrder[variableIndex], aString);
continue;
}
if (!nsCSSProps::IsEnabled(property, nsCSSProps::eEnabledForAllContent)) {
continue;
}
bool doneProperty = false;
// If we already used this property in a shorthand, skip it.
if (shorthandsUsed.Length() > 0) {
for (const nsCSSProperty *shorthands =
nsCSSProps::ShorthandsContaining(property);
*shorthands != eCSSProperty_UNKNOWN; ++shorthands) {
if (shorthandsUsed.Contains(*shorthands)) {
doneProperty = true;
break;
}
}
if (doneProperty)
continue;
}
// Try to use this property in a shorthand.
nsAutoString value;
for (const nsCSSProperty *shorthands =
nsCSSProps::ShorthandsContaining(property);
*shorthands != eCSSProperty_UNKNOWN; ++shorthands) {
// ShorthandsContaining returns the shorthands in order from those
// that contain the most subproperties to those that contain the
// least, which is exactly the order we want to test them.
nsCSSProperty shorthand = *shorthands;
GetValue(shorthand, value);
// in the system font case, skip over font-variant shorthand, since all
// subproperties are already dealt with via the font shorthand
if (shorthand == eCSSProperty_font_variant &&
value.EqualsLiteral("-moz-use-system-font")) {
continue;
}
// If GetValue gives us a non-empty string back, we can use that
// value; otherwise it's not possible to use this shorthand.
if (!value.IsEmpty()) {
AppendPropertyAndValueToString(shorthand, value, aString);
shorthandsUsed.AppendElement(shorthand);
doneProperty = true;
break;
}
if (shorthand == eCSSProperty_font) {
if (haveSystemFont && !didSystemFont) {
// Output the shorthand font declaration that we will
// partially override later. But don't add it to
// |shorthandsUsed|, since we will have to override it.
systemFont->AppendToString(eCSSProperty__x_system_font, value,
nsCSSValue::eNormalized);
AppendPropertyAndValueToString(eCSSProperty_font, value, aString);
value.Truncate();
didSystemFont = true;
}
// That we output the system font is enough for this property if:
// (1) it's the hidden system font subproperty (which either
// means we output it or we don't have it), or
// (2) its value is the hidden system font value and it matches
// the hidden system font subproperty in importance, and
// we output the system font subproperty.
const nsCSSValue *val = systemFontData->ValueFor(property);
if (property == eCSSProperty__x_system_font ||
(haveSystemFont && val && val->GetUnit() == eCSSUnit_System_Font)) {
doneProperty = true;
break;
}
}
}
if (doneProperty)
continue;
MOZ_ASSERT(value.IsEmpty(), "value should be empty now");
AppendPropertyAndValueToString(property, value, aString);
}
if (! aString.IsEmpty()) {
// if the string is not empty, we have trailing whitespace we
// should remove
aString.Truncate(aString.Length() - 1);
}
}
#ifdef DEBUG
/* virtual */ void
Declaration::List(FILE* out, int32_t aIndent) const
{
nsAutoCString str;
for (int32_t index = aIndent; --index >= 0; ) {
str.AppendLiteral(" ");
}
str.AppendLiteral("{ ");
nsAutoString s;
ToString(s);
AppendUTF16toUTF8(s, str);
str.AppendLiteral("}\n");
fprintf_stderr(out, "%s", str.get());
}
#endif
bool
Declaration::GetNthProperty(uint32_t aIndex, nsAString& aReturn) const
{
aReturn.Truncate();
if (aIndex < mOrder.Length()) {
nsCSSProperty property = GetPropertyAt(aIndex);
if (property == eCSSPropertyExtra_variable) {
GetCustomPropertyNameAt(aIndex, aReturn);
return true;
}
if (0 <= property) {
AppendASCIItoUTF16(nsCSSProps::GetStringValue(property), aReturn);
return true;
}
}
return false;
}
void
Declaration::InitializeEmpty()
{
MOZ_ASSERT(!mData && !mImportantData, "already initialized");
mData = nsCSSCompressedDataBlock::CreateEmptyBlock();
}
already_AddRefed<Declaration>
Declaration::EnsureMutable()
{
MOZ_ASSERT(mData, "should only be called when not expanded");
RefPtr<Declaration> result;
if (!IsMutable()) {
result = new Declaration(*this);
} else {
result = this;
}
return result.forget();
}
size_t
Declaration::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
size_t n = aMallocSizeOf(this);
n += mOrder.ShallowSizeOfExcludingThis(aMallocSizeOf);
n += mData ? mData ->SizeOfIncludingThis(aMallocSizeOf) : 0;
n += mImportantData ? mImportantData->SizeOfIncludingThis(aMallocSizeOf) : 0;
if (mVariables) {
n += mVariables->SizeOfIncludingThis(aMallocSizeOf);
}
if (mImportantVariables) {
n += mImportantVariables->SizeOfIncludingThis(aMallocSizeOf);
}
return n;
}
bool
Declaration::HasVariableDeclaration(const nsAString& aName) const
{
return (mVariables && mVariables->Has(aName)) ||
(mImportantVariables && mImportantVariables->Has(aName));
}
void
Declaration::GetVariableDeclaration(const nsAString& aName,
nsAString& aValue) const
{
aValue.Truncate();
CSSVariableDeclarations::Type type;
nsString value;
if ((mImportantVariables && mImportantVariables->Get(aName, type, value)) ||
(mVariables && mVariables->Get(aName, type, value))) {
switch (type) {
case CSSVariableDeclarations::eTokenStream:
aValue.Append(value);
break;
case CSSVariableDeclarations::eInitial:
aValue.AppendLiteral("initial");
break;
case CSSVariableDeclarations::eInherit:
aValue.AppendLiteral("inherit");
break;
case CSSVariableDeclarations::eUnset:
aValue.AppendLiteral("unset");
break;
default:
MOZ_ASSERT(false, "unexpected variable value type");
}
}
}
void
Declaration::AddVariableDeclaration(const nsAString& aName,
CSSVariableDeclarations::Type aType,
const nsString& aValue,
bool aIsImportant,
bool aOverrideImportant)
{
MOZ_ASSERT(IsMutable());
nsTArray<nsString>::index_type index = mVariableOrder.IndexOf(aName);
if (index == nsTArray<nsString>::NoIndex) {
index = mVariableOrder.Length();
mVariableOrder.AppendElement(aName);
}
if (!aIsImportant && !aOverrideImportant &&
mImportantVariables && mImportantVariables->Has(aName)) {
return;
}
CSSVariableDeclarations* variables;
if (aIsImportant) {
if (mVariables) {
mVariables->Remove(aName);
}
if (!mImportantVariables) {
mImportantVariables = new CSSVariableDeclarations;
}
variables = mImportantVariables;
} else {
if (mImportantVariables) {
mImportantVariables->Remove(aName);
}
if (!mVariables) {
mVariables = new CSSVariableDeclarations;
}
variables = mVariables;
}
switch (aType) {
case CSSVariableDeclarations::eTokenStream:
variables->PutTokenStream(aName, aValue);
break;
case CSSVariableDeclarations::eInitial:
MOZ_ASSERT(aValue.IsEmpty());
variables->PutInitial(aName);
break;
case CSSVariableDeclarations::eInherit:
MOZ_ASSERT(aValue.IsEmpty());
variables->PutInherit(aName);
break;
case CSSVariableDeclarations::eUnset:
MOZ_ASSERT(aValue.IsEmpty());
variables->PutUnset(aName);
break;
default:
MOZ_ASSERT(false, "unexpected aType value");
}
uint32_t propertyIndex = index + eCSSProperty_COUNT;
mOrder.RemoveElement(propertyIndex);
mOrder.AppendElement(propertyIndex);
}
void
Declaration::RemoveVariableDeclaration(const nsAString& aName)
{
if (mVariables) {
mVariables->Remove(aName);
}
if (mImportantVariables) {
mImportantVariables->Remove(aName);
}
nsTArray<nsString>::index_type index = mVariableOrder.IndexOf(aName);
if (index != nsTArray<nsString>::NoIndex) {
mOrder.RemoveElement(index + eCSSProperty_COUNT);
}
}
bool
Declaration::GetVariableValueIsImportant(const nsAString& aName) const
{
return mImportantVariables && mImportantVariables->Has(aName);
}
} // namespace css
} // namespace mozilla