layout/style/nsRuleNode.cpp

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=78: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /*
michael@0 8 * a node in the lexicographic tree of rules that match an element,
michael@0 9 * responsible for converting the rules' information into computed style
michael@0 10 */
michael@0 11
michael@0 12 #include <algorithm>
michael@0 13
michael@0 14 #include "mozilla/ArrayUtils.h"
michael@0 15 #include "mozilla/Assertions.h"
michael@0 16 #include "mozilla/DebugOnly.h"
michael@0 17 #include "mozilla/Likely.h"
michael@0 18 #include "mozilla/LookAndFeel.h"
michael@0 19
michael@0 20 #include "nsRuleNode.h"
michael@0 21 #include "nscore.h"
michael@0 22 #include "nsIWidget.h"
michael@0 23 #include "nsIPresShell.h"
michael@0 24 #include "nsFontMetrics.h"
michael@0 25 #include "gfxFont.h"
michael@0 26 #include "nsCSSPseudoElements.h"
michael@0 27 #include "nsThemeConstants.h"
michael@0 28 #include "pldhash.h"
michael@0 29 #include "nsStyleContext.h"
michael@0 30 #include "nsStyleSet.h"
michael@0 31 #include "nsStyleStruct.h"
michael@0 32 #include "nsSize.h"
michael@0 33 #include "nsRuleData.h"
michael@0 34 #include "gfxUserFontSet.h"
michael@0 35 #include "nsIStyleRule.h"
michael@0 36 #include "nsBidiUtils.h"
michael@0 37 #include "nsStyleStructInlines.h"
michael@0 38 #include "nsCSSProps.h"
michael@0 39 #include "nsTArray.h"
michael@0 40 #include "nsContentUtils.h"
michael@0 41 #include "CSSCalc.h"
michael@0 42 #include "nsPrintfCString.h"
michael@0 43 #include "nsRenderingContext.h"
michael@0 44 #include "nsStyleUtil.h"
michael@0 45 #include "nsIDocument.h"
michael@0 46 #include "prtime.h"
michael@0 47 #include "CSSVariableResolver.h"
michael@0 48 #include "nsCSSParser.h"
michael@0 49
michael@0 50 #if defined(_MSC_VER) || defined(__MINGW32__)
michael@0 51 #include <malloc.h>
michael@0 52 #ifdef _MSC_VER
michael@0 53 #define alloca _alloca
michael@0 54 #endif
michael@0 55 #endif
michael@0 56 #ifdef SOLARIS
michael@0 57 #include <alloca.h>
michael@0 58 #endif
michael@0 59
michael@0 60 using std::max;
michael@0 61 using std::min;
michael@0 62 using namespace mozilla;
michael@0 63 using namespace mozilla::dom;
michael@0 64
michael@0 65 #define NS_SET_IMAGE_REQUEST(method_, context_, request_) \
michael@0 66 if ((context_)->PresContext()->IsDynamic()) { \
michael@0 67 method_(request_); \
michael@0 68 } else { \
michael@0 69 nsRefPtr<imgRequestProxy> req = nsContentUtils::GetStaticRequest(request_); \
michael@0 70 method_(req); \
michael@0 71 }
michael@0 72
michael@0 73 #define NS_SET_IMAGE_REQUEST_WITH_DOC(method_, context_, requestgetter_) \
michael@0 74 { \
michael@0 75 nsIDocument* doc = (context_)->PresContext()->Document(); \
michael@0 76 NS_SET_IMAGE_REQUEST(method_, context_, requestgetter_(doc)) \
michael@0 77 }
michael@0 78
michael@0 79 /*
michael@0 80 * For storage of an |nsRuleNode|'s children in a PLDHashTable.
michael@0 81 */
michael@0 82
michael@0 83 struct ChildrenHashEntry : public PLDHashEntryHdr {
michael@0 84 // key is |mRuleNode->GetKey()|
michael@0 85 nsRuleNode *mRuleNode;
michael@0 86 };
michael@0 87
michael@0 88 /* static */ PLDHashNumber
michael@0 89 nsRuleNode::ChildrenHashHashKey(PLDHashTable *aTable, const void *aKey)
michael@0 90 {
michael@0 91 const nsRuleNode::Key *key =
michael@0 92 static_cast<const nsRuleNode::Key*>(aKey);
michael@0 93 // Disagreement on importance and level for the same rule is extremely
michael@0 94 // rare, so hash just on the rule.
michael@0 95 return PL_DHashVoidPtrKeyStub(aTable, key->mRule);
michael@0 96 }
michael@0 97
michael@0 98 /* static */ bool
michael@0 99 nsRuleNode::ChildrenHashMatchEntry(PLDHashTable *aTable,
michael@0 100 const PLDHashEntryHdr *aHdr,
michael@0 101 const void *aKey)
michael@0 102 {
michael@0 103 const ChildrenHashEntry *entry =
michael@0 104 static_cast<const ChildrenHashEntry*>(aHdr);
michael@0 105 const nsRuleNode::Key *key =
michael@0 106 static_cast<const nsRuleNode::Key*>(aKey);
michael@0 107 return entry->mRuleNode->GetKey() == *key;
michael@0 108 }
michael@0 109
michael@0 110 /* static */ const PLDHashTableOps
michael@0 111 nsRuleNode::ChildrenHashOps = {
michael@0 112 // It's probably better to allocate the table itself using malloc and
michael@0 113 // free rather than the pres shell's arena because the table doesn't
michael@0 114 // grow very often and the pres shell's arena doesn't recycle very
michael@0 115 // large size allocations.
michael@0 116 PL_DHashAllocTable,
michael@0 117 PL_DHashFreeTable,
michael@0 118 ChildrenHashHashKey,
michael@0 119 ChildrenHashMatchEntry,
michael@0 120 PL_DHashMoveEntryStub,
michael@0 121 PL_DHashClearEntryStub,
michael@0 122 PL_DHashFinalizeStub,
michael@0 123 nullptr
michael@0 124 };
michael@0 125
michael@0 126
michael@0 127 // EnsureBlockDisplay:
michael@0 128 // - if the display value (argument) is not a block-type
michael@0 129 // then we set it to a valid block display value
michael@0 130 // - For enforcing the floated/positioned element CSS2 rules
michael@0 131 // - We allow the behavior of "list-item" to be customized.
michael@0 132 // CSS21 says that position/float do not convert 'list-item' to 'block',
michael@0 133 // but it explicitly does not define whether 'list-item' should be
michael@0 134 // converted to block *on the root node*. To allow for flexibility
michael@0 135 // (so that we don't have to support a list-item root node), this method
michael@0 136 // lets the caller pick either behavior, using the 'aConvertListItem' arg.
michael@0 137 // Reference: http://www.w3.org/TR/CSS21/visuren.html#dis-pos-flo
michael@0 138 /* static */
michael@0 139 void
michael@0 140 nsRuleNode::EnsureBlockDisplay(uint8_t& display,
michael@0 141 bool aConvertListItem /* = false */)
michael@0 142 {
michael@0 143 // see if the display value is already a block
michael@0 144 switch (display) {
michael@0 145 case NS_STYLE_DISPLAY_LIST_ITEM :
michael@0 146 if (aConvertListItem) {
michael@0 147 display = NS_STYLE_DISPLAY_BLOCK;
michael@0 148 break;
michael@0 149 } // else, fall through to share the 'break' for non-changing display vals
michael@0 150 case NS_STYLE_DISPLAY_NONE :
michael@0 151 // never change display:none *ever*
michael@0 152 case NS_STYLE_DISPLAY_TABLE :
michael@0 153 case NS_STYLE_DISPLAY_BLOCK :
michael@0 154 case NS_STYLE_DISPLAY_FLEX :
michael@0 155 case NS_STYLE_DISPLAY_GRID :
michael@0 156 // do not muck with these at all - already blocks
michael@0 157 // This is equivalent to nsStyleDisplay::IsBlockOutside. (XXX Maybe we
michael@0 158 // should just call that?)
michael@0 159 // This needs to match the check done in
michael@0 160 // nsCSSFrameConstructor::FindMathMLData for <math>.
michael@0 161 break;
michael@0 162
michael@0 163 case NS_STYLE_DISPLAY_INLINE_TABLE :
michael@0 164 // make inline tables into tables
michael@0 165 display = NS_STYLE_DISPLAY_TABLE;
michael@0 166 break;
michael@0 167
michael@0 168 case NS_STYLE_DISPLAY_INLINE_FLEX:
michael@0 169 // make inline flex containers into flex containers
michael@0 170 display = NS_STYLE_DISPLAY_FLEX;
michael@0 171 break;
michael@0 172
michael@0 173 case NS_STYLE_DISPLAY_INLINE_GRID:
michael@0 174 // make inline grid containers into grid containers
michael@0 175 display = NS_STYLE_DISPLAY_GRID;
michael@0 176 break;
michael@0 177
michael@0 178 default :
michael@0 179 // make it a block
michael@0 180 display = NS_STYLE_DISPLAY_BLOCK;
michael@0 181 }
michael@0 182 }
michael@0 183
michael@0 184 static nscoord CalcLengthWith(const nsCSSValue& aValue,
michael@0 185 nscoord aFontSize,
michael@0 186 const nsStyleFont* aStyleFont,
michael@0 187 nsStyleContext* aStyleContext,
michael@0 188 nsPresContext* aPresContext,
michael@0 189 bool aUseProvidedRootEmSize,
michael@0 190 bool aUseUserFontSet,
michael@0 191 bool& aCanStoreInRuleTree);
michael@0 192
michael@0 193 struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
michael@0 194 public css::NumbersAlreadyNormalizedOps
michael@0 195 {
michael@0 196 // All of the parameters to CalcLengthWith except aValue.
michael@0 197 const nscoord mFontSize;
michael@0 198 const nsStyleFont* const mStyleFont;
michael@0 199 nsStyleContext* const mStyleContext;
michael@0 200 nsPresContext* const mPresContext;
michael@0 201 const bool mUseProvidedRootEmSize;
michael@0 202 const bool mUseUserFontSet;
michael@0 203 bool& mCanStoreInRuleTree;
michael@0 204
michael@0 205 CalcLengthCalcOps(nscoord aFontSize, const nsStyleFont* aStyleFont,
michael@0 206 nsStyleContext* aStyleContext, nsPresContext* aPresContext,
michael@0 207 bool aUseProvidedRootEmSize, bool aUseUserFontSet,
michael@0 208 bool& aCanStoreInRuleTree)
michael@0 209 : mFontSize(aFontSize),
michael@0 210 mStyleFont(aStyleFont),
michael@0 211 mStyleContext(aStyleContext),
michael@0 212 mPresContext(aPresContext),
michael@0 213 mUseProvidedRootEmSize(aUseProvidedRootEmSize),
michael@0 214 mUseUserFontSet(aUseUserFontSet),
michael@0 215 mCanStoreInRuleTree(aCanStoreInRuleTree)
michael@0 216 {
michael@0 217 }
michael@0 218
michael@0 219 result_type ComputeLeafValue(const nsCSSValue& aValue)
michael@0 220 {
michael@0 221 return CalcLengthWith(aValue, mFontSize, mStyleFont,
michael@0 222 mStyleContext, mPresContext, mUseProvidedRootEmSize,
michael@0 223 mUseUserFontSet, mCanStoreInRuleTree);
michael@0 224 }
michael@0 225 };
michael@0 226
michael@0 227 static inline nscoord ScaleCoord(const nsCSSValue &aValue, float factor)
michael@0 228 {
michael@0 229 return NSToCoordRoundWithClamp(aValue.GetFloatValue() * factor);
michael@0 230 }
michael@0 231
michael@0 232 already_AddRefed<nsFontMetrics>
michael@0 233 GetMetricsFor(nsPresContext* aPresContext,
michael@0 234 nsStyleContext* aStyleContext,
michael@0 235 const nsStyleFont* aStyleFont,
michael@0 236 nscoord aFontSize, // overrides value from aStyleFont
michael@0 237 bool aUseUserFontSet)
michael@0 238 {
michael@0 239 nsFont font = aStyleFont->mFont;
michael@0 240 font.size = aFontSize;
michael@0 241 gfxUserFontSet *fs = nullptr;
michael@0 242 if (aUseUserFontSet) {
michael@0 243 fs = aPresContext->GetUserFontSet();
michael@0 244 }
michael@0 245 gfxTextPerfMetrics *tp = aPresContext->GetTextPerfMetrics();
michael@0 246 nsRefPtr<nsFontMetrics> fm;
michael@0 247 aPresContext->DeviceContext()->GetMetricsFor(font,
michael@0 248 aStyleFont->mLanguage,
michael@0 249 fs, tp, *getter_AddRefs(fm));
michael@0 250 return fm.forget();
michael@0 251 }
michael@0 252
michael@0 253
michael@0 254 static nsSize CalcViewportUnitsScale(nsPresContext* aPresContext)
michael@0 255 {
michael@0 256 // The caller is making use of viewport units, so notify the pres context
michael@0 257 // that it will need to rebuild the rule tree if the size of the viewport
michael@0 258 // changes.
michael@0 259 aPresContext->SetUsesViewportUnits(true);
michael@0 260
michael@0 261 // The default (when we have 'overflow: auto' on the root element, or
michael@0 262 // trivially for 'overflow: hidden' since we never have scrollbars in that
michael@0 263 // case) is to define the scale of the viewport units without considering
michael@0 264 // scrollbars.
michael@0 265 nsSize viewportSize(aPresContext->GetVisibleArea().Size());
michael@0 266
michael@0 267 // Check for 'overflow: scroll' styles on the root scroll frame. If we find
michael@0 268 // any, the standard requires us to take scrollbars into account.
michael@0 269 nsIScrollableFrame* scrollFrame =
michael@0 270 aPresContext->PresShell()->GetRootScrollFrameAsScrollable();
michael@0 271 if (scrollFrame) {
michael@0 272 ScrollbarStyles styles(scrollFrame->GetScrollbarStyles());
michael@0 273
michael@0 274 if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL ||
michael@0 275 styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
michael@0 276 // Gather scrollbar size information.
michael@0 277 nsRefPtr<nsRenderingContext> context =
michael@0 278 aPresContext->PresShell()->CreateReferenceRenderingContext();
michael@0 279 nsMargin sizes(scrollFrame->GetDesiredScrollbarSizes(aPresContext, context));
michael@0 280
michael@0 281 if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL) {
michael@0 282 // 'overflow-x: scroll' means we must consider the horizontal scrollbar,
michael@0 283 // which affects the scale of viewport height units.
michael@0 284 viewportSize.height -= sizes.TopBottom();
michael@0 285 }
michael@0 286
michael@0 287 if (styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
michael@0 288 // 'overflow-y: scroll' means we must consider the vertical scrollbar,
michael@0 289 // which affects the scale of viewport width units.
michael@0 290 viewportSize.width -= sizes.LeftRight();
michael@0 291 }
michael@0 292 }
michael@0 293 }
michael@0 294
michael@0 295 return viewportSize;
michael@0 296 }
michael@0 297
michael@0 298 static nscoord CalcLengthWith(const nsCSSValue& aValue,
michael@0 299 nscoord aFontSize,
michael@0 300 const nsStyleFont* aStyleFont,
michael@0 301 nsStyleContext* aStyleContext,
michael@0 302 nsPresContext* aPresContext,
michael@0 303 bool aUseProvidedRootEmSize,
michael@0 304 // aUseUserFontSet should always be true
michael@0 305 // except when called from
michael@0 306 // CalcLengthWithInitialFont.
michael@0 307 bool aUseUserFontSet,
michael@0 308 bool& aCanStoreInRuleTree)
michael@0 309 {
michael@0 310 NS_ASSERTION(aValue.IsLengthUnit() || aValue.IsCalcUnit(),
michael@0 311 "not a length or calc unit");
michael@0 312 NS_ASSERTION(aStyleFont || aStyleContext,
michael@0 313 "Must have style data");
michael@0 314 NS_ASSERTION(!aStyleFont || !aStyleContext,
michael@0 315 "Duplicate sources of data");
michael@0 316 NS_ASSERTION(aPresContext, "Must have prescontext");
michael@0 317
michael@0 318 if (aValue.IsFixedLengthUnit()) {
michael@0 319 return aValue.GetFixedLength(aPresContext);
michael@0 320 }
michael@0 321 if (aValue.IsPixelLengthUnit()) {
michael@0 322 return aValue.GetPixelLength();
michael@0 323 }
michael@0 324 if (aValue.IsCalcUnit()) {
michael@0 325 // For properties for which lengths are the *only* units accepted in
michael@0 326 // calc(), we can handle calc() here and just compute a final
michael@0 327 // result. We ensure that we don't get to this code for other
michael@0 328 // properties by not calling CalcLength in those cases: SetCoord
michael@0 329 // only calls CalcLength for a calc when it is appropriate to do so.
michael@0 330 CalcLengthCalcOps ops(aFontSize, aStyleFont,
michael@0 331 aStyleContext, aPresContext,
michael@0 332 aUseProvidedRootEmSize, aUseUserFontSet,
michael@0 333 aCanStoreInRuleTree);
michael@0 334 return css::ComputeCalc(aValue, ops);
michael@0 335 }
michael@0 336 switch (aValue.GetUnit()) {
michael@0 337 // nsPresContext::SetVisibleArea and
michael@0 338 // nsPresContext::MediaFeatureValuesChanged handle dynamic changes
michael@0 339 // of the basis for viewport units by rebuilding the rule tree and
michael@0 340 // style context tree. Not caching them in the rule tree wouldn't
michael@0 341 // be sufficient to handle these changes because we also need a way
michael@0 342 // to get rid of cached values in the style context tree without any
michael@0 343 // changes in specified style. We can either do this by not caching
michael@0 344 // in the rule tree and then throwing away the style context tree
michael@0 345 // for dynamic viewport size changes, or by allowing caching in the
michael@0 346 // rule tree and using the existing rebuild style data path that
michael@0 347 // throws away the style context and the rule tree.
michael@0 348 // Thus we do cache viewport units in the rule tree. This allows us
michael@0 349 // to benefit from the performance advantages of the rule tree
michael@0 350 // (e.g., faster dynamic changes on other things, like transforms)
michael@0 351 // and allows us not to need an additional code path, in exchange
michael@0 352 // for an increased cost to dynamic changes to the viewport size
michael@0 353 // when viewport units are in use.
michael@0 354 case eCSSUnit_ViewportWidth: {
michael@0 355 return ScaleCoord(aValue, 0.01f * CalcViewportUnitsScale(aPresContext).width);
michael@0 356 }
michael@0 357 case eCSSUnit_ViewportHeight: {
michael@0 358 return ScaleCoord(aValue, 0.01f * CalcViewportUnitsScale(aPresContext).height);
michael@0 359 }
michael@0 360 case eCSSUnit_ViewportMin: {
michael@0 361 nsSize vuScale(CalcViewportUnitsScale(aPresContext));
michael@0 362 return ScaleCoord(aValue, 0.01f * min(vuScale.width, vuScale.height));
michael@0 363 }
michael@0 364 case eCSSUnit_ViewportMax: {
michael@0 365 nsSize vuScale(CalcViewportUnitsScale(aPresContext));
michael@0 366 return ScaleCoord(aValue, 0.01f * max(vuScale.width, vuScale.height));
michael@0 367 }
michael@0 368 // While we could deal with 'rem' units correctly by simply not
michael@0 369 // caching any data that uses them in the rule tree, it's valuable
michael@0 370 // to store them in the rule tree (for faster dynamic changes of
michael@0 371 // other things). And since the font size of the root element
michael@0 372 // changes rarely, we instead handle dynamic changes to the root
michael@0 373 // element's font size by rebuilding all style data in
michael@0 374 // nsCSSFrameConstructor::RestyleElement.
michael@0 375 case eCSSUnit_RootEM: {
michael@0 376 aPresContext->SetUsesRootEMUnits(true);
michael@0 377 nscoord rootFontSize;
michael@0 378
michael@0 379 // NOTE: Be very careful with |styleFont|, since we haven't set
michael@0 380 // aCanStoreInRuleTree to false yet, so we don't want to introduce
michael@0 381 // any dependencies on aStyleContext's data here.
michael@0 382 const nsStyleFont *styleFont =
michael@0 383 aStyleFont ? aStyleFont : aStyleContext->StyleFont();
michael@0 384
michael@0 385 if (aUseProvidedRootEmSize) {
michael@0 386 // We should use the provided aFontSize as the reference length to
michael@0 387 // scale. This only happens when we are calculating font-size or
michael@0 388 // an equivalent (scriptminsize or CalcLengthWithInitialFont) on
michael@0 389 // the root element, in which case aFontSize is already the
michael@0 390 // value we want.
michael@0 391 if (aFontSize == -1) {
michael@0 392 // XXX Should this be styleFont->mSize instead to avoid taking
michael@0 393 // minfontsize prefs into account?
michael@0 394 aFontSize = styleFont->mFont.size;
michael@0 395 }
michael@0 396 rootFontSize = aFontSize;
michael@0 397 } else if (aStyleContext && !aStyleContext->GetParent()) {
michael@0 398 // This is the root element (XXX we don't really know this, but
michael@0 399 // nsRuleNode::SetFont makes the same assumption!), so we should
michael@0 400 // use StyleFont on this context to get the root element's
michael@0 401 // font size.
michael@0 402 rootFontSize = styleFont->mFont.size;
michael@0 403 } else {
michael@0 404 // This is not the root element or we are calculating something other
michael@0 405 // than font size, so rem is relative to the root element's font size.
michael@0 406 nsRefPtr<nsStyleContext> rootStyle;
michael@0 407 const nsStyleFont *rootStyleFont = styleFont;
michael@0 408 Element* docElement = aPresContext->Document()->GetRootElement();
michael@0 409
michael@0 410 if (docElement) {
michael@0 411 rootStyle = aPresContext->StyleSet()->ResolveStyleFor(docElement,
michael@0 412 nullptr);
michael@0 413 rootStyleFont = rootStyle->StyleFont();
michael@0 414 }
michael@0 415
michael@0 416 rootFontSize = rootStyleFont->mFont.size;
michael@0 417 }
michael@0 418
michael@0 419 return ScaleCoord(aValue, float(rootFontSize));
michael@0 420 }
michael@0 421 default:
michael@0 422 // Fall through to the code for units that can't be stored in the
michael@0 423 // rule tree because they depend on font data.
michael@0 424 break;
michael@0 425 }
michael@0 426 // Common code for units that depend on the element's font data and
michael@0 427 // thus can't be stored in the rule tree:
michael@0 428 aCanStoreInRuleTree = false;
michael@0 429 const nsStyleFont *styleFont =
michael@0 430 aStyleFont ? aStyleFont : aStyleContext->StyleFont();
michael@0 431 if (aFontSize == -1) {
michael@0 432 // XXX Should this be styleFont->mSize instead to avoid taking minfontsize
michael@0 433 // prefs into account?
michael@0 434 aFontSize = styleFont->mFont.size;
michael@0 435 }
michael@0 436 switch (aValue.GetUnit()) {
michael@0 437 case eCSSUnit_EM: {
michael@0 438 // CSS2.1 specifies that this unit scales to the computed font
michael@0 439 // size, not the em-width in the font metrics, despite the name.
michael@0 440 return ScaleCoord(aValue, float(aFontSize));
michael@0 441 }
michael@0 442 case eCSSUnit_XHeight: {
michael@0 443 nsRefPtr<nsFontMetrics> fm =
michael@0 444 GetMetricsFor(aPresContext, aStyleContext, styleFont,
michael@0 445 aFontSize, aUseUserFontSet);
michael@0 446 return ScaleCoord(aValue, float(fm->XHeight()));
michael@0 447 }
michael@0 448 case eCSSUnit_Char: {
michael@0 449 nsRefPtr<nsFontMetrics> fm =
michael@0 450 GetMetricsFor(aPresContext, aStyleContext, styleFont,
michael@0 451 aFontSize, aUseUserFontSet);
michael@0 452 gfxFloat zeroWidth = (fm->GetThebesFontGroup()->GetFontAt(0)
michael@0 453 ->GetMetrics().zeroOrAveCharWidth);
michael@0 454
michael@0 455 return ScaleCoord(aValue, ceil(aPresContext->AppUnitsPerDevPixel() *
michael@0 456 zeroWidth));
michael@0 457 }
michael@0 458 default:
michael@0 459 NS_NOTREACHED("unexpected unit");
michael@0 460 break;
michael@0 461 }
michael@0 462 return 0;
michael@0 463 }
michael@0 464
michael@0 465 /* static */ nscoord
michael@0 466 nsRuleNode::CalcLength(const nsCSSValue& aValue,
michael@0 467 nsStyleContext* aStyleContext,
michael@0 468 nsPresContext* aPresContext,
michael@0 469 bool& aCanStoreInRuleTree)
michael@0 470 {
michael@0 471 NS_ASSERTION(aStyleContext, "Must have style data");
michael@0 472
michael@0 473 return CalcLengthWith(aValue, -1, nullptr,
michael@0 474 aStyleContext, aPresContext,
michael@0 475 false, true, aCanStoreInRuleTree);
michael@0 476 }
michael@0 477
michael@0 478 /* Inline helper function to redirect requests to CalcLength. */
michael@0 479 static inline nscoord CalcLength(const nsCSSValue& aValue,
michael@0 480 nsStyleContext* aStyleContext,
michael@0 481 nsPresContext* aPresContext,
michael@0 482 bool& aCanStoreInRuleTree)
michael@0 483 {
michael@0 484 return nsRuleNode::CalcLength(aValue, aStyleContext,
michael@0 485 aPresContext, aCanStoreInRuleTree);
michael@0 486 }
michael@0 487
michael@0 488 /* static */ nscoord
michael@0 489 nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
michael@0 490 const nsCSSValue& aValue)
michael@0 491 {
michael@0 492 nsStyleFont defaultFont(aPresContext); // FIXME: best language?
michael@0 493 bool canStoreInRuleTree;
michael@0 494 return CalcLengthWith(aValue, -1, &defaultFont,
michael@0 495 nullptr, aPresContext,
michael@0 496 true, false, canStoreInRuleTree);
michael@0 497 }
michael@0 498
michael@0 499 struct LengthPercentPairCalcOps : public css::NumbersAlreadyNormalizedOps
michael@0 500 {
michael@0 501 typedef nsRuleNode::ComputedCalc result_type;
michael@0 502
michael@0 503 LengthPercentPairCalcOps(nsStyleContext* aContext,
michael@0 504 nsPresContext* aPresContext,
michael@0 505 bool& aCanStoreInRuleTree)
michael@0 506 : mContext(aContext),
michael@0 507 mPresContext(aPresContext),
michael@0 508 mCanStoreInRuleTree(aCanStoreInRuleTree),
michael@0 509 mHasPercent(false) {}
michael@0 510
michael@0 511 nsStyleContext* mContext;
michael@0 512 nsPresContext* mPresContext;
michael@0 513 bool& mCanStoreInRuleTree;
michael@0 514 bool mHasPercent;
michael@0 515
michael@0 516 result_type ComputeLeafValue(const nsCSSValue& aValue)
michael@0 517 {
michael@0 518 if (aValue.GetUnit() == eCSSUnit_Percent) {
michael@0 519 mHasPercent = true;
michael@0 520 return result_type(0, aValue.GetPercentValue());
michael@0 521 }
michael@0 522 return result_type(CalcLength(aValue, mContext, mPresContext,
michael@0 523 mCanStoreInRuleTree),
michael@0 524 0.0f);
michael@0 525 }
michael@0 526
michael@0 527 result_type
michael@0 528 MergeAdditive(nsCSSUnit aCalcFunction,
michael@0 529 result_type aValue1, result_type aValue2)
michael@0 530 {
michael@0 531 if (aCalcFunction == eCSSUnit_Calc_Plus) {
michael@0 532 return result_type(NSCoordSaturatingAdd(aValue1.mLength,
michael@0 533 aValue2.mLength),
michael@0 534 aValue1.mPercent + aValue2.mPercent);
michael@0 535 }
michael@0 536 NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Minus,
michael@0 537 "min() and max() are not allowed in calc() on "
michael@0 538 "transform");
michael@0 539 return result_type(NSCoordSaturatingSubtract(aValue1.mLength,
michael@0 540 aValue2.mLength, 0),
michael@0 541 aValue1.mPercent - aValue2.mPercent);
michael@0 542 }
michael@0 543
michael@0 544 result_type
michael@0 545 MergeMultiplicativeL(nsCSSUnit aCalcFunction,
michael@0 546 float aValue1, result_type aValue2)
michael@0 547 {
michael@0 548 NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Times_L,
michael@0 549 "unexpected unit");
michael@0 550 return result_type(NSCoordSaturatingMultiply(aValue2.mLength, aValue1),
michael@0 551 aValue1 * aValue2.mPercent);
michael@0 552 }
michael@0 553
michael@0 554 result_type
michael@0 555 MergeMultiplicativeR(nsCSSUnit aCalcFunction,
michael@0 556 result_type aValue1, float aValue2)
michael@0 557 {
michael@0 558 NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Times_R ||
michael@0 559 aCalcFunction == eCSSUnit_Calc_Divided,
michael@0 560 "unexpected unit");
michael@0 561 if (aCalcFunction == eCSSUnit_Calc_Divided) {
michael@0 562 aValue2 = 1.0f / aValue2;
michael@0 563 }
michael@0 564 return result_type(NSCoordSaturatingMultiply(aValue1.mLength, aValue2),
michael@0 565 aValue1.mPercent * aValue2);
michael@0 566 }
michael@0 567
michael@0 568 };
michael@0 569
michael@0 570 static void
michael@0 571 SpecifiedCalcToComputedCalc(const nsCSSValue& aValue, nsStyleCoord& aCoord,
michael@0 572 nsStyleContext* aStyleContext,
michael@0 573 bool& aCanStoreInRuleTree)
michael@0 574 {
michael@0 575 LengthPercentPairCalcOps ops(aStyleContext, aStyleContext->PresContext(),
michael@0 576 aCanStoreInRuleTree);
michael@0 577 nsRuleNode::ComputedCalc vals = ComputeCalc(aValue, ops);
michael@0 578
michael@0 579 nsStyleCoord::Calc *calcObj =
michael@0 580 new (aStyleContext->Alloc(sizeof(nsStyleCoord::Calc))) nsStyleCoord::Calc;
michael@0 581 // Because we use aStyleContext->Alloc(), we have to store the result
michael@0 582 // on the style context and not in the rule tree.
michael@0 583 aCanStoreInRuleTree = false;
michael@0 584
michael@0 585 calcObj->mLength = vals.mLength;
michael@0 586 calcObj->mPercent = vals.mPercent;
michael@0 587 calcObj->mHasPercent = ops.mHasPercent;
michael@0 588
michael@0 589 aCoord.SetCalcValue(calcObj);
michael@0 590 }
michael@0 591
michael@0 592 /* static */ nsRuleNode::ComputedCalc
michael@0 593 nsRuleNode::SpecifiedCalcToComputedCalc(const nsCSSValue& aValue,
michael@0 594 nsStyleContext* aStyleContext,
michael@0 595 nsPresContext* aPresContext,
michael@0 596 bool& aCanStoreInRuleTree)
michael@0 597 {
michael@0 598 LengthPercentPairCalcOps ops(aStyleContext, aPresContext,
michael@0 599 aCanStoreInRuleTree);
michael@0 600 return ComputeCalc(aValue, ops);
michael@0 601 }
michael@0 602
michael@0 603 // This is our public API for handling calc() expressions that involve
michael@0 604 // percentages.
michael@0 605 /* static */ nscoord
michael@0 606 nsRuleNode::ComputeComputedCalc(const nsStyleCoord& aValue,
michael@0 607 nscoord aPercentageBasis)
michael@0 608 {
michael@0 609 nsStyleCoord::Calc *calc = aValue.GetCalcValue();
michael@0 610 return calc->mLength +
michael@0 611 NSToCoordFloorClamped(aPercentageBasis * calc->mPercent);
michael@0 612 }
michael@0 613
michael@0 614 /* static */ nscoord
michael@0 615 nsRuleNode::ComputeCoordPercentCalc(const nsStyleCoord& aCoord,
michael@0 616 nscoord aPercentageBasis)
michael@0 617 {
michael@0 618 switch (aCoord.GetUnit()) {
michael@0 619 case eStyleUnit_Coord:
michael@0 620 return aCoord.GetCoordValue();
michael@0 621 case eStyleUnit_Percent:
michael@0 622 return NSToCoordFloorClamped(aPercentageBasis * aCoord.GetPercentValue());
michael@0 623 case eStyleUnit_Calc:
michael@0 624 return ComputeComputedCalc(aCoord, aPercentageBasis);
michael@0 625 default:
michael@0 626 NS_ABORT_IF_FALSE(false, "unexpected unit");
michael@0 627 return 0;
michael@0 628 }
michael@0 629 }
michael@0 630
michael@0 631 /* Given an enumerated value that represents a box position, converts it to
michael@0 632 * a float representing the percentage of the box it corresponds to. For
michael@0 633 * example, "center" becomes 0.5f.
michael@0 634 *
michael@0 635 * @param aEnumValue The enumerated value.
michael@0 636 * @return The float percent it corresponds to.
michael@0 637 */
michael@0 638 static float
michael@0 639 GetFloatFromBoxPosition(int32_t aEnumValue)
michael@0 640 {
michael@0 641 switch (aEnumValue) {
michael@0 642 case NS_STYLE_BG_POSITION_LEFT:
michael@0 643 case NS_STYLE_BG_POSITION_TOP:
michael@0 644 return 0.0f;
michael@0 645 case NS_STYLE_BG_POSITION_RIGHT:
michael@0 646 case NS_STYLE_BG_POSITION_BOTTOM:
michael@0 647 return 1.0f;
michael@0 648 default:
michael@0 649 NS_NOTREACHED("unexpected value");
michael@0 650 // fall through
michael@0 651 case NS_STYLE_BG_POSITION_CENTER:
michael@0 652 return 0.5f;
michael@0 653 }
michael@0 654 }
michael@0 655
michael@0 656 #define SETCOORD_NORMAL 0x01 // N
michael@0 657 #define SETCOORD_AUTO 0x02 // A
michael@0 658 #define SETCOORD_INHERIT 0x04 // H
michael@0 659 #define SETCOORD_PERCENT 0x08 // P
michael@0 660 #define SETCOORD_FACTOR 0x10 // F
michael@0 661 #define SETCOORD_LENGTH 0x20 // L
michael@0 662 #define SETCOORD_INTEGER 0x40 // I
michael@0 663 #define SETCOORD_ENUMERATED 0x80 // E
michael@0 664 #define SETCOORD_NONE 0x100 // O
michael@0 665 #define SETCOORD_INITIAL_ZERO 0x200
michael@0 666 #define SETCOORD_INITIAL_AUTO 0x400
michael@0 667 #define SETCOORD_INITIAL_NONE 0x800
michael@0 668 #define SETCOORD_INITIAL_NORMAL 0x1000
michael@0 669 #define SETCOORD_INITIAL_HALF 0x2000
michael@0 670 #define SETCOORD_INITIAL_HUNDRED_PCT 0x00004000
michael@0 671 #define SETCOORD_INITIAL_FACTOR_ONE 0x00008000
michael@0 672 #define SETCOORD_INITIAL_FACTOR_ZERO 0x00010000
michael@0 673 #define SETCOORD_CALC_LENGTH_ONLY 0x00020000
michael@0 674 #define SETCOORD_CALC_CLAMP_NONNEGATIVE 0x00040000 // modifier for CALC_LENGTH_ONLY
michael@0 675 #define SETCOORD_STORE_CALC 0x00080000
michael@0 676 #define SETCOORD_BOX_POSITION 0x00100000 // exclusive with _ENUMERATED
michael@0 677 #define SETCOORD_ANGLE 0x00200000
michael@0 678 #define SETCOORD_UNSET_INHERIT 0x00400000
michael@0 679 #define SETCOORD_UNSET_INITIAL 0x00800000
michael@0 680
michael@0 681 #define SETCOORD_LP (SETCOORD_LENGTH | SETCOORD_PERCENT)
michael@0 682 #define SETCOORD_LH (SETCOORD_LENGTH | SETCOORD_INHERIT)
michael@0 683 #define SETCOORD_AH (SETCOORD_AUTO | SETCOORD_INHERIT)
michael@0 684 #define SETCOORD_LAH (SETCOORD_AUTO | SETCOORD_LENGTH | SETCOORD_INHERIT)
michael@0 685 #define SETCOORD_LPH (SETCOORD_LP | SETCOORD_INHERIT)
michael@0 686 #define SETCOORD_LPAH (SETCOORD_LP | SETCOORD_AH)
michael@0 687 #define SETCOORD_LPE (SETCOORD_LP | SETCOORD_ENUMERATED)
michael@0 688 #define SETCOORD_LPEH (SETCOORD_LPE | SETCOORD_INHERIT)
michael@0 689 #define SETCOORD_LPAEH (SETCOORD_LPAH | SETCOORD_ENUMERATED)
michael@0 690 #define SETCOORD_LPO (SETCOORD_LP | SETCOORD_NONE)
michael@0 691 #define SETCOORD_LPOH (SETCOORD_LPH | SETCOORD_NONE)
michael@0 692 #define SETCOORD_LPOEH (SETCOORD_LPOH | SETCOORD_ENUMERATED)
michael@0 693 #define SETCOORD_LE (SETCOORD_LENGTH | SETCOORD_ENUMERATED)
michael@0 694 #define SETCOORD_LEH (SETCOORD_LE | SETCOORD_INHERIT)
michael@0 695 #define SETCOORD_IA (SETCOORD_INTEGER | SETCOORD_AUTO)
michael@0 696 #define SETCOORD_LAE (SETCOORD_LENGTH | SETCOORD_AUTO | SETCOORD_ENUMERATED)
michael@0 697
michael@0 698 // changes aCoord iff it returns true
michael@0 699 static bool SetCoord(const nsCSSValue& aValue, nsStyleCoord& aCoord,
michael@0 700 const nsStyleCoord& aParentCoord,
michael@0 701 int32_t aMask, nsStyleContext* aStyleContext,
michael@0 702 nsPresContext* aPresContext,
michael@0 703 bool& aCanStoreInRuleTree)
michael@0 704 {
michael@0 705 bool result = true;
michael@0 706 if (aValue.GetUnit() == eCSSUnit_Null) {
michael@0 707 result = false;
michael@0 708 }
michael@0 709 else if ((((aMask & SETCOORD_LENGTH) != 0) &&
michael@0 710 aValue.IsLengthUnit()) ||
michael@0 711 (((aMask & SETCOORD_CALC_LENGTH_ONLY) != 0) &&
michael@0 712 aValue.IsCalcUnit())) {
michael@0 713 nscoord len = CalcLength(aValue, aStyleContext, aPresContext,
michael@0 714 aCanStoreInRuleTree);
michael@0 715 if ((aMask & SETCOORD_CALC_CLAMP_NONNEGATIVE) && len < 0) {
michael@0 716 NS_ASSERTION(aValue.IsCalcUnit(),
michael@0 717 "parser should have ensured no nonnegative lengths");
michael@0 718 len = 0;
michael@0 719 }
michael@0 720 aCoord.SetCoordValue(len);
michael@0 721 }
michael@0 722 else if (((aMask & SETCOORD_PERCENT) != 0) &&
michael@0 723 (aValue.GetUnit() == eCSSUnit_Percent)) {
michael@0 724 aCoord.SetPercentValue(aValue.GetPercentValue());
michael@0 725 }
michael@0 726 else if (((aMask & SETCOORD_INTEGER) != 0) &&
michael@0 727 (aValue.GetUnit() == eCSSUnit_Integer)) {
michael@0 728 aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Integer);
michael@0 729 }
michael@0 730 else if (((aMask & SETCOORD_ENUMERATED) != 0) &&
michael@0 731 (aValue.GetUnit() == eCSSUnit_Enumerated)) {
michael@0 732 aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Enumerated);
michael@0 733 }
michael@0 734 else if (((aMask & SETCOORD_BOX_POSITION) != 0) &&
michael@0 735 (aValue.GetUnit() == eCSSUnit_Enumerated)) {
michael@0 736 aCoord.SetPercentValue(GetFloatFromBoxPosition(aValue.GetIntValue()));
michael@0 737 }
michael@0 738 else if (((aMask & SETCOORD_AUTO) != 0) &&
michael@0 739 (aValue.GetUnit() == eCSSUnit_Auto)) {
michael@0 740 aCoord.SetAutoValue();
michael@0 741 }
michael@0 742 else if ((((aMask & SETCOORD_INHERIT) != 0) &&
michael@0 743 aValue.GetUnit() == eCSSUnit_Inherit) ||
michael@0 744 (((aMask & SETCOORD_UNSET_INHERIT) != 0) &&
michael@0 745 aValue.GetUnit() == eCSSUnit_Unset)) {
michael@0 746 aCoord = aParentCoord; // just inherit value from parent
michael@0 747 aCanStoreInRuleTree = false;
michael@0 748 }
michael@0 749 else if (((aMask & SETCOORD_NORMAL) != 0) &&
michael@0 750 (aValue.GetUnit() == eCSSUnit_Normal)) {
michael@0 751 aCoord.SetNormalValue();
michael@0 752 }
michael@0 753 else if (((aMask & SETCOORD_NONE) != 0) &&
michael@0 754 (aValue.GetUnit() == eCSSUnit_None)) {
michael@0 755 aCoord.SetNoneValue();
michael@0 756 }
michael@0 757 else if (((aMask & SETCOORD_FACTOR) != 0) &&
michael@0 758 (aValue.GetUnit() == eCSSUnit_Number)) {
michael@0 759 aCoord.SetFactorValue(aValue.GetFloatValue());
michael@0 760 }
michael@0 761 else if (((aMask & SETCOORD_STORE_CALC) != 0) &&
michael@0 762 (aValue.IsCalcUnit())) {
michael@0 763 SpecifiedCalcToComputedCalc(aValue, aCoord, aStyleContext,
michael@0 764 aCanStoreInRuleTree);
michael@0 765 }
michael@0 766 else if (aValue.GetUnit() == eCSSUnit_Initial ||
michael@0 767 (aValue.GetUnit() == eCSSUnit_Unset &&
michael@0 768 ((aMask & SETCOORD_UNSET_INITIAL) != 0))) {
michael@0 769 if ((aMask & SETCOORD_INITIAL_AUTO) != 0) {
michael@0 770 aCoord.SetAutoValue();
michael@0 771 }
michael@0 772 else if ((aMask & SETCOORD_INITIAL_ZERO) != 0) {
michael@0 773 aCoord.SetCoordValue(0);
michael@0 774 }
michael@0 775 else if ((aMask & SETCOORD_INITIAL_FACTOR_ZERO) != 0) {
michael@0 776 aCoord.SetFactorValue(0.0f);
michael@0 777 }
michael@0 778 else if ((aMask & SETCOORD_INITIAL_NONE) != 0) {
michael@0 779 aCoord.SetNoneValue();
michael@0 780 }
michael@0 781 else if ((aMask & SETCOORD_INITIAL_NORMAL) != 0) {
michael@0 782 aCoord.SetNormalValue();
michael@0 783 }
michael@0 784 else if ((aMask & SETCOORD_INITIAL_HALF) != 0) {
michael@0 785 aCoord.SetPercentValue(0.5f);
michael@0 786 }
michael@0 787 else if ((aMask & SETCOORD_INITIAL_HUNDRED_PCT) != 0) {
michael@0 788 aCoord.SetPercentValue(1.0f);
michael@0 789 }
michael@0 790 else if ((aMask & SETCOORD_INITIAL_FACTOR_ONE) != 0) {
michael@0 791 aCoord.SetFactorValue(1.0f);
michael@0 792 }
michael@0 793 else {
michael@0 794 result = false; // didn't set anything
michael@0 795 }
michael@0 796 }
michael@0 797 else if ((aMask & SETCOORD_ANGLE) != 0 &&
michael@0 798 (aValue.IsAngularUnit())) {
michael@0 799 nsStyleUnit unit;
michael@0 800 switch (aValue.GetUnit()) {
michael@0 801 case eCSSUnit_Degree: unit = eStyleUnit_Degree; break;
michael@0 802 case eCSSUnit_Grad: unit = eStyleUnit_Grad; break;
michael@0 803 case eCSSUnit_Radian: unit = eStyleUnit_Radian; break;
michael@0 804 case eCSSUnit_Turn: unit = eStyleUnit_Turn; break;
michael@0 805 default: NS_NOTREACHED("unrecognized angular unit");
michael@0 806 unit = eStyleUnit_Degree;
michael@0 807 }
michael@0 808 aCoord.SetAngleValue(aValue.GetAngleValue(), unit);
michael@0 809 }
michael@0 810 else {
michael@0 811 result = false; // didn't set anything
michael@0 812 }
michael@0 813 return result;
michael@0 814 }
michael@0 815
michael@0 816 // This inline function offers a shortcut for SetCoord() by refusing to accept
michael@0 817 // SETCOORD_LENGTH, SETCOORD_INHERIT and SETCOORD_UNSET_* masks.
michael@0 818 static inline bool SetAbsCoord(const nsCSSValue& aValue,
michael@0 819 nsStyleCoord& aCoord,
michael@0 820 int32_t aMask)
michael@0 821 {
michael@0 822 NS_ABORT_IF_FALSE((aMask & (SETCOORD_LH | SETCOORD_UNSET_INHERIT |
michael@0 823 SETCOORD_UNSET_INITIAL)) == 0,
michael@0 824 "does not handle SETCOORD_LENGTH, SETCOORD_INHERIT and "
michael@0 825 "SETCOORD_UNSET_*");
michael@0 826
michael@0 827 // The values of the following variables will never be used; so it does not
michael@0 828 // matter what to set.
michael@0 829 const nsStyleCoord dummyParentCoord;
michael@0 830 nsStyleContext* dummyStyleContext = nullptr;
michael@0 831 nsPresContext* dummyPresContext = nullptr;
michael@0 832 bool dummyCanStoreInRuleTree = true;
michael@0 833
michael@0 834 bool rv = SetCoord(aValue, aCoord, dummyParentCoord, aMask,
michael@0 835 dummyStyleContext, dummyPresContext,
michael@0 836 dummyCanStoreInRuleTree);
michael@0 837 NS_ABORT_IF_FALSE(dummyCanStoreInRuleTree,
michael@0 838 "SetCoord() should not modify dummyCanStoreInRuleTree.");
michael@0 839
michael@0 840 return rv;
michael@0 841 }
michael@0 842
michael@0 843 /* Given a specified value that might be a pair value, call SetCoord twice,
michael@0 844 * either using each member of the pair, or using the unpaired value twice.
michael@0 845 */
michael@0 846 static bool
michael@0 847 SetPairCoords(const nsCSSValue& aValue,
michael@0 848 nsStyleCoord& aCoordX, nsStyleCoord& aCoordY,
michael@0 849 const nsStyleCoord& aParentX, const nsStyleCoord& aParentY,
michael@0 850 int32_t aMask, nsStyleContext* aStyleContext,
michael@0 851 nsPresContext* aPresContext, bool& aCanStoreInRuleTree)
michael@0 852 {
michael@0 853 const nsCSSValue& valX =
michael@0 854 aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mXValue : aValue;
michael@0 855 const nsCSSValue& valY =
michael@0 856 aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mYValue : aValue;
michael@0 857
michael@0 858 bool cX = SetCoord(valX, aCoordX, aParentX, aMask, aStyleContext,
michael@0 859 aPresContext, aCanStoreInRuleTree);
michael@0 860 mozilla::DebugOnly<bool> cY = SetCoord(valY, aCoordY, aParentY, aMask,
michael@0 861 aStyleContext, aPresContext, aCanStoreInRuleTree);
michael@0 862 NS_ABORT_IF_FALSE(cX == cY, "changed one but not the other");
michael@0 863 return cX;
michael@0 864 }
michael@0 865
michael@0 866 static bool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
michael@0 867 nsPresContext* aPresContext, nsStyleContext *aContext,
michael@0 868 nscolor& aResult, bool& aCanStoreInRuleTree)
michael@0 869 {
michael@0 870 bool result = false;
michael@0 871 nsCSSUnit unit = aValue.GetUnit();
michael@0 872
michael@0 873 if (aValue.IsNumericColorUnit()) {
michael@0 874 aResult = aValue.GetColorValue();
michael@0 875 result = true;
michael@0 876 }
michael@0 877 else if (eCSSUnit_Ident == unit) {
michael@0 878 nsAutoString value;
michael@0 879 aValue.GetStringValue(value);
michael@0 880 nscolor rgba;
michael@0 881 if (NS_ColorNameToRGB(value, &rgba)) {
michael@0 882 aResult = rgba;
michael@0 883 result = true;
michael@0 884 }
michael@0 885 }
michael@0 886 else if (eCSSUnit_EnumColor == unit) {
michael@0 887 int32_t intValue = aValue.GetIntValue();
michael@0 888 if (0 <= intValue) {
michael@0 889 LookAndFeel::ColorID colorID = (LookAndFeel::ColorID) intValue;
michael@0 890 bool useStandinsForNativeColors = aPresContext &&
michael@0 891 !aPresContext->IsChrome();
michael@0 892 if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID,
michael@0 893 useStandinsForNativeColors, &aResult))) {
michael@0 894 result = true;
michael@0 895 }
michael@0 896 }
michael@0 897 else {
michael@0 898 aResult = NS_RGB(0, 0, 0);
michael@0 899 result = false;
michael@0 900 switch (intValue) {
michael@0 901 case NS_COLOR_MOZ_HYPERLINKTEXT:
michael@0 902 if (aPresContext) {
michael@0 903 aResult = aPresContext->DefaultLinkColor();
michael@0 904 result = true;
michael@0 905 }
michael@0 906 break;
michael@0 907 case NS_COLOR_MOZ_VISITEDHYPERLINKTEXT:
michael@0 908 if (aPresContext) {
michael@0 909 aResult = aPresContext->DefaultVisitedLinkColor();
michael@0 910 result = true;
michael@0 911 }
michael@0 912 break;
michael@0 913 case NS_COLOR_MOZ_ACTIVEHYPERLINKTEXT:
michael@0 914 if (aPresContext) {
michael@0 915 aResult = aPresContext->DefaultActiveLinkColor();
michael@0 916 result = true;
michael@0 917 }
michael@0 918 break;
michael@0 919 case NS_COLOR_CURRENTCOLOR:
michael@0 920 // The data computed from this can't be shared in the rule tree
michael@0 921 // because they could be used on a node with a different color
michael@0 922 aCanStoreInRuleTree = false;
michael@0 923 if (aContext) {
michael@0 924 aResult = aContext->StyleColor()->mColor;
michael@0 925 result = true;
michael@0 926 }
michael@0 927 break;
michael@0 928 case NS_COLOR_MOZ_DEFAULT_COLOR:
michael@0 929 if (aPresContext) {
michael@0 930 aResult = aPresContext->DefaultColor();
michael@0 931 result = true;
michael@0 932 }
michael@0 933 break;
michael@0 934 case NS_COLOR_MOZ_DEFAULT_BACKGROUND_COLOR:
michael@0 935 if (aPresContext) {
michael@0 936 aResult = aPresContext->DefaultBackgroundColor();
michael@0 937 result = true;
michael@0 938 }
michael@0 939 break;
michael@0 940 default:
michael@0 941 NS_NOTREACHED("Should never have an unknown negative colorID.");
michael@0 942 break;
michael@0 943 }
michael@0 944 }
michael@0 945 }
michael@0 946 else if (eCSSUnit_Inherit == unit) {
michael@0 947 aResult = aParentColor;
michael@0 948 result = true;
michael@0 949 aCanStoreInRuleTree = false;
michael@0 950 }
michael@0 951 else if (eCSSUnit_Enumerated == unit &&
michael@0 952 aValue.GetIntValue() == NS_STYLE_COLOR_INHERIT_FROM_BODY) {
michael@0 953 NS_ASSERTION(aPresContext->CompatibilityMode() == eCompatibility_NavQuirks,
michael@0 954 "Should only get this value in quirks mode");
michael@0 955 // We just grab the color from the prescontext, and rely on the fact that
michael@0 956 // if the body color ever changes all its descendants will get new style
michael@0 957 // contexts (but NOT necessarily new rulenodes).
michael@0 958 aResult = aPresContext->BodyTextColor();
michael@0 959 result = true;
michael@0 960 aCanStoreInRuleTree = false;
michael@0 961 }
michael@0 962 return result;
michael@0 963 }
michael@0 964
michael@0 965 static void SetGradientCoord(const nsCSSValue& aValue, nsPresContext* aPresContext,
michael@0 966 nsStyleContext* aContext, nsStyleCoord& aResult,
michael@0 967 bool& aCanStoreInRuleTree)
michael@0 968 {
michael@0 969 // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
michael@0 970 if (!SetCoord(aValue, aResult, nsStyleCoord(),
michael@0 971 SETCOORD_LPO | SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC,
michael@0 972 aContext, aPresContext, aCanStoreInRuleTree)) {
michael@0 973 NS_NOTREACHED("unexpected unit for gradient anchor point");
michael@0 974 aResult.SetNoneValue();
michael@0 975 }
michael@0 976 }
michael@0 977
michael@0 978 static void SetGradient(const nsCSSValue& aValue, nsPresContext* aPresContext,
michael@0 979 nsStyleContext* aContext, nsStyleGradient& aResult,
michael@0 980 bool& aCanStoreInRuleTree)
michael@0 981 {
michael@0 982 NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Gradient,
michael@0 983 "The given data is not a gradient");
michael@0 984
michael@0 985 const nsCSSValueGradient* gradient = aValue.GetGradientValue();
michael@0 986
michael@0 987 if (gradient->mIsExplicitSize) {
michael@0 988 SetCoord(gradient->GetRadiusX(), aResult.mRadiusX, nsStyleCoord(),
michael@0 989 SETCOORD_LP | SETCOORD_STORE_CALC,
michael@0 990 aContext, aPresContext, aCanStoreInRuleTree);
michael@0 991 if (gradient->GetRadiusY().GetUnit() != eCSSUnit_None) {
michael@0 992 SetCoord(gradient->GetRadiusY(), aResult.mRadiusY, nsStyleCoord(),
michael@0 993 SETCOORD_LP | SETCOORD_STORE_CALC,
michael@0 994 aContext, aPresContext, aCanStoreInRuleTree);
michael@0 995 aResult.mShape = NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL;
michael@0 996 } else {
michael@0 997 aResult.mRadiusY = aResult.mRadiusX;
michael@0 998 aResult.mShape = NS_STYLE_GRADIENT_SHAPE_CIRCULAR;
michael@0 999 }
michael@0 1000 aResult.mSize = NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE;
michael@0 1001 } else if (gradient->mIsRadial) {
michael@0 1002 if (gradient->GetRadialShape().GetUnit() == eCSSUnit_Enumerated) {
michael@0 1003 aResult.mShape = gradient->GetRadialShape().GetIntValue();
michael@0 1004 } else {
michael@0 1005 NS_ASSERTION(gradient->GetRadialShape().GetUnit() == eCSSUnit_None,
michael@0 1006 "bad unit for radial shape");
michael@0 1007 aResult.mShape = NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL;
michael@0 1008 }
michael@0 1009 if (gradient->GetRadialSize().GetUnit() == eCSSUnit_Enumerated) {
michael@0 1010 aResult.mSize = gradient->GetRadialSize().GetIntValue();
michael@0 1011 } else {
michael@0 1012 NS_ASSERTION(gradient->GetRadialSize().GetUnit() == eCSSUnit_None,
michael@0 1013 "bad unit for radial shape");
michael@0 1014 aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER;
michael@0 1015 }
michael@0 1016 } else {
michael@0 1017 NS_ASSERTION(gradient->GetRadialShape().GetUnit() == eCSSUnit_None,
michael@0 1018 "bad unit for linear shape");
michael@0 1019 NS_ASSERTION(gradient->GetRadialSize().GetUnit() == eCSSUnit_None,
michael@0 1020 "bad unit for linear size");
michael@0 1021 aResult.mShape = NS_STYLE_GRADIENT_SHAPE_LINEAR;
michael@0 1022 aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER;
michael@0 1023 }
michael@0 1024
michael@0 1025 aResult.mLegacySyntax = gradient->mIsLegacySyntax;
michael@0 1026
michael@0 1027 // bg-position
michael@0 1028 SetGradientCoord(gradient->mBgPos.mXValue, aPresContext, aContext,
michael@0 1029 aResult.mBgPosX, aCanStoreInRuleTree);
michael@0 1030
michael@0 1031 SetGradientCoord(gradient->mBgPos.mYValue, aPresContext, aContext,
michael@0 1032 aResult.mBgPosY, aCanStoreInRuleTree);
michael@0 1033
michael@0 1034 aResult.mRepeating = gradient->mIsRepeating;
michael@0 1035
michael@0 1036 // angle
michael@0 1037 const nsStyleCoord dummyParentCoord;
michael@0 1038 if (!SetCoord(gradient->mAngle, aResult.mAngle, dummyParentCoord, SETCOORD_ANGLE,
michael@0 1039 aContext, aPresContext, aCanStoreInRuleTree)) {
michael@0 1040 NS_ASSERTION(gradient->mAngle.GetUnit() == eCSSUnit_None,
michael@0 1041 "bad unit for gradient angle");
michael@0 1042 aResult.mAngle.SetNoneValue();
michael@0 1043 }
michael@0 1044
michael@0 1045 // stops
michael@0 1046 for (uint32_t i = 0; i < gradient->mStops.Length(); i++) {
michael@0 1047 nsStyleGradientStop stop;
michael@0 1048 const nsCSSValueGradientStop &valueStop = gradient->mStops[i];
michael@0 1049
michael@0 1050 if (!SetCoord(valueStop.mLocation, stop.mLocation,
michael@0 1051 nsStyleCoord(), SETCOORD_LPO | SETCOORD_STORE_CALC,
michael@0 1052 aContext, aPresContext, aCanStoreInRuleTree)) {
michael@0 1053 NS_NOTREACHED("unexpected unit for gradient stop location");
michael@0 1054 }
michael@0 1055
michael@0 1056 // inherit is not a valid color for stops, so we pass in a dummy
michael@0 1057 // parent color
michael@0 1058 NS_ASSERTION(valueStop.mColor.GetUnit() != eCSSUnit_Inherit,
michael@0 1059 "inherit is not a valid color for gradient stops");
michael@0 1060 SetColor(valueStop.mColor, NS_RGB(0, 0, 0), aPresContext,
michael@0 1061 aContext, stop.mColor, aCanStoreInRuleTree);
michael@0 1062
michael@0 1063 aResult.mStops.AppendElement(stop);
michael@0 1064 }
michael@0 1065 }
michael@0 1066
michael@0 1067 // -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
michael@0 1068 static void SetStyleImageToImageRect(nsStyleContext* aStyleContext,
michael@0 1069 const nsCSSValue& aValue,
michael@0 1070 nsStyleImage& aResult)
michael@0 1071 {
michael@0 1072 NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Function &&
michael@0 1073 aValue.EqualsFunction(eCSSKeyword__moz_image_rect),
michael@0 1074 "the value is not valid -moz-image-rect()");
michael@0 1075
michael@0 1076 nsCSSValue::Array* arr = aValue.GetArrayValue();
michael@0 1077 NS_ABORT_IF_FALSE(arr && arr->Count() == 6, "invalid number of arguments");
michael@0 1078
michael@0 1079 // <uri>
michael@0 1080 if (arr->Item(1).GetUnit() == eCSSUnit_Image) {
michael@0 1081 NS_SET_IMAGE_REQUEST_WITH_DOC(aResult.SetImageData,
michael@0 1082 aStyleContext,
michael@0 1083 arr->Item(1).GetImageValue)
michael@0 1084 } else {
michael@0 1085 NS_WARNING("nsCSSValue::Image::Image() failed?");
michael@0 1086 }
michael@0 1087
michael@0 1088 // <top>, <right>, <bottom>, <left>
michael@0 1089 nsStyleSides cropRect;
michael@0 1090 NS_FOR_CSS_SIDES(side) {
michael@0 1091 nsStyleCoord coord;
michael@0 1092 const nsCSSValue& val = arr->Item(2 + side);
michael@0 1093
michael@0 1094 #ifdef DEBUG
michael@0 1095 bool unitOk =
michael@0 1096 #endif
michael@0 1097 SetAbsCoord(val, coord, SETCOORD_FACTOR | SETCOORD_PERCENT);
michael@0 1098 NS_ABORT_IF_FALSE(unitOk, "Incorrect data structure created by CSS parser");
michael@0 1099 cropRect.Set(side, coord);
michael@0 1100 }
michael@0 1101 aResult.SetCropRect(&cropRect);
michael@0 1102 }
michael@0 1103
michael@0 1104 static void SetStyleImage(nsStyleContext* aStyleContext,
michael@0 1105 const nsCSSValue& aValue,
michael@0 1106 nsStyleImage& aResult,
michael@0 1107 bool& aCanStoreInRuleTree)
michael@0 1108 {
michael@0 1109 if (aValue.GetUnit() == eCSSUnit_Null) {
michael@0 1110 return;
michael@0 1111 }
michael@0 1112
michael@0 1113 aResult.SetNull();
michael@0 1114
michael@0 1115 switch (aValue.GetUnit()) {
michael@0 1116 case eCSSUnit_Image:
michael@0 1117 NS_SET_IMAGE_REQUEST_WITH_DOC(aResult.SetImageData,
michael@0 1118 aStyleContext,
michael@0 1119 aValue.GetImageValue)
michael@0 1120 break;
michael@0 1121 case eCSSUnit_Function:
michael@0 1122 if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) {
michael@0 1123 SetStyleImageToImageRect(aStyleContext, aValue, aResult);
michael@0 1124 } else {
michael@0 1125 NS_NOTREACHED("-moz-image-rect() is the only expected function");
michael@0 1126 }
michael@0 1127 break;
michael@0 1128 case eCSSUnit_Gradient:
michael@0 1129 {
michael@0 1130 nsStyleGradient* gradient = new nsStyleGradient();
michael@0 1131 if (gradient) {
michael@0 1132 SetGradient(aValue, aStyleContext->PresContext(), aStyleContext,
michael@0 1133 *gradient, aCanStoreInRuleTree);
michael@0 1134 aResult.SetGradientData(gradient);
michael@0 1135 }
michael@0 1136 break;
michael@0 1137 }
michael@0 1138 case eCSSUnit_Element:
michael@0 1139 aResult.SetElementId(aValue.GetStringBufferValue());
michael@0 1140 break;
michael@0 1141 case eCSSUnit_Initial:
michael@0 1142 case eCSSUnit_Unset:
michael@0 1143 case eCSSUnit_None:
michael@0 1144 break;
michael@0 1145 default:
michael@0 1146 // We might have eCSSUnit_URL values for if-visited style
michael@0 1147 // contexts, which we can safely treat like 'none'. Otherwise
michael@0 1148 // this is an unexpected unit.
michael@0 1149 NS_ASSERTION(aStyleContext->IsStyleIfVisited() &&
michael@0 1150 aValue.GetUnit() == eCSSUnit_URL,
michael@0 1151 "unexpected unit; maybe nsCSSValue::Image::Image() failed?");
michael@0 1152 break;
michael@0 1153 }
michael@0 1154 }
michael@0 1155
michael@0 1156 // flags for SetDiscrete - align values with SETCOORD_* constants
michael@0 1157 // where possible
michael@0 1158
michael@0 1159 #define SETDSC_NORMAL 0x01 // N
michael@0 1160 #define SETDSC_AUTO 0x02 // A
michael@0 1161 #define SETDSC_INTEGER 0x40 // I
michael@0 1162 #define SETDSC_ENUMERATED 0x80 // E
michael@0 1163 #define SETDSC_NONE 0x100 // O
michael@0 1164 #define SETDSC_SYSTEM_FONT 0x2000
michael@0 1165 #define SETDSC_UNSET_INHERIT 0x00400000
michael@0 1166 #define SETDSC_UNSET_INITIAL 0x00800000
michael@0 1167
michael@0 1168 // no caller cares whether aField was changed or not
michael@0 1169 template <typename FieldT,
michael@0 1170 typename T1, typename T2, typename T3, typename T4, typename T5>
michael@0 1171 static void
michael@0 1172 SetDiscrete(const nsCSSValue& aValue, FieldT & aField,
michael@0 1173 bool& aCanStoreInRuleTree, uint32_t aMask,
michael@0 1174 FieldT aParentValue,
michael@0 1175 T1 aInitialValue,
michael@0 1176 T2 aAutoValue,
michael@0 1177 T3 aNoneValue,
michael@0 1178 T4 aNormalValue,
michael@0 1179 T5 aSystemFontValue)
michael@0 1180 {
michael@0 1181 switch (aValue.GetUnit()) {
michael@0 1182 case eCSSUnit_Null:
michael@0 1183 return;
michael@0 1184
michael@0 1185 // every caller of SetDiscrete provides inherit and initial
michael@0 1186 // alternatives, so we don't require them to say so in the mask
michael@0 1187 case eCSSUnit_Inherit:
michael@0 1188 aCanStoreInRuleTree = false;
michael@0 1189 aField = aParentValue;
michael@0 1190 return;
michael@0 1191
michael@0 1192 case eCSSUnit_Initial:
michael@0 1193 aField = aInitialValue;
michael@0 1194 return;
michael@0 1195
michael@0 1196 // every caller provides one or other of these alternatives,
michael@0 1197 // but they have to say which
michael@0 1198 case eCSSUnit_Enumerated:
michael@0 1199 if (aMask & SETDSC_ENUMERATED) {
michael@0 1200 aField = aValue.GetIntValue();
michael@0 1201 return;
michael@0 1202 }
michael@0 1203 break;
michael@0 1204
michael@0 1205 case eCSSUnit_Integer:
michael@0 1206 if (aMask & SETDSC_INTEGER) {
michael@0 1207 aField = aValue.GetIntValue();
michael@0 1208 return;
michael@0 1209 }
michael@0 1210 break;
michael@0 1211
michael@0 1212 // remaining possibilities in descending order of frequency of use
michael@0 1213 case eCSSUnit_Auto:
michael@0 1214 if (aMask & SETDSC_AUTO) {
michael@0 1215 aField = aAutoValue;
michael@0 1216 return;
michael@0 1217 }
michael@0 1218 break;
michael@0 1219
michael@0 1220 case eCSSUnit_None:
michael@0 1221 if (aMask & SETDSC_NONE) {
michael@0 1222 aField = aNoneValue;
michael@0 1223 return;
michael@0 1224 }
michael@0 1225 break;
michael@0 1226
michael@0 1227 case eCSSUnit_Normal:
michael@0 1228 if (aMask & SETDSC_NORMAL) {
michael@0 1229 aField = aNormalValue;
michael@0 1230 return;
michael@0 1231 }
michael@0 1232 break;
michael@0 1233
michael@0 1234 case eCSSUnit_System_Font:
michael@0 1235 if (aMask & SETDSC_SYSTEM_FONT) {
michael@0 1236 aField = aSystemFontValue;
michael@0 1237 return;
michael@0 1238 }
michael@0 1239 break;
michael@0 1240
michael@0 1241 case eCSSUnit_Unset:
michael@0 1242 if (aMask & SETDSC_UNSET_INHERIT) {
michael@0 1243 aCanStoreInRuleTree = false;
michael@0 1244 aField = aParentValue;
michael@0 1245 return;
michael@0 1246 }
michael@0 1247 if (aMask & SETDSC_UNSET_INITIAL) {
michael@0 1248 aField = aInitialValue;
michael@0 1249 return;
michael@0 1250 }
michael@0 1251 break;
michael@0 1252
michael@0 1253 default:
michael@0 1254 break;
michael@0 1255 }
michael@0 1256
michael@0 1257 NS_NOTREACHED("SetDiscrete: inappropriate unit");
michael@0 1258 }
michael@0 1259
michael@0 1260 // flags for SetFactor
michael@0 1261 #define SETFCT_POSITIVE 0x01 // assert value is >= 0.0f
michael@0 1262 #define SETFCT_OPACITY 0x02 // clamp value to [0.0f .. 1.0f]
michael@0 1263 #define SETFCT_NONE 0x04 // allow _None (uses aInitialValue).
michael@0 1264 #define SETFCT_UNSET_INHERIT 0x00400000
michael@0 1265 #define SETFCT_UNSET_INITIAL 0x00800000
michael@0 1266
michael@0 1267 static void
michael@0 1268 SetFactor(const nsCSSValue& aValue, float& aField, bool& aCanStoreInRuleTree,
michael@0 1269 float aParentValue, float aInitialValue, uint32_t aFlags = 0)
michael@0 1270 {
michael@0 1271 switch (aValue.GetUnit()) {
michael@0 1272 case eCSSUnit_Null:
michael@0 1273 return;
michael@0 1274
michael@0 1275 case eCSSUnit_Number:
michael@0 1276 aField = aValue.GetFloatValue();
michael@0 1277 if (aFlags & SETFCT_POSITIVE) {
michael@0 1278 NS_ASSERTION(aField >= 0.0f, "negative value for positive-only property");
michael@0 1279 if (aField < 0.0f)
michael@0 1280 aField = 0.0f;
michael@0 1281 }
michael@0 1282 if (aFlags & SETFCT_OPACITY) {
michael@0 1283 if (aField < 0.0f)
michael@0 1284 aField = 0.0f;
michael@0 1285 if (aField > 1.0f)
michael@0 1286 aField = 1.0f;
michael@0 1287 }
michael@0 1288 return;
michael@0 1289
michael@0 1290 case eCSSUnit_Inherit:
michael@0 1291 aCanStoreInRuleTree = false;
michael@0 1292 aField = aParentValue;
michael@0 1293 return;
michael@0 1294
michael@0 1295 case eCSSUnit_Initial:
michael@0 1296 aField = aInitialValue;
michael@0 1297 return;
michael@0 1298
michael@0 1299 case eCSSUnit_None:
michael@0 1300 if (aFlags & SETFCT_NONE) {
michael@0 1301 aField = aInitialValue;
michael@0 1302 return;
michael@0 1303 }
michael@0 1304 break;
michael@0 1305
michael@0 1306 case eCSSUnit_Unset:
michael@0 1307 if (aFlags & SETFCT_UNSET_INHERIT) {
michael@0 1308 aCanStoreInRuleTree = false;
michael@0 1309 aField = aParentValue;
michael@0 1310 return;
michael@0 1311 }
michael@0 1312 if (aFlags & SETFCT_UNSET_INITIAL) {
michael@0 1313 aField = aInitialValue;
michael@0 1314 return;
michael@0 1315 }
michael@0 1316 break;
michael@0 1317
michael@0 1318 default:
michael@0 1319 break;
michael@0 1320 }
michael@0 1321
michael@0 1322 NS_NOTREACHED("SetFactor: inappropriate unit");
michael@0 1323 }
michael@0 1324
michael@0 1325 // Overloaded new operator. Initializes the memory to 0 and relies on an arena
michael@0 1326 // (which comes from the presShell) to perform the allocation.
michael@0 1327 void*
michael@0 1328 nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
michael@0 1329 {
michael@0 1330 // Check the recycle list first.
michael@0 1331 return aPresContext->PresShell()->AllocateByObjectID(nsPresArena::nsRuleNode_id, sz);
michael@0 1332 }
michael@0 1333
michael@0 1334 /* static */ PLDHashOperator
michael@0 1335 nsRuleNode::EnqueueRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
michael@0 1336 uint32_t number, void *arg)
michael@0 1337 {
michael@0 1338 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
michael@0 1339 nsRuleNode ***destroyQueueTail = static_cast<nsRuleNode***>(arg);
michael@0 1340 **destroyQueueTail = entry->mRuleNode;
michael@0 1341 *destroyQueueTail = &entry->mRuleNode->mNextSibling;
michael@0 1342 return PL_DHASH_NEXT;
michael@0 1343 }
michael@0 1344
michael@0 1345 // Overridden to prevent the global delete from being called, since the memory
michael@0 1346 // came out of an nsIArena instead of the global delete operator's heap.
michael@0 1347 void
michael@0 1348 nsRuleNode::DestroyInternal(nsRuleNode ***aDestroyQueueTail)
michael@0 1349 {
michael@0 1350 nsRuleNode *destroyQueue, **destroyQueueTail;
michael@0 1351 if (aDestroyQueueTail) {
michael@0 1352 destroyQueueTail = *aDestroyQueueTail;
michael@0 1353 } else {
michael@0 1354 destroyQueue = nullptr;
michael@0 1355 destroyQueueTail = &destroyQueue;
michael@0 1356 }
michael@0 1357
michael@0 1358 if (ChildrenAreHashed()) {
michael@0 1359 PLDHashTable *children = ChildrenHash();
michael@0 1360 PL_DHashTableEnumerate(children, EnqueueRuleNodeChildren,
michael@0 1361 &destroyQueueTail);
michael@0 1362 *destroyQueueTail = nullptr; // ensure null-termination
michael@0 1363 PL_DHashTableDestroy(children);
michael@0 1364 } else if (HaveChildren()) {
michael@0 1365 *destroyQueueTail = ChildrenList();
michael@0 1366 do {
michael@0 1367 destroyQueueTail = &(*destroyQueueTail)->mNextSibling;
michael@0 1368 } while (*destroyQueueTail);
michael@0 1369 }
michael@0 1370 mChildren.asVoid = nullptr;
michael@0 1371
michael@0 1372 if (aDestroyQueueTail) {
michael@0 1373 // Our caller destroys the queue.
michael@0 1374 *aDestroyQueueTail = destroyQueueTail;
michael@0 1375 } else {
michael@0 1376 // We have to do destroy the queue. When we destroy each node, it
michael@0 1377 // will add its children to the queue.
michael@0 1378 while (destroyQueue) {
michael@0 1379 nsRuleNode *cur = destroyQueue;
michael@0 1380 destroyQueue = destroyQueue->mNextSibling;
michael@0 1381 if (!destroyQueue) {
michael@0 1382 NS_ASSERTION(destroyQueueTail == &cur->mNextSibling, "mangled list");
michael@0 1383 destroyQueueTail = &destroyQueue;
michael@0 1384 }
michael@0 1385 cur->DestroyInternal(&destroyQueueTail);
michael@0 1386 }
michael@0 1387 }
michael@0 1388
michael@0 1389 // Destroy ourselves.
michael@0 1390 this->~nsRuleNode();
michael@0 1391
michael@0 1392 // Don't let the memory be freed, since it will be recycled
michael@0 1393 // instead. Don't call the global operator delete.
michael@0 1394 mPresContext->PresShell()->FreeByObjectID(nsPresArena::nsRuleNode_id, this);
michael@0 1395 }
michael@0 1396
michael@0 1397 nsRuleNode* nsRuleNode::CreateRootNode(nsPresContext* aPresContext)
michael@0 1398 {
michael@0 1399 return new (aPresContext)
michael@0 1400 nsRuleNode(aPresContext, nullptr, nullptr, 0xff, false);
michael@0 1401 }
michael@0 1402
michael@0 1403 nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
michael@0 1404 nsIStyleRule* aRule, uint8_t aLevel,
michael@0 1405 bool aIsImportant)
michael@0 1406 : mPresContext(aContext),
michael@0 1407 mParent(aParent),
michael@0 1408 mRule(aRule),
michael@0 1409 mDependentBits((uint32_t(aLevel) << NS_RULE_NODE_LEVEL_SHIFT) |
michael@0 1410 (aIsImportant ? NS_RULE_NODE_IS_IMPORTANT : 0)),
michael@0 1411 mNoneBits(0),
michael@0 1412 mRefCnt(0)
michael@0 1413 {
michael@0 1414 MOZ_ASSERT(aContext);
michael@0 1415 NS_ABORT_IF_FALSE(IsRoot() == !aRule,
michael@0 1416 "non-root rule nodes must have a rule");
michael@0 1417
michael@0 1418 mChildren.asVoid = nullptr;
michael@0 1419 MOZ_COUNT_CTOR(nsRuleNode);
michael@0 1420
michael@0 1421 if (mRule) {
michael@0 1422 mRule->AddRef();
michael@0 1423 }
michael@0 1424
michael@0 1425 NS_ASSERTION(IsRoot() || GetLevel() == aLevel, "not enough bits");
michael@0 1426 NS_ASSERTION(IsRoot() || IsImportantRule() == aIsImportant, "yikes");
michael@0 1427 /* If IsRoot(), then aContext->StyleSet() is typically null at this
michael@0 1428 point. In any case, we don't want to treat the root rulenode as
michael@0 1429 unused. */
michael@0 1430 if (!IsRoot()) {
michael@0 1431 mParent->AddRef();
michael@0 1432 aContext->StyleSet()->RuleNodeUnused();
michael@0 1433 }
michael@0 1434
michael@0 1435 // nsStyleSet::GetContext depends on there being only one animation
michael@0 1436 // rule.
michael@0 1437 NS_ABORT_IF_FALSE(IsRoot() || GetLevel() != nsStyleSet::eAnimationSheet ||
michael@0 1438 mParent->IsRoot() ||
michael@0 1439 mParent->GetLevel() != nsStyleSet::eAnimationSheet,
michael@0 1440 "must be only one rule at animation level");
michael@0 1441 }
michael@0 1442
michael@0 1443 nsRuleNode::~nsRuleNode()
michael@0 1444 {
michael@0 1445 MOZ_COUNT_DTOR(nsRuleNode);
michael@0 1446 if (mStyleData.mResetData || mStyleData.mInheritedData)
michael@0 1447 mStyleData.Destroy(mDependentBits, mPresContext);
michael@0 1448 if (mRule) {
michael@0 1449 mRule->Release();
michael@0 1450 }
michael@0 1451 }
michael@0 1452
michael@0 1453 nsRuleNode*
michael@0 1454 nsRuleNode::Transition(nsIStyleRule* aRule, uint8_t aLevel,
michael@0 1455 bool aIsImportantRule)
michael@0 1456 {
michael@0 1457 nsRuleNode* next = nullptr;
michael@0 1458 nsRuleNode::Key key(aRule, aLevel, aIsImportantRule);
michael@0 1459
michael@0 1460 if (HaveChildren() && !ChildrenAreHashed()) {
michael@0 1461 int32_t numKids = 0;
michael@0 1462 nsRuleNode* curr = ChildrenList();
michael@0 1463 while (curr && curr->GetKey() != key) {
michael@0 1464 curr = curr->mNextSibling;
michael@0 1465 ++numKids;
michael@0 1466 }
michael@0 1467 if (curr)
michael@0 1468 next = curr;
michael@0 1469 else if (numKids >= kMaxChildrenInList)
michael@0 1470 ConvertChildrenToHash();
michael@0 1471 }
michael@0 1472
michael@0 1473 if (ChildrenAreHashed()) {
michael@0 1474 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>
michael@0 1475 (PL_DHashTableOperate(ChildrenHash(), &key, PL_DHASH_ADD));
michael@0 1476 if (!entry) {
michael@0 1477 NS_WARNING("out of memory");
michael@0 1478 return this;
michael@0 1479 }
michael@0 1480 if (entry->mRuleNode)
michael@0 1481 next = entry->mRuleNode;
michael@0 1482 else {
michael@0 1483 next = entry->mRuleNode = new (mPresContext)
michael@0 1484 nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
michael@0 1485 if (!next) {
michael@0 1486 PL_DHashTableRawRemove(ChildrenHash(), entry);
michael@0 1487 NS_WARNING("out of memory");
michael@0 1488 return this;
michael@0 1489 }
michael@0 1490 }
michael@0 1491 } else if (!next) {
michael@0 1492 // Create the new entry in our list.
michael@0 1493 next = new (mPresContext)
michael@0 1494 nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
michael@0 1495 if (!next) {
michael@0 1496 NS_WARNING("out of memory");
michael@0 1497 return this;
michael@0 1498 }
michael@0 1499 next->mNextSibling = ChildrenList();
michael@0 1500 SetChildrenList(next);
michael@0 1501 }
michael@0 1502
michael@0 1503 return next;
michael@0 1504 }
michael@0 1505
michael@0 1506 void nsRuleNode::SetUsedDirectly()
michael@0 1507 {
michael@0 1508 mDependentBits |= NS_RULE_NODE_USED_DIRECTLY;
michael@0 1509
michael@0 1510 // Maintain the invariant that any rule node that is used directly has
michael@0 1511 // all structs that live in the rule tree cached (which
michael@0 1512 // nsRuleNode::GetStyleData depends on for speed).
michael@0 1513 if (mDependentBits & NS_STYLE_INHERIT_MASK) {
michael@0 1514 for (nsStyleStructID sid = nsStyleStructID(0); sid < nsStyleStructID_Length;
michael@0 1515 sid = nsStyleStructID(sid + 1)) {
michael@0 1516 uint32_t bit = nsCachedStyleData::GetBitForSID(sid);
michael@0 1517 if (mDependentBits & bit) {
michael@0 1518 nsRuleNode *source = mParent;
michael@0 1519 while ((source->mDependentBits & bit) && !source->IsUsedDirectly()) {
michael@0 1520 source = source->mParent;
michael@0 1521 }
michael@0 1522 void *data = source->mStyleData.GetStyleData(sid);
michael@0 1523 NS_ASSERTION(data, "unexpected null struct");
michael@0 1524 mStyleData.SetStyleData(sid, mPresContext, data);
michael@0 1525 }
michael@0 1526 }
michael@0 1527 }
michael@0 1528 }
michael@0 1529
michael@0 1530 void
michael@0 1531 nsRuleNode::ConvertChildrenToHash()
michael@0 1532 {
michael@0 1533 NS_ASSERTION(!ChildrenAreHashed() && HaveChildren(),
michael@0 1534 "must have a non-empty list of children");
michael@0 1535 PLDHashTable *hash = PL_NewDHashTable(&ChildrenHashOps, nullptr,
michael@0 1536 sizeof(ChildrenHashEntry),
michael@0 1537 kMaxChildrenInList * 4);
michael@0 1538 if (!hash)
michael@0 1539 return;
michael@0 1540 for (nsRuleNode* curr = ChildrenList(); curr; curr = curr->mNextSibling) {
michael@0 1541 // This will never fail because of the initial size we gave the table.
michael@0 1542 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(
michael@0 1543 PL_DHashTableOperate(hash, curr->mRule, PL_DHASH_ADD));
michael@0 1544 NS_ASSERTION(!entry->mRuleNode, "duplicate entries in list");
michael@0 1545 entry->mRuleNode = curr;
michael@0 1546 }
michael@0 1547 SetChildrenHash(hash);
michael@0 1548 }
michael@0 1549
michael@0 1550 inline void
michael@0 1551 nsRuleNode::PropagateNoneBit(uint32_t aBit, nsRuleNode* aHighestNode)
michael@0 1552 {
michael@0 1553 nsRuleNode* curr = this;
michael@0 1554 for (;;) {
michael@0 1555 NS_ASSERTION(!(curr->mNoneBits & aBit), "propagating too far");
michael@0 1556 curr->mNoneBits |= aBit;
michael@0 1557 if (curr == aHighestNode)
michael@0 1558 break;
michael@0 1559 curr = curr->mParent;
michael@0 1560 }
michael@0 1561 }
michael@0 1562
michael@0 1563 inline void
michael@0 1564 nsRuleNode::PropagateDependentBit(nsStyleStructID aSID, nsRuleNode* aHighestNode,
michael@0 1565 void* aStruct)
michael@0 1566 {
michael@0 1567 NS_ASSERTION(aStruct, "expected struct");
michael@0 1568
michael@0 1569 uint32_t bit = nsCachedStyleData::GetBitForSID(aSID);
michael@0 1570 for (nsRuleNode* curr = this; curr != aHighestNode; curr = curr->mParent) {
michael@0 1571 if (curr->mDependentBits & bit) {
michael@0 1572 #ifdef DEBUG
michael@0 1573 while (curr != aHighestNode) {
michael@0 1574 NS_ASSERTION(curr->mDependentBits & bit, "bit not set");
michael@0 1575 curr = curr->mParent;
michael@0 1576 }
michael@0 1577 #endif
michael@0 1578 break;
michael@0 1579 }
michael@0 1580
michael@0 1581 curr->mDependentBits |= bit;
michael@0 1582
michael@0 1583 if (curr->IsUsedDirectly()) {
michael@0 1584 curr->mStyleData.SetStyleData(aSID, mPresContext, aStruct);
michael@0 1585 }
michael@0 1586 }
michael@0 1587 }
michael@0 1588
michael@0 1589 /*
michael@0 1590 * The following "Check" functions are used for determining what type of
michael@0 1591 * sharing can be used for the data on this rule node. MORE HERE...
michael@0 1592 */
michael@0 1593
michael@0 1594 /*
michael@0 1595 * a callback function that that can revise the result of
michael@0 1596 * CheckSpecifiedProperties before finishing; aResult is the current
michael@0 1597 * result, and it returns the revised one.
michael@0 1598 */
michael@0 1599 typedef nsRuleNode::RuleDetail
michael@0 1600 (* CheckCallbackFn)(const nsRuleData* aRuleData,
michael@0 1601 nsRuleNode::RuleDetail aResult);
michael@0 1602
michael@0 1603 /**
michael@0 1604 * @param aValue the value being examined
michael@0 1605 * @param aSpecifiedCount to be incremented by one if the value is specified
michael@0 1606 * @param aInheritedCount to be incremented by one if the value is set to inherit
michael@0 1607 * @param aUnsetCount to be incremented by one if the value is set to unset
michael@0 1608 */
michael@0 1609 inline void
michael@0 1610 ExamineCSSValue(const nsCSSValue& aValue,
michael@0 1611 uint32_t& aSpecifiedCount,
michael@0 1612 uint32_t& aInheritedCount,
michael@0 1613 uint32_t& aUnsetCount)
michael@0 1614 {
michael@0 1615 if (aValue.GetUnit() != eCSSUnit_Null) {
michael@0 1616 ++aSpecifiedCount;
michael@0 1617 if (aValue.GetUnit() == eCSSUnit_Inherit) {
michael@0 1618 ++aInheritedCount;
michael@0 1619 } else if (aValue.GetUnit() == eCSSUnit_Unset) {
michael@0 1620 ++aUnsetCount;
michael@0 1621 }
michael@0 1622 }
michael@0 1623 }
michael@0 1624
michael@0 1625 static nsRuleNode::RuleDetail
michael@0 1626 CheckFontCallback(const nsRuleData* aRuleData,
michael@0 1627 nsRuleNode::RuleDetail aResult)
michael@0 1628 {
michael@0 1629 // em, ex, percent, 'larger', and 'smaller' values on font-size depend
michael@0 1630 // on the parent context's font-size
michael@0 1631 // Likewise, 'lighter' and 'bolder' values of 'font-weight', and 'wider'
michael@0 1632 // and 'narrower' values of 'font-stretch' depend on the parent.
michael@0 1633 const nsCSSValue& size = *aRuleData->ValueForFontSize();
michael@0 1634 const nsCSSValue& weight = *aRuleData->ValueForFontWeight();
michael@0 1635 if ((size.IsRelativeLengthUnit() && size.GetUnit() != eCSSUnit_RootEM) ||
michael@0 1636 size.GetUnit() == eCSSUnit_Percent ||
michael@0 1637 (size.GetUnit() == eCSSUnit_Enumerated &&
michael@0 1638 (size.GetIntValue() == NS_STYLE_FONT_SIZE_SMALLER ||
michael@0 1639 size.GetIntValue() == NS_STYLE_FONT_SIZE_LARGER)) ||
michael@0 1640 aRuleData->ValueForScriptLevel()->GetUnit() == eCSSUnit_Integer ||
michael@0 1641 (weight.GetUnit() == eCSSUnit_Enumerated &&
michael@0 1642 (weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_BOLDER ||
michael@0 1643 weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_LIGHTER))) {
michael@0 1644 NS_ASSERTION(aResult == nsRuleNode::eRulePartialReset ||
michael@0 1645 aResult == nsRuleNode::eRuleFullReset ||
michael@0 1646 aResult == nsRuleNode::eRulePartialMixed ||
michael@0 1647 aResult == nsRuleNode::eRuleFullMixed,
michael@0 1648 "we know we already have a reset-counted property");
michael@0 1649 // Promote reset to mixed since we have something that depends on
michael@0 1650 // the parent. But never promote to inherited since that could
michael@0 1651 // cause inheritance of the exact value.
michael@0 1652 if (aResult == nsRuleNode::eRulePartialReset)
michael@0 1653 aResult = nsRuleNode::eRulePartialMixed;
michael@0 1654 else if (aResult == nsRuleNode::eRuleFullReset)
michael@0 1655 aResult = nsRuleNode::eRuleFullMixed;
michael@0 1656 }
michael@0 1657
michael@0 1658 return aResult;
michael@0 1659 }
michael@0 1660
michael@0 1661 static nsRuleNode::RuleDetail
michael@0 1662 CheckColorCallback(const nsRuleData* aRuleData,
michael@0 1663 nsRuleNode::RuleDetail aResult)
michael@0 1664 {
michael@0 1665 // currentColor values for color require inheritance
michael@0 1666 const nsCSSValue* colorValue = aRuleData->ValueForColor();
michael@0 1667 if (colorValue->GetUnit() == eCSSUnit_EnumColor &&
michael@0 1668 colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
michael@0 1669 NS_ASSERTION(aResult == nsRuleNode::eRuleFullReset,
michael@0 1670 "we should already be counted as full-reset");
michael@0 1671 aResult = nsRuleNode::eRuleFullInherited;
michael@0 1672 }
michael@0 1673
michael@0 1674 return aResult;
michael@0 1675 }
michael@0 1676
michael@0 1677 static nsRuleNode::RuleDetail
michael@0 1678 CheckTextCallback(const nsRuleData* aRuleData,
michael@0 1679 nsRuleNode::RuleDetail aResult)
michael@0 1680 {
michael@0 1681 const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
michael@0 1682 if (textAlignValue->GetUnit() == eCSSUnit_Enumerated &&
michael@0 1683 textAlignValue->GetIntValue() ==
michael@0 1684 NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT) {
michael@0 1685 // Promote reset to mixed since we have something that depends on
michael@0 1686 // the parent.
michael@0 1687 if (aResult == nsRuleNode::eRulePartialReset)
michael@0 1688 aResult = nsRuleNode::eRulePartialMixed;
michael@0 1689 else if (aResult == nsRuleNode::eRuleFullReset)
michael@0 1690 aResult = nsRuleNode::eRuleFullMixed;
michael@0 1691 }
michael@0 1692
michael@0 1693 return aResult;
michael@0 1694 }
michael@0 1695
michael@0 1696 static nsRuleNode::RuleDetail
michael@0 1697 CheckVariablesCallback(const nsRuleData* aRuleData,
michael@0 1698 nsRuleNode::RuleDetail aResult)
michael@0 1699 {
michael@0 1700 // We don't actually have any properties on nsStyleVariables, so we do
michael@0 1701 // all of the RuleDetail calculation in here.
michael@0 1702 if (aRuleData->mVariables) {
michael@0 1703 return nsRuleNode::eRulePartialMixed;
michael@0 1704 }
michael@0 1705 return nsRuleNode::eRuleNone;
michael@0 1706 }
michael@0 1707
michael@0 1708 #define FLAG_DATA_FOR_PROPERTY(name_, id_, method_, flags_, pref_, \
michael@0 1709 parsevariant_, kwtable_, stylestructoffset_, \
michael@0 1710 animtype_) \
michael@0 1711 flags_,
michael@0 1712
michael@0 1713 // The order here must match the enums in *CheckCounter in nsCSSProps.cpp.
michael@0 1714
michael@0 1715 static const uint32_t gFontFlags[] = {
michael@0 1716 #define CSS_PROP_FONT FLAG_DATA_FOR_PROPERTY
michael@0 1717 #include "nsCSSPropList.h"
michael@0 1718 #undef CSS_PROP_FONT
michael@0 1719 };
michael@0 1720
michael@0 1721 static const uint32_t gDisplayFlags[] = {
michael@0 1722 #define CSS_PROP_DISPLAY FLAG_DATA_FOR_PROPERTY
michael@0 1723 #include "nsCSSPropList.h"
michael@0 1724 #undef CSS_PROP_DISPLAY
michael@0 1725 };
michael@0 1726
michael@0 1727 static const uint32_t gVisibilityFlags[] = {
michael@0 1728 #define CSS_PROP_VISIBILITY FLAG_DATA_FOR_PROPERTY
michael@0 1729 #include "nsCSSPropList.h"
michael@0 1730 #undef CSS_PROP_VISIBILITY
michael@0 1731 };
michael@0 1732
michael@0 1733 static const uint32_t gMarginFlags[] = {
michael@0 1734 #define CSS_PROP_MARGIN FLAG_DATA_FOR_PROPERTY
michael@0 1735 #include "nsCSSPropList.h"
michael@0 1736 #undef CSS_PROP_MARGIN
michael@0 1737 };
michael@0 1738
michael@0 1739 static const uint32_t gBorderFlags[] = {
michael@0 1740 #define CSS_PROP_BORDER FLAG_DATA_FOR_PROPERTY
michael@0 1741 #include "nsCSSPropList.h"
michael@0 1742 #undef CSS_PROP_BORDER
michael@0 1743 };
michael@0 1744
michael@0 1745 static const uint32_t gPaddingFlags[] = {
michael@0 1746 #define CSS_PROP_PADDING FLAG_DATA_FOR_PROPERTY
michael@0 1747 #include "nsCSSPropList.h"
michael@0 1748 #undef CSS_PROP_PADDING
michael@0 1749 };
michael@0 1750
michael@0 1751 static const uint32_t gOutlineFlags[] = {
michael@0 1752 #define CSS_PROP_OUTLINE FLAG_DATA_FOR_PROPERTY
michael@0 1753 #include "nsCSSPropList.h"
michael@0 1754 #undef CSS_PROP_OUTLINE
michael@0 1755 };
michael@0 1756
michael@0 1757 static const uint32_t gListFlags[] = {
michael@0 1758 #define CSS_PROP_LIST FLAG_DATA_FOR_PROPERTY
michael@0 1759 #include "nsCSSPropList.h"
michael@0 1760 #undef CSS_PROP_LIST
michael@0 1761 };
michael@0 1762
michael@0 1763 static const uint32_t gColorFlags[] = {
michael@0 1764 #define CSS_PROP_COLOR FLAG_DATA_FOR_PROPERTY
michael@0 1765 #include "nsCSSPropList.h"
michael@0 1766 #undef CSS_PROP_COLOR
michael@0 1767 };
michael@0 1768
michael@0 1769 static const uint32_t gBackgroundFlags[] = {
michael@0 1770 #define CSS_PROP_BACKGROUND FLAG_DATA_FOR_PROPERTY
michael@0 1771 #include "nsCSSPropList.h"
michael@0 1772 #undef CSS_PROP_BACKGROUND
michael@0 1773 };
michael@0 1774
michael@0 1775 static const uint32_t gPositionFlags[] = {
michael@0 1776 #define CSS_PROP_POSITION FLAG_DATA_FOR_PROPERTY
michael@0 1777 #include "nsCSSPropList.h"
michael@0 1778 #undef CSS_PROP_POSITION
michael@0 1779 };
michael@0 1780
michael@0 1781 static const uint32_t gTableFlags[] = {
michael@0 1782 #define CSS_PROP_TABLE FLAG_DATA_FOR_PROPERTY
michael@0 1783 #include "nsCSSPropList.h"
michael@0 1784 #undef CSS_PROP_TABLE
michael@0 1785 };
michael@0 1786
michael@0 1787 static const uint32_t gTableBorderFlags[] = {
michael@0 1788 #define CSS_PROP_TABLEBORDER FLAG_DATA_FOR_PROPERTY
michael@0 1789 #include "nsCSSPropList.h"
michael@0 1790 #undef CSS_PROP_TABLEBORDER
michael@0 1791 };
michael@0 1792
michael@0 1793 static const uint32_t gContentFlags[] = {
michael@0 1794 #define CSS_PROP_CONTENT FLAG_DATA_FOR_PROPERTY
michael@0 1795 #include "nsCSSPropList.h"
michael@0 1796 #undef CSS_PROP_CONTENT
michael@0 1797 };
michael@0 1798
michael@0 1799 static const uint32_t gQuotesFlags[] = {
michael@0 1800 #define CSS_PROP_QUOTES FLAG_DATA_FOR_PROPERTY
michael@0 1801 #include "nsCSSPropList.h"
michael@0 1802 #undef CSS_PROP_QUOTES
michael@0 1803 };
michael@0 1804
michael@0 1805 static const uint32_t gTextFlags[] = {
michael@0 1806 #define CSS_PROP_TEXT FLAG_DATA_FOR_PROPERTY
michael@0 1807 #include "nsCSSPropList.h"
michael@0 1808 #undef CSS_PROP_TEXT
michael@0 1809 };
michael@0 1810
michael@0 1811 static const uint32_t gTextResetFlags[] = {
michael@0 1812 #define CSS_PROP_TEXTRESET FLAG_DATA_FOR_PROPERTY
michael@0 1813 #include "nsCSSPropList.h"
michael@0 1814 #undef CSS_PROP_TEXTRESET
michael@0 1815 };
michael@0 1816
michael@0 1817 static const uint32_t gUserInterfaceFlags[] = {
michael@0 1818 #define CSS_PROP_USERINTERFACE FLAG_DATA_FOR_PROPERTY
michael@0 1819 #include "nsCSSPropList.h"
michael@0 1820 #undef CSS_PROP_USERINTERFACE
michael@0 1821 };
michael@0 1822
michael@0 1823 static const uint32_t gUIResetFlags[] = {
michael@0 1824 #define CSS_PROP_UIRESET FLAG_DATA_FOR_PROPERTY
michael@0 1825 #include "nsCSSPropList.h"
michael@0 1826 #undef CSS_PROP_UIRESET
michael@0 1827 };
michael@0 1828
michael@0 1829 static const uint32_t gXULFlags[] = {
michael@0 1830 #define CSS_PROP_XUL FLAG_DATA_FOR_PROPERTY
michael@0 1831 #include "nsCSSPropList.h"
michael@0 1832 #undef CSS_PROP_XUL
michael@0 1833 };
michael@0 1834
michael@0 1835 static const uint32_t gSVGFlags[] = {
michael@0 1836 #define CSS_PROP_SVG FLAG_DATA_FOR_PROPERTY
michael@0 1837 #include "nsCSSPropList.h"
michael@0 1838 #undef CSS_PROP_SVG
michael@0 1839 };
michael@0 1840
michael@0 1841 static const uint32_t gSVGResetFlags[] = {
michael@0 1842 #define CSS_PROP_SVGRESET FLAG_DATA_FOR_PROPERTY
michael@0 1843 #include "nsCSSPropList.h"
michael@0 1844 #undef CSS_PROP_SVGRESET
michael@0 1845 };
michael@0 1846
michael@0 1847 static const uint32_t gColumnFlags[] = {
michael@0 1848 #define CSS_PROP_COLUMN FLAG_DATA_FOR_PROPERTY
michael@0 1849 #include "nsCSSPropList.h"
michael@0 1850 #undef CSS_PROP_COLUMN
michael@0 1851 };
michael@0 1852
michael@0 1853 // There are no properties in nsStyleVariables, but we can't have a
michael@0 1854 // zero length array.
michael@0 1855 static const uint32_t gVariablesFlags[] = {
michael@0 1856 0,
michael@0 1857 #define CSS_PROP_VARIABLES FLAG_DATA_FOR_PROPERTY
michael@0 1858 #include "nsCSSPropList.h"
michael@0 1859 #undef CSS_PROP_VARIABLES
michael@0 1860 };
michael@0 1861 static_assert(sizeof(gVariablesFlags) == sizeof(uint32_t),
michael@0 1862 "if nsStyleVariables has properties now you can remove the dummy "
michael@0 1863 "gVariablesFlags entry");
michael@0 1864
michael@0 1865 #undef FLAG_DATA_FOR_PROPERTY
michael@0 1866
michael@0 1867 static const uint32_t* gFlagsByStruct[] = {
michael@0 1868
michael@0 1869 #define STYLE_STRUCT(name, checkdata_cb) \
michael@0 1870 g##name##Flags,
michael@0 1871 #include "nsStyleStructList.h"
michael@0 1872 #undef STYLE_STRUCT
michael@0 1873
michael@0 1874 };
michael@0 1875
michael@0 1876 static const CheckCallbackFn gCheckCallbacks[] = {
michael@0 1877
michael@0 1878 #define STYLE_STRUCT(name, checkdata_cb) \
michael@0 1879 checkdata_cb,
michael@0 1880 #include "nsStyleStructList.h"
michael@0 1881 #undef STYLE_STRUCT
michael@0 1882
michael@0 1883 };
michael@0 1884
michael@0 1885 #ifdef DEBUG
michael@0 1886 static bool
michael@0 1887 AreAllMathMLPropertiesUndefined(const nsRuleData* aRuleData)
michael@0 1888 {
michael@0 1889 return
michael@0 1890 aRuleData->ValueForScriptLevel()->GetUnit() == eCSSUnit_Null &&
michael@0 1891 aRuleData->ValueForScriptSizeMultiplier()->GetUnit() == eCSSUnit_Null &&
michael@0 1892 aRuleData->ValueForScriptMinSize()->GetUnit() == eCSSUnit_Null &&
michael@0 1893 aRuleData->ValueForMathVariant()->GetUnit() == eCSSUnit_Null &&
michael@0 1894 aRuleData->ValueForMathDisplay()->GetUnit() == eCSSUnit_Null;
michael@0 1895 }
michael@0 1896 #endif
michael@0 1897
michael@0 1898 inline nsRuleNode::RuleDetail
michael@0 1899 nsRuleNode::CheckSpecifiedProperties(const nsStyleStructID aSID,
michael@0 1900 const nsRuleData* aRuleData)
michael@0 1901 {
michael@0 1902 // Build a count of the:
michael@0 1903 uint32_t total = 0, // total number of props in the struct
michael@0 1904 specified = 0, // number that were specified for this node
michael@0 1905 inherited = 0, // number that were 'inherit' (and not
michael@0 1906 // eCSSUnit_Inherit) for this node
michael@0 1907 unset = 0; // number that were 'unset'
michael@0 1908
michael@0 1909 // See comment in nsRuleData.h above mValueOffsets.
michael@0 1910 NS_ABORT_IF_FALSE(aRuleData->mValueOffsets[aSID] == 0,
michael@0 1911 "we assume the value offset is zero instead of adding it");
michael@0 1912 for (nsCSSValue *values = aRuleData->mValueStorage,
michael@0 1913 *values_end = values + nsCSSProps::PropertyCountInStruct(aSID);
michael@0 1914 values != values_end; ++values) {
michael@0 1915 ++total;
michael@0 1916 ExamineCSSValue(*values, specified, inherited, unset);
michael@0 1917 }
michael@0 1918
michael@0 1919 if (!nsCachedStyleData::IsReset(aSID)) {
michael@0 1920 // For inherited properties, 'unset' means the same as 'inherit'.
michael@0 1921 inherited += unset;
michael@0 1922 unset = 0;
michael@0 1923 }
michael@0 1924
michael@0 1925 #if 0
michael@0 1926 printf("CheckSpecifiedProperties: SID=%d total=%d spec=%d inh=%d.\n",
michael@0 1927 aSID, total, specified, inherited);
michael@0 1928 #endif
michael@0 1929
michael@0 1930 NS_ASSERTION(aSID != eStyleStruct_Font ||
michael@0 1931 mPresContext->Document()->GetMathMLEnabled() ||
michael@0 1932 AreAllMathMLPropertiesUndefined(aRuleData),
michael@0 1933 "MathML style property was defined even though MathML is disabled");
michael@0 1934
michael@0 1935 /*
michael@0 1936 * Return the most specific information we can: prefer None or Full
michael@0 1937 * over Partial, and Reset or Inherited over Mixed, since we can
michael@0 1938 * optimize based on the edge cases and not the in-between cases.
michael@0 1939 */
michael@0 1940 nsRuleNode::RuleDetail result;
michael@0 1941 if (inherited == total)
michael@0 1942 result = eRuleFullInherited;
michael@0 1943 else if (specified == total
michael@0 1944 // MathML defines 5 properties in Font that will never be set when
michael@0 1945 // MathML is not in use. Therefore if all but five
michael@0 1946 // properties have been set, and MathML is not enabled, we can treat
michael@0 1947 // this as fully specified. Code in nsMathMLElementFactory will
michael@0 1948 // rebuild the rule tree and style data when MathML is first enabled
michael@0 1949 // (see nsMathMLElement::BindToTree).
michael@0 1950 || (aSID == eStyleStruct_Font && specified + 5 == total &&
michael@0 1951 !mPresContext->Document()->GetMathMLEnabled())
michael@0 1952 ) {
michael@0 1953 if (inherited == 0)
michael@0 1954 result = eRuleFullReset;
michael@0 1955 else
michael@0 1956 result = eRuleFullMixed;
michael@0 1957 } else if (specified == 0)
michael@0 1958 result = eRuleNone;
michael@0 1959 else if (specified == inherited)
michael@0 1960 result = eRulePartialInherited;
michael@0 1961 else if (inherited == 0)
michael@0 1962 result = eRulePartialReset;
michael@0 1963 else
michael@0 1964 result = eRulePartialMixed;
michael@0 1965
michael@0 1966 CheckCallbackFn cb = gCheckCallbacks[aSID];
michael@0 1967 if (cb) {
michael@0 1968 result = (*cb)(aRuleData, result);
michael@0 1969 }
michael@0 1970
michael@0 1971 return result;
michael@0 1972 }
michael@0 1973
michael@0 1974 // If we need to restrict which properties apply to the style context,
michael@0 1975 // return the bit to check in nsCSSProp's flags table. Otherwise,
michael@0 1976 // return 0.
michael@0 1977 inline uint32_t
michael@0 1978 GetPseudoRestriction(nsStyleContext *aContext)
michael@0 1979 {
michael@0 1980 // This needs to match nsStyleSet::WalkRestrictionRule.
michael@0 1981 uint32_t pseudoRestriction = 0;
michael@0 1982 nsIAtom *pseudoType = aContext->GetPseudo();
michael@0 1983 if (pseudoType) {
michael@0 1984 if (pseudoType == nsCSSPseudoElements::firstLetter) {
michael@0 1985 pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LETTER;
michael@0 1986 } else if (pseudoType == nsCSSPseudoElements::firstLine) {
michael@0 1987 pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LINE;
michael@0 1988 } else if (pseudoType == nsCSSPseudoElements::mozPlaceholder) {
michael@0 1989 pseudoRestriction = CSS_PROPERTY_APPLIES_TO_PLACEHOLDER;
michael@0 1990 }
michael@0 1991 }
michael@0 1992 return pseudoRestriction;
michael@0 1993 }
michael@0 1994
michael@0 1995 static void
michael@0 1996 UnsetPropertiesWithoutFlags(const nsStyleStructID aSID,
michael@0 1997 nsRuleData* aRuleData,
michael@0 1998 uint32_t aFlags)
michael@0 1999 {
michael@0 2000 NS_ASSERTION(aFlags != 0, "aFlags must be nonzero");
michael@0 2001
michael@0 2002 const uint32_t *flagData = gFlagsByStruct[aSID];
michael@0 2003
michael@0 2004 // See comment in nsRuleData.h above mValueOffsets.
michael@0 2005 NS_ABORT_IF_FALSE(aRuleData->mValueOffsets[aSID] == 0,
michael@0 2006 "we assume the value offset is zero instead of adding it");
michael@0 2007 nsCSSValue *values = aRuleData->mValueStorage;
michael@0 2008
michael@0 2009 for (size_t i = 0, i_end = nsCSSProps::PropertyCountInStruct(aSID);
michael@0 2010 i != i_end; ++i) {
michael@0 2011 if ((flagData[i] & aFlags) != aFlags)
michael@0 2012 values[i].Reset();
michael@0 2013 }
michael@0 2014 }
michael@0 2015
michael@0 2016 /**
michael@0 2017 * We allocate arrays of CSS values with alloca. (These arrays are a
michael@0 2018 * fixed size per style struct, but we don't want to waste the
michael@0 2019 * allocation and construction/destruction costs of the big structs when
michael@0 2020 * we're handling much smaller ones.) Since the lifetime of an alloca
michael@0 2021 * allocation is the life of the calling function, the caller must call
michael@0 2022 * alloca. However, to ensure that constructors and destructors are
michael@0 2023 * balanced, we do the constructor and destructor calling from this RAII
michael@0 2024 * class, AutoCSSValueArray.
michael@0 2025 */
michael@0 2026 struct AutoCSSValueArray {
michael@0 2027 /**
michael@0 2028 * aStorage must be the result of alloca(aCount * sizeof(nsCSSValue))
michael@0 2029 */
michael@0 2030 AutoCSSValueArray(void* aStorage, size_t aCount) {
michael@0 2031 NS_ABORT_IF_FALSE(size_t(aStorage) % NS_ALIGNMENT_OF(nsCSSValue) == 0,
michael@0 2032 "bad alignment from alloca");
michael@0 2033 mCount = aCount;
michael@0 2034 // Don't use placement new[], since it might store extra data
michael@0 2035 // for the count (on Windows!).
michael@0 2036 mArray = static_cast<nsCSSValue*>(aStorage);
michael@0 2037 for (size_t i = 0; i < mCount; ++i) {
michael@0 2038 new (mArray + i) nsCSSValue();
michael@0 2039 }
michael@0 2040 }
michael@0 2041
michael@0 2042 ~AutoCSSValueArray() {
michael@0 2043 for (size_t i = 0; i < mCount; ++i) {
michael@0 2044 mArray[i].~nsCSSValue();
michael@0 2045 }
michael@0 2046 }
michael@0 2047
michael@0 2048 nsCSSValue* get() { return mArray; }
michael@0 2049
michael@0 2050 private:
michael@0 2051 nsCSSValue *mArray;
michael@0 2052 size_t mCount;
michael@0 2053 };
michael@0 2054
michael@0 2055 /* static */ bool
michael@0 2056 nsRuleNode::ResolveVariableReferences(const nsStyleStructID aSID,
michael@0 2057 nsRuleData* aRuleData,
michael@0 2058 nsStyleContext* aContext)
michael@0 2059 {
michael@0 2060 MOZ_ASSERT(aSID != eStyleStruct_Variables);
michael@0 2061 MOZ_ASSERT(aRuleData->mSIDs & nsCachedStyleData::GetBitForSID(aSID));
michael@0 2062 MOZ_ASSERT(aRuleData->mValueOffsets[aSID] == 0);
michael@0 2063
michael@0 2064 nsCSSParser parser;
michael@0 2065 bool anyTokenStreams = false;
michael@0 2066
michael@0 2067 // Look at each property in the nsRuleData for the given style struct.
michael@0 2068 size_t nprops = nsCSSProps::PropertyCountInStruct(aSID);
michael@0 2069 for (nsCSSValue* value = aRuleData->mValueStorage,
michael@0 2070 *values_end = aRuleData->mValueStorage + nprops;
michael@0 2071 value != values_end; value++) {
michael@0 2072 if (value->GetUnit() != eCSSUnit_TokenStream) {
michael@0 2073 continue;
michael@0 2074 }
michael@0 2075
michael@0 2076 const CSSVariableValues* variables =
michael@0 2077 &aContext->StyleVariables()->mVariables;
michael@0 2078 nsCSSValueTokenStream* tokenStream = value->GetTokenStreamValue();
michael@0 2079
michael@0 2080 // Note that ParsePropertyWithVariableReferences relies on the fact
michael@0 2081 // that the nsCSSValue in aRuleData for the property we are re-parsing
michael@0 2082 // is still the token stream value. When
michael@0 2083 // ParsePropertyWithVariableReferences calls
michael@0 2084 // nsCSSExpandedDataBlock::MapRuleInfoInto, that function will add
michael@0 2085 // the ImageValue that is created into the token stream object's
michael@0 2086 // mImageValues table; see the comment above mImageValues for why.
michael@0 2087
michael@0 2088 // XXX Should pass in sheet here (see bug 952338).
michael@0 2089 parser.ParsePropertyWithVariableReferences(
michael@0 2090 tokenStream->mPropertyID, tokenStream->mShorthandPropertyID,
michael@0 2091 tokenStream->mTokenStream, variables, aRuleData,
michael@0 2092 tokenStream->mSheetURI, tokenStream->mBaseURI,
michael@0 2093 tokenStream->mSheetPrincipal, nullptr,
michael@0 2094 tokenStream->mLineNumber, tokenStream->mLineOffset);
michael@0 2095 aRuleData->mCanStoreInRuleTree = false;
michael@0 2096 anyTokenStreams = true;
michael@0 2097 }
michael@0 2098
michael@0 2099 return anyTokenStreams;
michael@0 2100 }
michael@0 2101
michael@0 2102 const void*
michael@0 2103 nsRuleNode::WalkRuleTree(const nsStyleStructID aSID,
michael@0 2104 nsStyleContext* aContext)
michael@0 2105 {
michael@0 2106 // use placement new[] on the result of alloca() to allocate a
michael@0 2107 // variable-sized stack array, including execution of constructors,
michael@0 2108 // and use an RAII class to run the destructors too.
michael@0 2109 size_t nprops = nsCSSProps::PropertyCountInStruct(aSID);
michael@0 2110 void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
michael@0 2111 AutoCSSValueArray dataArray(dataStorage, nprops);
michael@0 2112
michael@0 2113 nsRuleData ruleData(nsCachedStyleData::GetBitForSID(aSID),
michael@0 2114 dataArray.get(), mPresContext, aContext);
michael@0 2115 ruleData.mValueOffsets[aSID] = 0;
michael@0 2116
michael@0 2117 // We start at the most specific rule in the tree.
michael@0 2118 void* startStruct = nullptr;
michael@0 2119
michael@0 2120 nsRuleNode* ruleNode = this;
michael@0 2121 nsRuleNode* highestNode = nullptr; // The highest node in the rule tree
michael@0 2122 // that has the same properties
michael@0 2123 // specified for struct |aSID| as
michael@0 2124 // |this| does.
michael@0 2125 nsRuleNode* rootNode = this; // After the loop below, this will be the
michael@0 2126 // highest node that we've walked without
michael@0 2127 // finding cached data on the rule tree.
michael@0 2128 // If we don't find any cached data, it
michael@0 2129 // will be the root. (XXX misnamed)
michael@0 2130 RuleDetail detail = eRuleNone;
michael@0 2131 uint32_t bit = nsCachedStyleData::GetBitForSID(aSID);
michael@0 2132
michael@0 2133 while (ruleNode) {
michael@0 2134 // See if this rule node has cached the fact that the remaining
michael@0 2135 // nodes along this path specify no data whatsoever.
michael@0 2136 if (ruleNode->mNoneBits & bit)
michael@0 2137 break;
michael@0 2138
michael@0 2139 // If the dependent bit is set on a rule node for this struct, that
michael@0 2140 // means its rule won't have any information to add, so skip it.
michael@0 2141 // NOTE: If we exit the loop because of the !IsUsedDirectly() check,
michael@0 2142 // then we're guaranteed to break immediately afterwards due to a
michael@0 2143 // non-null startStruct.
michael@0 2144 while ((ruleNode->mDependentBits & bit) && !ruleNode->IsUsedDirectly()) {
michael@0 2145 NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nullptr,
michael@0 2146 "dependent bit with cached data makes no sense");
michael@0 2147 // Climb up to the next rule in the tree (a less specific rule).
michael@0 2148 rootNode = ruleNode;
michael@0 2149 ruleNode = ruleNode->mParent;
michael@0 2150 NS_ASSERTION(!(ruleNode->mNoneBits & bit), "can't have both bits set");
michael@0 2151 }
michael@0 2152
michael@0 2153 // Check for cached data after the inner loop above -- otherwise
michael@0 2154 // we'll miss it.
michael@0 2155 startStruct = ruleNode->mStyleData.GetStyleData(aSID);
michael@0 2156 if (startStruct)
michael@0 2157 break; // We found a rule with fully specified data. We don't
michael@0 2158 // need to go up the tree any further, since the remainder
michael@0 2159 // of this branch has already been computed.
michael@0 2160
michael@0 2161 // Ask the rule to fill in the properties that it specifies.
michael@0 2162 nsIStyleRule *rule = ruleNode->mRule;
michael@0 2163 if (rule) {
michael@0 2164 ruleData.mLevel = ruleNode->GetLevel();
michael@0 2165 ruleData.mIsImportantRule = ruleNode->IsImportantRule();
michael@0 2166 rule->MapRuleInfoInto(&ruleData);
michael@0 2167 }
michael@0 2168
michael@0 2169 // Now we check to see how many properties have been specified by
michael@0 2170 // the rules we've examined so far.
michael@0 2171 RuleDetail oldDetail = detail;
michael@0 2172 detail = CheckSpecifiedProperties(aSID, &ruleData);
michael@0 2173
michael@0 2174 if (oldDetail == eRuleNone && detail != eRuleNone)
michael@0 2175 highestNode = ruleNode;
michael@0 2176
michael@0 2177 if (detail == eRuleFullReset ||
michael@0 2178 detail == eRuleFullMixed ||
michael@0 2179 detail == eRuleFullInherited)
michael@0 2180 break; // We don't need to examine any more rules. All properties
michael@0 2181 // have been fully specified.
michael@0 2182
michael@0 2183 // Climb up to the next rule in the tree (a less specific rule).
michael@0 2184 rootNode = ruleNode;
michael@0 2185 ruleNode = ruleNode->mParent;
michael@0 2186 }
michael@0 2187
michael@0 2188 bool recomputeDetail = false;
michael@0 2189
michael@0 2190 // If we are computing a style struct other than nsStyleVariables, and
michael@0 2191 // ruleData has any properties with variable references (nsCSSValues of
michael@0 2192 // type eCSSUnit_TokenStream), then we need to resolve these.
michael@0 2193 if (aSID != eStyleStruct_Variables) {
michael@0 2194 // A property's value might have became 'inherit' after resolving
michael@0 2195 // variable references. (This happens when an inherited property
michael@0 2196 // fails to parse its resolved value.) We need to recompute
michael@0 2197 // |detail| in case this happened.
michael@0 2198 recomputeDetail = ResolveVariableReferences(aSID, &ruleData, aContext);
michael@0 2199 }
michael@0 2200
michael@0 2201 // If needed, unset the properties that don't have a flag that allows
michael@0 2202 // them to be set for this style context. (For example, only some
michael@0 2203 // properties apply to :first-line and :first-letter.)
michael@0 2204 uint32_t pseudoRestriction = GetPseudoRestriction(aContext);
michael@0 2205 if (pseudoRestriction) {
michael@0 2206 UnsetPropertiesWithoutFlags(aSID, &ruleData, pseudoRestriction);
michael@0 2207
michael@0 2208 // We need to recompute |detail| based on the restrictions we just applied.
michael@0 2209 // We can adjust |detail| arbitrarily because of the restriction
michael@0 2210 // rule added in nsStyleSet::WalkRestrictionRule.
michael@0 2211 recomputeDetail = true;
michael@0 2212 }
michael@0 2213
michael@0 2214 if (recomputeDetail) {
michael@0 2215 detail = CheckSpecifiedProperties(aSID, &ruleData);
michael@0 2216 }
michael@0 2217
michael@0 2218 NS_ASSERTION(!startStruct || (detail != eRuleFullReset &&
michael@0 2219 detail != eRuleFullMixed &&
michael@0 2220 detail != eRuleFullInherited),
michael@0 2221 "can't have start struct and be fully specified");
michael@0 2222
michael@0 2223 bool isReset = nsCachedStyleData::IsReset(aSID);
michael@0 2224 if (!highestNode)
michael@0 2225 highestNode = rootNode;
michael@0 2226
michael@0 2227 if (!ruleData.mCanStoreInRuleTree)
michael@0 2228 detail = eRulePartialMixed; // Treat as though some data is specified to avoid
michael@0 2229 // the optimizations and force data computation.
michael@0 2230
michael@0 2231 if (detail == eRuleNone && startStruct) {
michael@0 2232 // We specified absolutely no rule information, but a parent rule in the tree
michael@0 2233 // specified all the rule information. We set a bit along the branch from our
michael@0 2234 // node in the tree to the node that specified the data that tells nodes on that
michael@0 2235 // branch that they never need to examine their rules for this particular struct type
michael@0 2236 // ever again.
michael@0 2237 PropagateDependentBit(aSID, ruleNode, startStruct);
michael@0 2238 return startStruct;
michael@0 2239 }
michael@0 2240 if ((!startStruct && !isReset &&
michael@0 2241 (detail == eRuleNone || detail == eRulePartialInherited)) ||
michael@0 2242 detail == eRuleFullInherited) {
michael@0 2243 // We specified no non-inherited information and neither did any of
michael@0 2244 // our parent rules.
michael@0 2245
michael@0 2246 // We set a bit along the branch from the highest node (ruleNode)
michael@0 2247 // down to our node (this) indicating that no non-inherited data was
michael@0 2248 // specified. This bit is guaranteed to be set already on the path
michael@0 2249 // from the highest node to the root node in the case where
michael@0 2250 // (detail == eRuleNone), which is the most common case here.
michael@0 2251 // We must check |!isReset| because the Compute*Data functions for
michael@0 2252 // reset structs wouldn't handle none bits correctly.
michael@0 2253 if (highestNode != this && !isReset)
michael@0 2254 PropagateNoneBit(bit, highestNode);
michael@0 2255
michael@0 2256 // All information must necessarily be inherited from our parent style context.
michael@0 2257 // In the absence of any computed data in the rule tree and with
michael@0 2258 // no rules specified that didn't have values of 'inherit', we should check our parent.
michael@0 2259 nsStyleContext* parentContext = aContext->GetParent();
michael@0 2260 if (isReset) {
michael@0 2261 /* Reset structs don't inherit from first-line. */
michael@0 2262 /* See similar code in COMPUTE_START_RESET */
michael@0 2263 while (parentContext &&
michael@0 2264 parentContext->GetPseudo() == nsCSSPseudoElements::firstLine) {
michael@0 2265 parentContext = parentContext->GetParent();
michael@0 2266 }
michael@0 2267 }
michael@0 2268 if (parentContext) {
michael@0 2269 // We have a parent, and so we should just inherit from the parent.
michael@0 2270 // Set the inherit bits on our context. These bits tell the style context that
michael@0 2271 // it never has to go back to the rule tree for data. Instead the style context tree
michael@0 2272 // should be walked to find the data.
michael@0 2273 const void* parentStruct = parentContext->StyleData(aSID);
michael@0 2274 aContext->AddStyleBit(bit); // makes const_cast OK.
michael@0 2275 aContext->SetStyle(aSID, const_cast<void*>(parentStruct));
michael@0 2276 return parentStruct;
michael@0 2277 }
michael@0 2278 else
michael@0 2279 // We are the root. In the case of fonts, the default values just
michael@0 2280 // come from the pres context.
michael@0 2281 return SetDefaultOnRoot(aSID, aContext);
michael@0 2282 }
michael@0 2283
michael@0 2284 // We need to compute the data from the information that the rules specified.
michael@0 2285 const void* res;
michael@0 2286 #define STYLE_STRUCT_TEST aSID
michael@0 2287 #define STYLE_STRUCT(name, checkdata_cb) \
michael@0 2288 res = Compute##name##Data(startStruct, &ruleData, aContext, \
michael@0 2289 highestNode, detail, ruleData.mCanStoreInRuleTree);
michael@0 2290 #include "nsStyleStructList.h"
michael@0 2291 #undef STYLE_STRUCT
michael@0 2292 #undef STYLE_STRUCT_TEST
michael@0 2293
michael@0 2294 // Now return the result.
michael@0 2295 return res;
michael@0 2296 }
michael@0 2297
michael@0 2298 const void*
michael@0 2299 nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContext)
michael@0 2300 {
michael@0 2301 switch (aSID) {
michael@0 2302 case eStyleStruct_Font:
michael@0 2303 {
michael@0 2304 nsStyleFont* fontData = new (mPresContext) nsStyleFont(mPresContext);
michael@0 2305 nscoord minimumFontSize = mPresContext->MinFontSize(fontData->mLanguage);
michael@0 2306
michael@0 2307 if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
michael@0 2308 fontData->mFont.size = std::max(fontData->mSize, minimumFontSize);
michael@0 2309 }
michael@0 2310 else {
michael@0 2311 fontData->mFont.size = fontData->mSize;
michael@0 2312 }
michael@0 2313 aContext->SetStyle(eStyleStruct_Font, fontData);
michael@0 2314 return fontData;
michael@0 2315 }
michael@0 2316 case eStyleStruct_Display:
michael@0 2317 {
michael@0 2318 nsStyleDisplay* disp = new (mPresContext) nsStyleDisplay();
michael@0 2319 aContext->SetStyle(eStyleStruct_Display, disp);
michael@0 2320 return disp;
michael@0 2321 }
michael@0 2322 case eStyleStruct_Visibility:
michael@0 2323 {
michael@0 2324 nsStyleVisibility* vis = new (mPresContext) nsStyleVisibility(mPresContext);
michael@0 2325 aContext->SetStyle(eStyleStruct_Visibility, vis);
michael@0 2326 return vis;
michael@0 2327 }
michael@0 2328 case eStyleStruct_Text:
michael@0 2329 {
michael@0 2330 nsStyleText* text = new (mPresContext) nsStyleText();
michael@0 2331 aContext->SetStyle(eStyleStruct_Text, text);
michael@0 2332 return text;
michael@0 2333 }
michael@0 2334 case eStyleStruct_TextReset:
michael@0 2335 {
michael@0 2336 nsStyleTextReset* text = new (mPresContext) nsStyleTextReset();
michael@0 2337 aContext->SetStyle(eStyleStruct_TextReset, text);
michael@0 2338 return text;
michael@0 2339 }
michael@0 2340 case eStyleStruct_Color:
michael@0 2341 {
michael@0 2342 nsStyleColor* color = new (mPresContext) nsStyleColor(mPresContext);
michael@0 2343 aContext->SetStyle(eStyleStruct_Color, color);
michael@0 2344 return color;
michael@0 2345 }
michael@0 2346 case eStyleStruct_Background:
michael@0 2347 {
michael@0 2348 nsStyleBackground* bg = new (mPresContext) nsStyleBackground();
michael@0 2349 aContext->SetStyle(eStyleStruct_Background, bg);
michael@0 2350 return bg;
michael@0 2351 }
michael@0 2352 case eStyleStruct_Margin:
michael@0 2353 {
michael@0 2354 nsStyleMargin* margin = new (mPresContext) nsStyleMargin();
michael@0 2355 aContext->SetStyle(eStyleStruct_Margin, margin);
michael@0 2356 return margin;
michael@0 2357 }
michael@0 2358 case eStyleStruct_Border:
michael@0 2359 {
michael@0 2360 nsStyleBorder* border = new (mPresContext) nsStyleBorder(mPresContext);
michael@0 2361 aContext->SetStyle(eStyleStruct_Border, border);
michael@0 2362 return border;
michael@0 2363 }
michael@0 2364 case eStyleStruct_Padding:
michael@0 2365 {
michael@0 2366 nsStylePadding* padding = new (mPresContext) nsStylePadding();
michael@0 2367 aContext->SetStyle(eStyleStruct_Padding, padding);
michael@0 2368 return padding;
michael@0 2369 }
michael@0 2370 case eStyleStruct_Outline:
michael@0 2371 {
michael@0 2372 nsStyleOutline* outline = new (mPresContext) nsStyleOutline(mPresContext);
michael@0 2373 aContext->SetStyle(eStyleStruct_Outline, outline);
michael@0 2374 return outline;
michael@0 2375 }
michael@0 2376 case eStyleStruct_List:
michael@0 2377 {
michael@0 2378 nsStyleList* list = new (mPresContext) nsStyleList();
michael@0 2379 aContext->SetStyle(eStyleStruct_List, list);
michael@0 2380 return list;
michael@0 2381 }
michael@0 2382 case eStyleStruct_Position:
michael@0 2383 {
michael@0 2384 nsStylePosition* pos = new (mPresContext) nsStylePosition();
michael@0 2385 aContext->SetStyle(eStyleStruct_Position, pos);
michael@0 2386 return pos;
michael@0 2387 }
michael@0 2388 case eStyleStruct_Table:
michael@0 2389 {
michael@0 2390 nsStyleTable* table = new (mPresContext) nsStyleTable();
michael@0 2391 aContext->SetStyle(eStyleStruct_Table, table);
michael@0 2392 return table;
michael@0 2393 }
michael@0 2394 case eStyleStruct_TableBorder:
michael@0 2395 {
michael@0 2396 nsStyleTableBorder* table = new (mPresContext) nsStyleTableBorder(mPresContext);
michael@0 2397 aContext->SetStyle(eStyleStruct_TableBorder, table);
michael@0 2398 return table;
michael@0 2399 }
michael@0 2400 case eStyleStruct_Content:
michael@0 2401 {
michael@0 2402 nsStyleContent* content = new (mPresContext) nsStyleContent();
michael@0 2403 aContext->SetStyle(eStyleStruct_Content, content);
michael@0 2404 return content;
michael@0 2405 }
michael@0 2406 case eStyleStruct_Quotes:
michael@0 2407 {
michael@0 2408 nsStyleQuotes* quotes = new (mPresContext) nsStyleQuotes();
michael@0 2409 aContext->SetStyle(eStyleStruct_Quotes, quotes);
michael@0 2410 return quotes;
michael@0 2411 }
michael@0 2412 case eStyleStruct_UserInterface:
michael@0 2413 {
michael@0 2414 nsStyleUserInterface* ui = new (mPresContext) nsStyleUserInterface();
michael@0 2415 aContext->SetStyle(eStyleStruct_UserInterface, ui);
michael@0 2416 return ui;
michael@0 2417 }
michael@0 2418 case eStyleStruct_UIReset:
michael@0 2419 {
michael@0 2420 nsStyleUIReset* ui = new (mPresContext) nsStyleUIReset();
michael@0 2421 aContext->SetStyle(eStyleStruct_UIReset, ui);
michael@0 2422 return ui;
michael@0 2423 }
michael@0 2424 case eStyleStruct_XUL:
michael@0 2425 {
michael@0 2426 nsStyleXUL* xul = new (mPresContext) nsStyleXUL();
michael@0 2427 aContext->SetStyle(eStyleStruct_XUL, xul);
michael@0 2428 return xul;
michael@0 2429 }
michael@0 2430 case eStyleStruct_Column:
michael@0 2431 {
michael@0 2432 nsStyleColumn* column = new (mPresContext) nsStyleColumn(mPresContext);
michael@0 2433 aContext->SetStyle(eStyleStruct_Column, column);
michael@0 2434 return column;
michael@0 2435 }
michael@0 2436 case eStyleStruct_SVG:
michael@0 2437 {
michael@0 2438 nsStyleSVG* svg = new (mPresContext) nsStyleSVG();
michael@0 2439 aContext->SetStyle(eStyleStruct_SVG, svg);
michael@0 2440 return svg;
michael@0 2441 }
michael@0 2442 case eStyleStruct_SVGReset:
michael@0 2443 {
michael@0 2444 nsStyleSVGReset* svgReset = new (mPresContext) nsStyleSVGReset();
michael@0 2445 aContext->SetStyle(eStyleStruct_SVGReset, svgReset);
michael@0 2446 return svgReset;
michael@0 2447 }
michael@0 2448 case eStyleStruct_Variables:
michael@0 2449 {
michael@0 2450 nsStyleVariables* vars = new (mPresContext) nsStyleVariables();
michael@0 2451 aContext->SetStyle(eStyleStruct_Variables, vars);
michael@0 2452 return vars;
michael@0 2453 }
michael@0 2454 default:
michael@0 2455 /*
michael@0 2456 * unhandled case: nsStyleStructID_Length.
michael@0 2457 * last item of nsStyleStructID, to know its length.
michael@0 2458 */
michael@0 2459 NS_ABORT_IF_FALSE(false, "unexpected SID");
michael@0 2460 return nullptr;
michael@0 2461 }
michael@0 2462 return nullptr;
michael@0 2463 }
michael@0 2464
michael@0 2465 /*
michael@0 2466 * This function handles cascading of *-left or *-right box properties
michael@0 2467 * against *-start (which is L for LTR and R for RTL) or *-end (which is
michael@0 2468 * R for LTR and L for RTL).
michael@0 2469 *
michael@0 2470 * Cascading these properties correctly is hard because we need to
michael@0 2471 * cascade two properties as one, but which two properties depends on a
michael@0 2472 * third property ('direction'). We solve this by treating each of
michael@0 2473 * these properties (say, 'margin-start') as a shorthand that sets a
michael@0 2474 * property containing the value of the property specified
michael@0 2475 * ('margin-start-value') and sets a pair of properties
michael@0 2476 * ('margin-left-ltr-source' and 'margin-right-rtl-source') saying which
michael@0 2477 * of the properties we use. Thus, when we want to compute the value of
michael@0 2478 * 'margin-left' when 'direction' is 'ltr', we look at the value of
michael@0 2479 * 'margin-left-ltr-source', which tells us whether to use the highest
michael@0 2480 * 'margin-left' in the cascade or the highest 'margin-start'.
michael@0 2481 *
michael@0 2482 * Finally, since we can compute the normal (*-left and *-right)
michael@0 2483 * properties in a loop, this function works by modifying the data we
michael@0 2484 * will use in that loop (which the caller must copy from the const
michael@0 2485 * input).
michael@0 2486 */
michael@0 2487 void
michael@0 2488 nsRuleNode::AdjustLogicalBoxProp(nsStyleContext* aContext,
michael@0 2489 const nsCSSValue& aLTRSource,
michael@0 2490 const nsCSSValue& aRTLSource,
michael@0 2491 const nsCSSValue& aLTRLogicalValue,
michael@0 2492 const nsCSSValue& aRTLLogicalValue,
michael@0 2493 mozilla::css::Side aSide,
michael@0 2494 nsCSSRect& aValueRect,
michael@0 2495 bool& aCanStoreInRuleTree)
michael@0 2496 {
michael@0 2497 bool LTRlogical = aLTRSource.GetUnit() == eCSSUnit_Enumerated &&
michael@0 2498 aLTRSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
michael@0 2499 bool RTLlogical = aRTLSource.GetUnit() == eCSSUnit_Enumerated &&
michael@0 2500 aRTLSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
michael@0 2501 if (LTRlogical || RTLlogical) {
michael@0 2502 // We can't cache anything on the rule tree if we use any data from
michael@0 2503 // the style context, since data cached in the rule tree could be
michael@0 2504 // used with a style context with a different value.
michael@0 2505 aCanStoreInRuleTree = false;
michael@0 2506 uint8_t dir = aContext->StyleVisibility()->mDirection;
michael@0 2507
michael@0 2508 if (dir == NS_STYLE_DIRECTION_LTR) {
michael@0 2509 if (LTRlogical)
michael@0 2510 aValueRect.*(nsCSSRect::sides[aSide]) = aLTRLogicalValue;
michael@0 2511 } else {
michael@0 2512 if (RTLlogical)
michael@0 2513 aValueRect.*(nsCSSRect::sides[aSide]) = aRTLLogicalValue;
michael@0 2514 }
michael@0 2515 } else if (aLTRLogicalValue.GetUnit() == eCSSUnit_Inherit ||
michael@0 2516 aRTLLogicalValue.GetUnit() == eCSSUnit_Inherit) {
michael@0 2517 // It actually is valid to store this in the ruletree, since
michael@0 2518 // LTRlogical and RTLlogical are both false, but doing that will
michael@0 2519 // trigger asserts. Silence those.
michael@0 2520 aCanStoreInRuleTree = false;
michael@0 2521 }
michael@0 2522 }
michael@0 2523
michael@0 2524 /**
michael@0 2525 * Begin an nsRuleNode::Compute*Data function for an inherited struct.
michael@0 2526 *
michael@0 2527 * @param type_ The nsStyle* type this function computes.
michael@0 2528 * @param ctorargs_ The arguments used for the default nsStyle* constructor.
michael@0 2529 * @param data_ Variable (declared here) holding the result of this
michael@0 2530 * function.
michael@0 2531 * @param parentdata_ Variable (declared here) holding the parent style
michael@0 2532 * context's data for this struct.
michael@0 2533 */
michael@0 2534 #define COMPUTE_START_INHERITED(type_, ctorargs_, data_, parentdata_) \
michael@0 2535 NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
michael@0 2536 "should not have bothered calling Compute*Data"); \
michael@0 2537 \
michael@0 2538 nsStyleContext* parentContext = aContext->GetParent(); \
michael@0 2539 \
michael@0 2540 nsStyle##type_* data_ = nullptr; \
michael@0 2541 mozilla::Maybe<nsStyle##type_> maybeFakeParentData; \
michael@0 2542 const nsStyle##type_* parentdata_ = nullptr; \
michael@0 2543 bool canStoreInRuleTree = aCanStoreInRuleTree; \
michael@0 2544 \
michael@0 2545 /* If |canStoreInRuleTree| might be true by the time we're done, we */ \
michael@0 2546 /* can't call parentContext->Style##type_() since it could recur into */ \
michael@0 2547 /* setting the same struct on the same rule node, causing a leak. */ \
michael@0 2548 if (aRuleDetail != eRuleFullReset && \
michael@0 2549 (!aStartStruct || (aRuleDetail != eRulePartialReset && \
michael@0 2550 aRuleDetail != eRuleNone))) { \
michael@0 2551 if (parentContext) { \
michael@0 2552 parentdata_ = parentContext->Style##type_(); \
michael@0 2553 } else { \
michael@0 2554 maybeFakeParentData.construct ctorargs_; \
michael@0 2555 parentdata_ = maybeFakeParentData.addr(); \
michael@0 2556 } \
michael@0 2557 } \
michael@0 2558 if (aStartStruct) \
michael@0 2559 /* We only need to compute the delta between this computed data and */ \
michael@0 2560 /* our computed data. */ \
michael@0 2561 data_ = new (mPresContext) \
michael@0 2562 nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
michael@0 2563 else { \
michael@0 2564 if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) { \
michael@0 2565 /* No question. We will have to inherit. Go ahead and init */ \
michael@0 2566 /* with inherited vals from parent. */ \
michael@0 2567 canStoreInRuleTree = false; \
michael@0 2568 if (parentdata_) \
michael@0 2569 data_ = new (mPresContext) nsStyle##type_(*parentdata_); \
michael@0 2570 else \
michael@0 2571 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
michael@0 2572 } \
michael@0 2573 else \
michael@0 2574 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
michael@0 2575 } \
michael@0 2576 \
michael@0 2577 if (!parentdata_) \
michael@0 2578 parentdata_ = data_;
michael@0 2579
michael@0 2580 /**
michael@0 2581 * Begin an nsRuleNode::Compute*Data function for a reset struct.
michael@0 2582 *
michael@0 2583 * @param type_ The nsStyle* type this function computes.
michael@0 2584 * @param ctorargs_ The arguments used for the default nsStyle* constructor.
michael@0 2585 * @param data_ Variable (declared here) holding the result of this
michael@0 2586 * function.
michael@0 2587 * @param parentdata_ Variable (declared here) holding the parent style
michael@0 2588 * context's data for this struct.
michael@0 2589 */
michael@0 2590 #define COMPUTE_START_RESET(type_, ctorargs_, data_, parentdata_) \
michael@0 2591 NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
michael@0 2592 "should not have bothered calling Compute*Data"); \
michael@0 2593 \
michael@0 2594 nsStyleContext* parentContext = aContext->GetParent(); \
michael@0 2595 /* Reset structs don't inherit from first-line */ \
michael@0 2596 /* See similar code in WalkRuleTree */ \
michael@0 2597 while (parentContext && \
michael@0 2598 parentContext->GetPseudo() == nsCSSPseudoElements::firstLine) { \
michael@0 2599 parentContext = parentContext->GetParent(); \
michael@0 2600 } \
michael@0 2601 \
michael@0 2602 nsStyle##type_* data_; \
michael@0 2603 if (aStartStruct) \
michael@0 2604 /* We only need to compute the delta between this computed data and */ \
michael@0 2605 /* our computed data. */ \
michael@0 2606 data_ = new (mPresContext) \
michael@0 2607 nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
michael@0 2608 else \
michael@0 2609 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
michael@0 2610 \
michael@0 2611 /* If |canStoreInRuleTree| might be true by the time we're done, we */ \
michael@0 2612 /* can't call parentContext->Style##type_() since it could recur into */ \
michael@0 2613 /* setting the same struct on the same rule node, causing a leak. */ \
michael@0 2614 mozilla::Maybe<nsStyle##type_> maybeFakeParentData; \
michael@0 2615 const nsStyle##type_* parentdata_ = data_; \
michael@0 2616 if (aRuleDetail != eRuleFullReset && \
michael@0 2617 aRuleDetail != eRulePartialReset && \
michael@0 2618 aRuleDetail != eRuleNone) { \
michael@0 2619 if (parentContext) { \
michael@0 2620 parentdata_ = parentContext->Style##type_(); \
michael@0 2621 } else { \
michael@0 2622 maybeFakeParentData.construct ctorargs_; \
michael@0 2623 parentdata_ = maybeFakeParentData.addr(); \
michael@0 2624 } \
michael@0 2625 } \
michael@0 2626 bool canStoreInRuleTree = aCanStoreInRuleTree;
michael@0 2627
michael@0 2628 /**
michael@0 2629 * End an nsRuleNode::Compute*Data function for an inherited struct.
michael@0 2630 *
michael@0 2631 * @param type_ The nsStyle* type this function computes.
michael@0 2632 * @param data_ Variable holding the result of this function.
michael@0 2633 */
michael@0 2634 #define COMPUTE_END_INHERITED(type_, data_) \
michael@0 2635 NS_POSTCONDITION(!canStoreInRuleTree || aRuleDetail == eRuleFullReset || \
michael@0 2636 (aStartStruct && aRuleDetail == eRulePartialReset), \
michael@0 2637 "canStoreInRuleTree must be false for inherited structs " \
michael@0 2638 "unless all properties have been specified with values " \
michael@0 2639 "other than inherit"); \
michael@0 2640 if (canStoreInRuleTree) { \
michael@0 2641 /* We were fully specified and can therefore be cached right on the */ \
michael@0 2642 /* rule node. */ \
michael@0 2643 if (!aHighestNode->mStyleData.mInheritedData) { \
michael@0 2644 aHighestNode->mStyleData.mInheritedData = \
michael@0 2645 new (mPresContext) nsInheritedStyleData; \
michael@0 2646 } \
michael@0 2647 NS_ASSERTION(!aHighestNode->mStyleData.mInheritedData-> \
michael@0 2648 mStyleStructs[eStyleStruct_##type_], \
michael@0 2649 "Going to leak style data"); \
michael@0 2650 aHighestNode->mStyleData.mInheritedData-> \
michael@0 2651 mStyleStructs[eStyleStruct_##type_] = data_; \
michael@0 2652 /* Propagate the bit down. */ \
michael@0 2653 PropagateDependentBit(eStyleStruct_##type_, aHighestNode, data_); \
michael@0 2654 /* Tell the style context that it doesn't own the data */ \
michael@0 2655 aContext-> \
michael@0 2656 AddStyleBit(nsCachedStyleData::GetBitForSID(eStyleStruct_##type_)); \
michael@0 2657 } \
michael@0 2658 /* Always cache inherited data on the style context */ \
michael@0 2659 aContext->SetStyle##type_(data_); \
michael@0 2660 \
michael@0 2661 return data_;
michael@0 2662
michael@0 2663 /**
michael@0 2664 * End an nsRuleNode::Compute*Data function for a reset struct.
michael@0 2665 *
michael@0 2666 * @param type_ The nsStyle* type this function computes.
michael@0 2667 * @param data_ Variable holding the result of this function.
michael@0 2668 */
michael@0 2669 #define COMPUTE_END_RESET(type_, data_) \
michael@0 2670 NS_POSTCONDITION(!canStoreInRuleTree || \
michael@0 2671 aRuleDetail == eRuleNone || \
michael@0 2672 aRuleDetail == eRulePartialReset || \
michael@0 2673 aRuleDetail == eRuleFullReset, \
michael@0 2674 "canStoreInRuleTree must be false for reset structs " \
michael@0 2675 "if any properties were specified as inherit"); \
michael@0 2676 if (!canStoreInRuleTree) \
michael@0 2677 /* We can't be cached in the rule node. We have to be put right */ \
michael@0 2678 /* on the style context. */ \
michael@0 2679 aContext->SetStyle(eStyleStruct_##type_, data_); \
michael@0 2680 else { \
michael@0 2681 /* We were fully specified and can therefore be cached right on the */ \
michael@0 2682 /* rule node. */ \
michael@0 2683 if (!aHighestNode->mStyleData.mResetData) { \
michael@0 2684 aHighestNode->mStyleData.mResetData = \
michael@0 2685 new (mPresContext) nsResetStyleData; \
michael@0 2686 } \
michael@0 2687 NS_ASSERTION(!aHighestNode->mStyleData.mResetData-> \
michael@0 2688 mStyleStructs[eStyleStruct_##type_], \
michael@0 2689 "Going to leak style data"); \
michael@0 2690 aHighestNode->mStyleData.mResetData-> \
michael@0 2691 mStyleStructs[eStyleStruct_##type_] = data_; \
michael@0 2692 /* Propagate the bit down. */ \
michael@0 2693 PropagateDependentBit(eStyleStruct_##type_, aHighestNode, data_); \
michael@0 2694 } \
michael@0 2695 \
michael@0 2696 return data_;
michael@0 2697
michael@0 2698 // This function figures out how much scaling should be suppressed to
michael@0 2699 // satisfy scriptminsize. This is our attempt to implement
michael@0 2700 // http://www.w3.org/TR/MathML2/chapter3.html#id.3.3.4.2.2
michael@0 2701 // This is called after mScriptLevel, mScriptMinSize and mScriptSizeMultiplier
michael@0 2702 // have been set in aFont.
michael@0 2703 //
michael@0 2704 // Here are the invariants we enforce:
michael@0 2705 // 1) A decrease in size must not reduce the size below minscriptsize.
michael@0 2706 // 2) An increase in size must not increase the size above the size we would
michael@0 2707 // have if minscriptsize had not been applied anywhere.
michael@0 2708 // 3) The scriptlevel-induced size change must between 1.0 and the parent's
michael@0 2709 // scriptsizemultiplier^(new script level - old script level), as close to the
michael@0 2710 // latter as possible subject to constraints 1 and 2.
michael@0 2711 static nscoord
michael@0 2712 ComputeScriptLevelSize(const nsStyleFont* aFont, const nsStyleFont* aParentFont,
michael@0 2713 nsPresContext* aPresContext, nscoord* aUnconstrainedSize)
michael@0 2714 {
michael@0 2715 int32_t scriptLevelChange =
michael@0 2716 aFont->mScriptLevel - aParentFont->mScriptLevel;
michael@0 2717 if (scriptLevelChange == 0) {
michael@0 2718 *aUnconstrainedSize = aParentFont->mScriptUnconstrainedSize;
michael@0 2719 // Constraint #3 says that we cannot change size, and #1 and #2 are always
michael@0 2720 // satisfied with no change. It's important this be fast because it covers
michael@0 2721 // all non-MathML content.
michael@0 2722 return aParentFont->mSize;
michael@0 2723 }
michael@0 2724
michael@0 2725 // Compute actual value of minScriptSize
michael@0 2726 nscoord minScriptSize = aParentFont->mScriptMinSize;
michael@0 2727 if (aFont->mAllowZoom) {
michael@0 2728 minScriptSize = nsStyleFont::ZoomText(aPresContext, minScriptSize);
michael@0 2729 }
michael@0 2730
michael@0 2731 double scriptLevelScale =
michael@0 2732 pow(aParentFont->mScriptSizeMultiplier, scriptLevelChange);
michael@0 2733 // Compute the size we would have had if minscriptsize had never been
michael@0 2734 // applied, also prevent overflow (bug 413274)
michael@0 2735 *aUnconstrainedSize =
michael@0 2736 NSToCoordRound(std::min(aParentFont->mScriptUnconstrainedSize*scriptLevelScale,
michael@0 2737 double(nscoord_MAX)));
michael@0 2738 // Compute the size we could get via scriptlevel change
michael@0 2739 nscoord scriptLevelSize =
michael@0 2740 NSToCoordRound(std::min(aParentFont->mSize*scriptLevelScale,
michael@0 2741 double(nscoord_MAX)));
michael@0 2742 if (scriptLevelScale <= 1.0) {
michael@0 2743 if (aParentFont->mSize <= minScriptSize) {
michael@0 2744 // We can't decrease the font size at all, so just stick to no change
michael@0 2745 // (authors are allowed to explicitly set the font size smaller than
michael@0 2746 // minscriptsize)
michael@0 2747 return aParentFont->mSize;
michael@0 2748 }
michael@0 2749 // We can decrease, so apply constraint #1
michael@0 2750 return std::max(minScriptSize, scriptLevelSize);
michael@0 2751 } else {
michael@0 2752 // scriptminsize can only make sizes larger than the unconstrained size
michael@0 2753 NS_ASSERTION(*aUnconstrainedSize <= scriptLevelSize, "How can this ever happen?");
michael@0 2754 // Apply constraint #2
michael@0 2755 return std::min(scriptLevelSize, std::max(*aUnconstrainedSize, minScriptSize));
michael@0 2756 }
michael@0 2757 }
michael@0 2758
michael@0 2759
michael@0 2760 /* static */ nscoord
michael@0 2761 nsRuleNode::CalcFontPointSize(int32_t aHTMLSize, int32_t aBasePointSize,
michael@0 2762 nsPresContext* aPresContext,
michael@0 2763 nsFontSizeType aFontSizeType)
michael@0 2764 {
michael@0 2765 #define sFontSizeTableMin 9
michael@0 2766 #define sFontSizeTableMax 16
michael@0 2767
michael@0 2768 // This table seems to be the one used by MacIE5. We hope its adoption in Mozilla
michael@0 2769 // and eventually in WinIE5.5 will help to establish a standard rendering across
michael@0 2770 // platforms and browsers. For now, it is used only in Strict mode. More can be read
michael@0 2771 // in the document written by Todd Farhner at:
michael@0 2772 // http://style.verso.com/font_size_intervals/altintervals.html
michael@0 2773 //
michael@0 2774 static int32_t sStrictFontSizeTable[sFontSizeTableMax - sFontSizeTableMin + 1][8] =
michael@0 2775 {
michael@0 2776 { 9, 9, 9, 9, 11, 14, 18, 27},
michael@0 2777 { 9, 9, 9, 10, 12, 15, 20, 30},
michael@0 2778 { 9, 9, 10, 11, 13, 17, 22, 33},
michael@0 2779 { 9, 9, 10, 12, 14, 18, 24, 36},
michael@0 2780 { 9, 10, 12, 13, 16, 20, 26, 39},
michael@0 2781 { 9, 10, 12, 14, 17, 21, 28, 42},
michael@0 2782 { 9, 10, 13, 15, 18, 23, 30, 45},
michael@0 2783 { 9, 10, 13, 16, 18, 24, 32, 48}
michael@0 2784 };
michael@0 2785 // HTML 1 2 3 4 5 6 7
michael@0 2786 // CSS xxs xs s m l xl xxl
michael@0 2787 // |
michael@0 2788 // user pref
michael@0 2789 //
michael@0 2790 //------------------------------------------------------------
michael@0 2791 //
michael@0 2792 // This table gives us compatibility with WinNav4 for the default fonts only.
michael@0 2793 // In WinNav4, the default fonts were:
michael@0 2794 //
michael@0 2795 // Times/12pt == Times/16px at 96ppi
michael@0 2796 // Courier/10pt == Courier/13px at 96ppi
michael@0 2797 //
michael@0 2798 // The 2 lines below marked "anchored" have the exact pixel sizes used by
michael@0 2799 // WinNav4 for Times/12pt and Courier/10pt at 96ppi. As you can see, the
michael@0 2800 // HTML size 3 (user pref) for those 2 anchored lines is 13px and 16px.
michael@0 2801 //
michael@0 2802 // All values other than the anchored values were filled in by hand, never
michael@0 2803 // going below 9px, and maintaining a "diagonal" relationship. See for
michael@0 2804 // example the 13s -- they follow a diagonal line through the table.
michael@0 2805 //
michael@0 2806 static int32_t sQuirksFontSizeTable[sFontSizeTableMax - sFontSizeTableMin + 1][8] =
michael@0 2807 {
michael@0 2808 { 9, 9, 9, 9, 11, 14, 18, 28 },
michael@0 2809 { 9, 9, 9, 10, 12, 15, 20, 31 },
michael@0 2810 { 9, 9, 9, 11, 13, 17, 22, 34 },
michael@0 2811 { 9, 9, 10, 12, 14, 18, 24, 37 },
michael@0 2812 { 9, 9, 10, 13, 16, 20, 26, 40 }, // anchored (13)
michael@0 2813 { 9, 9, 11, 14, 17, 21, 28, 42 },
michael@0 2814 { 9, 10, 12, 15, 17, 23, 30, 45 },
michael@0 2815 { 9, 10, 13, 16, 18, 24, 32, 48 } // anchored (16)
michael@0 2816 };
michael@0 2817 // HTML 1 2 3 4 5 6 7
michael@0 2818 // CSS xxs xs s m l xl xxl
michael@0 2819 // |
michael@0 2820 // user pref
michael@0 2821
michael@0 2822 #if 0
michael@0 2823 //
michael@0 2824 // These are the exact pixel values used by WinIE5 at 96ppi.
michael@0 2825 //
michael@0 2826 { ?, 8, 11, 12, 13, 16, 21, 32 }, // smallest
michael@0 2827 { ?, 9, 12, 13, 16, 21, 27, 40 }, // smaller
michael@0 2828 { ?, 10, 13, 16, 18, 24, 32, 48 }, // medium
michael@0 2829 { ?, 13, 16, 19, 21, 27, 37, ?? }, // larger
michael@0 2830 { ?, 16, 19, 21, 24, 32, 43, ?? } // largest
michael@0 2831 //
michael@0 2832 // HTML 1 2 3 4 5 6 7
michael@0 2833 // CSS ? ? ? ? ? ? ? ?
michael@0 2834 //
michael@0 2835 // (CSS not tested yet.)
michael@0 2836 //
michael@0 2837 #endif
michael@0 2838
michael@0 2839 static int32_t sFontSizeFactors[8] = { 60,75,89,100,120,150,200,300 };
michael@0 2840
michael@0 2841 static int32_t sCSSColumns[7] = {0, 1, 2, 3, 4, 5, 6}; // xxs...xxl
michael@0 2842 static int32_t sHTMLColumns[7] = {1, 2, 3, 4, 5, 6, 7}; // 1...7
michael@0 2843
michael@0 2844 double dFontSize;
michael@0 2845
michael@0 2846 if (aFontSizeType == eFontSize_HTML) {
michael@0 2847 aHTMLSize--; // input as 1-7
michael@0 2848 }
michael@0 2849
michael@0 2850 if (aHTMLSize < 0)
michael@0 2851 aHTMLSize = 0;
michael@0 2852 else if (aHTMLSize > 6)
michael@0 2853 aHTMLSize = 6;
michael@0 2854
michael@0 2855 int32_t* column;
michael@0 2856 switch (aFontSizeType)
michael@0 2857 {
michael@0 2858 case eFontSize_HTML: column = sHTMLColumns; break;
michael@0 2859 case eFontSize_CSS: column = sCSSColumns; break;
michael@0 2860 }
michael@0 2861
michael@0 2862 // Make special call specifically for fonts (needed PrintPreview)
michael@0 2863 int32_t fontSize = nsPresContext::AppUnitsToIntCSSPixels(aBasePointSize);
michael@0 2864
michael@0 2865 if ((fontSize >= sFontSizeTableMin) && (fontSize <= sFontSizeTableMax))
michael@0 2866 {
michael@0 2867 int32_t row = fontSize - sFontSizeTableMin;
michael@0 2868
michael@0 2869 if (aPresContext->CompatibilityMode() == eCompatibility_NavQuirks) {
michael@0 2870 dFontSize = nsPresContext::CSSPixelsToAppUnits(sQuirksFontSizeTable[row][column[aHTMLSize]]);
michael@0 2871 } else {
michael@0 2872 dFontSize = nsPresContext::CSSPixelsToAppUnits(sStrictFontSizeTable[row][column[aHTMLSize]]);
michael@0 2873 }
michael@0 2874 }
michael@0 2875 else
michael@0 2876 {
michael@0 2877 int32_t factor = sFontSizeFactors[column[aHTMLSize]];
michael@0 2878 dFontSize = (factor * aBasePointSize) / 100;
michael@0 2879 }
michael@0 2880
michael@0 2881
michael@0 2882 if (1.0 < dFontSize) {
michael@0 2883 return (nscoord)dFontSize;
michael@0 2884 }
michael@0 2885 return (nscoord)1;
michael@0 2886 }
michael@0 2887
michael@0 2888
michael@0 2889 //------------------------------------------------------------------------------
michael@0 2890 //
michael@0 2891 //------------------------------------------------------------------------------
michael@0 2892
michael@0 2893 /* static */ nscoord
michael@0 2894 nsRuleNode::FindNextSmallerFontSize(nscoord aFontSize, int32_t aBasePointSize,
michael@0 2895 nsPresContext* aPresContext,
michael@0 2896 nsFontSizeType aFontSizeType)
michael@0 2897 {
michael@0 2898 int32_t index;
michael@0 2899 int32_t indexMin;
michael@0 2900 int32_t indexMax;
michael@0 2901 float relativePosition;
michael@0 2902 nscoord smallerSize;
michael@0 2903 nscoord indexFontSize = aFontSize; // XXX initialize to quell a spurious gcc3.2 warning
michael@0 2904 nscoord smallestIndexFontSize;
michael@0 2905 nscoord largestIndexFontSize;
michael@0 2906 nscoord smallerIndexFontSize;
michael@0 2907 nscoord largerIndexFontSize;
michael@0 2908
michael@0 2909 nscoord onePx = nsPresContext::CSSPixelsToAppUnits(1);
michael@0 2910
michael@0 2911 if (aFontSizeType == eFontSize_HTML) {
michael@0 2912 indexMin = 1;
michael@0 2913 indexMax = 7;
michael@0 2914 } else {
michael@0 2915 indexMin = 0;
michael@0 2916 indexMax = 6;
michael@0 2917 }
michael@0 2918
michael@0 2919 smallestIndexFontSize = CalcFontPointSize(indexMin, aBasePointSize, aPresContext, aFontSizeType);
michael@0 2920 largestIndexFontSize = CalcFontPointSize(indexMax, aBasePointSize, aPresContext, aFontSizeType);
michael@0 2921 if (aFontSize > smallestIndexFontSize) {
michael@0 2922 if (aFontSize < NSToCoordRound(float(largestIndexFontSize) * 1.5)) { // smaller will be in HTML table
michael@0 2923 // find largest index smaller than current
michael@0 2924 for (index = indexMax; index >= indexMin; index--) {
michael@0 2925 indexFontSize = CalcFontPointSize(index, aBasePointSize, aPresContext, aFontSizeType);
michael@0 2926 if (indexFontSize < aFontSize)
michael@0 2927 break;
michael@0 2928 }
michael@0 2929 // set up points beyond table for interpolation purposes
michael@0 2930 if (indexFontSize == smallestIndexFontSize) {
michael@0 2931 smallerIndexFontSize = indexFontSize - onePx;
michael@0 2932 largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
michael@0 2933 } else if (indexFontSize == largestIndexFontSize) {
michael@0 2934 smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
michael@0 2935 largerIndexFontSize = NSToCoordRound(float(largestIndexFontSize) * 1.5);
michael@0 2936 } else {
michael@0 2937 smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
michael@0 2938 largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
michael@0 2939 }
michael@0 2940 // compute the relative position of the parent size between the two closest indexed sizes
michael@0 2941 relativePosition = float(aFontSize - indexFontSize) / float(largerIndexFontSize - indexFontSize);
michael@0 2942 // set the new size to have the same relative position between the next smallest two indexed sizes
michael@0 2943 smallerSize = smallerIndexFontSize + NSToCoordRound(relativePosition * (indexFontSize - smallerIndexFontSize));
michael@0 2944 }
michael@0 2945 else { // larger than HTML table, drop by 33%
michael@0 2946 smallerSize = NSToCoordRound(float(aFontSize) / 1.5);
michael@0 2947 }
michael@0 2948 }
michael@0 2949 else { // smaller than HTML table, drop by 1px
michael@0 2950 smallerSize = std::max(aFontSize - onePx, onePx);
michael@0 2951 }
michael@0 2952 return smallerSize;
michael@0 2953 }
michael@0 2954
michael@0 2955 //------------------------------------------------------------------------------
michael@0 2956 //
michael@0 2957 //------------------------------------------------------------------------------
michael@0 2958
michael@0 2959 /* static */ nscoord
michael@0 2960 nsRuleNode::FindNextLargerFontSize(nscoord aFontSize, int32_t aBasePointSize,
michael@0 2961 nsPresContext* aPresContext,
michael@0 2962 nsFontSizeType aFontSizeType)
michael@0 2963 {
michael@0 2964 int32_t index;
michael@0 2965 int32_t indexMin;
michael@0 2966 int32_t indexMax;
michael@0 2967 float relativePosition;
michael@0 2968 nscoord adjustment;
michael@0 2969 nscoord largerSize;
michael@0 2970 nscoord indexFontSize = aFontSize; // XXX initialize to quell a spurious gcc3.2 warning
michael@0 2971 nscoord smallestIndexFontSize;
michael@0 2972 nscoord largestIndexFontSize;
michael@0 2973 nscoord smallerIndexFontSize;
michael@0 2974 nscoord largerIndexFontSize;
michael@0 2975
michael@0 2976 nscoord onePx = nsPresContext::CSSPixelsToAppUnits(1);
michael@0 2977
michael@0 2978 if (aFontSizeType == eFontSize_HTML) {
michael@0 2979 indexMin = 1;
michael@0 2980 indexMax = 7;
michael@0 2981 } else {
michael@0 2982 indexMin = 0;
michael@0 2983 indexMax = 6;
michael@0 2984 }
michael@0 2985
michael@0 2986 smallestIndexFontSize = CalcFontPointSize(indexMin, aBasePointSize, aPresContext, aFontSizeType);
michael@0 2987 largestIndexFontSize = CalcFontPointSize(indexMax, aBasePointSize, aPresContext, aFontSizeType);
michael@0 2988 if (aFontSize > (smallestIndexFontSize - onePx)) {
michael@0 2989 if (aFontSize < largestIndexFontSize) { // larger will be in HTML table
michael@0 2990 // find smallest index larger than current
michael@0 2991 for (index = indexMin; index <= indexMax; index++) {
michael@0 2992 indexFontSize = CalcFontPointSize(index, aBasePointSize, aPresContext, aFontSizeType);
michael@0 2993 if (indexFontSize > aFontSize)
michael@0 2994 break;
michael@0 2995 }
michael@0 2996 // set up points beyond table for interpolation purposes
michael@0 2997 if (indexFontSize == smallestIndexFontSize) {
michael@0 2998 smallerIndexFontSize = indexFontSize - onePx;
michael@0 2999 largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
michael@0 3000 } else if (indexFontSize == largestIndexFontSize) {
michael@0 3001 smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
michael@0 3002 largerIndexFontSize = NSCoordSaturatingMultiply(largestIndexFontSize, 1.5);
michael@0 3003 } else {
michael@0 3004 smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
michael@0 3005 largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
michael@0 3006 }
michael@0 3007 // compute the relative position of the parent size between the two closest indexed sizes
michael@0 3008 relativePosition = float(aFontSize - smallerIndexFontSize) / float(indexFontSize - smallerIndexFontSize);
michael@0 3009 // set the new size to have the same relative position between the next largest two indexed sizes
michael@0 3010 adjustment = NSCoordSaturatingNonnegativeMultiply(largerIndexFontSize - indexFontSize, relativePosition);
michael@0 3011 largerSize = NSCoordSaturatingAdd(indexFontSize, adjustment);
michael@0 3012 }
michael@0 3013 else { // larger than HTML table, increase by 50%
michael@0 3014 largerSize = NSCoordSaturatingMultiply(aFontSize, 1.5);
michael@0 3015 }
michael@0 3016 }
michael@0 3017 else { // smaller than HTML table, increase by 1px
michael@0 3018 largerSize = NSCoordSaturatingAdd(aFontSize, onePx);
michael@0 3019 }
michael@0 3020 return largerSize;
michael@0 3021 }
michael@0 3022
michael@0 3023 struct SetFontSizeCalcOps : public css::BasicCoordCalcOps,
michael@0 3024 public css::NumbersAlreadyNormalizedOps
michael@0 3025 {
michael@0 3026 // The parameters beyond aValue that we need for CalcLengthWith.
michael@0 3027 const nscoord mParentSize;
michael@0 3028 const nsStyleFont* const mParentFont;
michael@0 3029 nsPresContext* const mPresContext;
michael@0 3030 const bool mAtRoot;
michael@0 3031 bool& mCanStoreInRuleTree;
michael@0 3032
michael@0 3033 SetFontSizeCalcOps(nscoord aParentSize, const nsStyleFont* aParentFont,
michael@0 3034 nsPresContext* aPresContext, bool aAtRoot,
michael@0 3035 bool& aCanStoreInRuleTree)
michael@0 3036 : mParentSize(aParentSize),
michael@0 3037 mParentFont(aParentFont),
michael@0 3038 mPresContext(aPresContext),
michael@0 3039 mAtRoot(aAtRoot),
michael@0 3040 mCanStoreInRuleTree(aCanStoreInRuleTree)
michael@0 3041 {
michael@0 3042 }
michael@0 3043
michael@0 3044 result_type ComputeLeafValue(const nsCSSValue& aValue)
michael@0 3045 {
michael@0 3046 nscoord size;
michael@0 3047 if (aValue.IsLengthUnit()) {
michael@0 3048 // Note that font-based length units use the parent's size
michael@0 3049 // unadjusted for scriptlevel changes. A scriptlevel change
michael@0 3050 // between us and the parent is simply ignored.
michael@0 3051 size = CalcLengthWith(aValue, mParentSize,
michael@0 3052 mParentFont,
michael@0 3053 nullptr, mPresContext, mAtRoot,
michael@0 3054 true, mCanStoreInRuleTree);
michael@0 3055 if (!aValue.IsRelativeLengthUnit() && mParentFont->mAllowZoom) {
michael@0 3056 size = nsStyleFont::ZoomText(mPresContext, size);
michael@0 3057 }
michael@0 3058 }
michael@0 3059 else if (eCSSUnit_Percent == aValue.GetUnit()) {
michael@0 3060 mCanStoreInRuleTree = false;
michael@0 3061 // Note that % units use the parent's size unadjusted for scriptlevel
michael@0 3062 // changes. A scriptlevel change between us and the parent is simply
michael@0 3063 // ignored.
michael@0 3064 // aValue.GetPercentValue() may be negative for, e.g., calc(-50%)
michael@0 3065 size = NSCoordSaturatingMultiply(mParentSize, aValue.GetPercentValue());
michael@0 3066 } else {
michael@0 3067 NS_ABORT_IF_FALSE(false, "unexpected value");
michael@0 3068 size = mParentSize;
michael@0 3069 }
michael@0 3070
michael@0 3071 return size;
michael@0 3072 }
michael@0 3073 };
michael@0 3074
michael@0 3075 /* static */ void
michael@0 3076 nsRuleNode::SetFontSize(nsPresContext* aPresContext,
michael@0 3077 const nsRuleData* aRuleData,
michael@0 3078 const nsStyleFont* aFont,
michael@0 3079 const nsStyleFont* aParentFont,
michael@0 3080 nscoord* aSize,
michael@0 3081 const nsFont& aSystemFont,
michael@0 3082 nscoord aParentSize,
michael@0 3083 nscoord aScriptLevelAdjustedParentSize,
michael@0 3084 bool aUsedStartStruct,
michael@0 3085 bool aAtRoot,
michael@0 3086 bool& aCanStoreInRuleTree)
michael@0 3087 {
michael@0 3088 // If false, means that *aSize has not been zoomed. If true, means that
michael@0 3089 // *aSize has been zoomed iff aParentFont->mAllowZoom is true.
michael@0 3090 bool sizeIsZoomedAccordingToParent = false;
michael@0 3091
michael@0 3092 int32_t baseSize = (int32_t) aPresContext->
michael@0 3093 GetDefaultFont(aFont->mGenericID, aFont->mLanguage)->size;
michael@0 3094 const nsCSSValue* sizeValue = aRuleData->ValueForFontSize();
michael@0 3095 if (eCSSUnit_Enumerated == sizeValue->GetUnit()) {
michael@0 3096 int32_t value = sizeValue->GetIntValue();
michael@0 3097
michael@0 3098 if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) &&
michael@0 3099 (value <= NS_STYLE_FONT_SIZE_XXLARGE)) {
michael@0 3100 *aSize = CalcFontPointSize(value, baseSize,
michael@0 3101 aPresContext, eFontSize_CSS);
michael@0 3102 }
michael@0 3103 else if (NS_STYLE_FONT_SIZE_XXXLARGE == value) {
michael@0 3104 // <font size="7"> is not specified in CSS, so we don't use eFontSize_CSS.
michael@0 3105 *aSize = CalcFontPointSize(value, baseSize, aPresContext);
michael@0 3106 }
michael@0 3107 else if (NS_STYLE_FONT_SIZE_LARGER == value ||
michael@0 3108 NS_STYLE_FONT_SIZE_SMALLER == value) {
michael@0 3109 aCanStoreInRuleTree = false;
michael@0 3110
michael@0 3111 // Un-zoom so we use the tables correctly. We'll then rezoom due
michael@0 3112 // to the |zoom = true| above.
michael@0 3113 // Note that relative units here use the parent's size unadjusted
michael@0 3114 // for scriptlevel changes. A scriptlevel change between us and the parent
michael@0 3115 // is simply ignored.
michael@0 3116 nscoord parentSize = aParentSize;
michael@0 3117 if (aParentFont->mAllowZoom) {
michael@0 3118 parentSize = nsStyleFont::UnZoomText(aPresContext, parentSize);
michael@0 3119 }
michael@0 3120
michael@0 3121 if (NS_STYLE_FONT_SIZE_LARGER == value) {
michael@0 3122 *aSize = FindNextLargerFontSize(parentSize,
michael@0 3123 baseSize, aPresContext, eFontSize_CSS);
michael@0 3124
michael@0 3125 NS_ASSERTION(*aSize >= parentSize,
michael@0 3126 "FindNextLargerFontSize failed");
michael@0 3127 }
michael@0 3128 else {
michael@0 3129 *aSize = FindNextSmallerFontSize(parentSize,
michael@0 3130 baseSize, aPresContext, eFontSize_CSS);
michael@0 3131 NS_ASSERTION(*aSize < parentSize ||
michael@0 3132 parentSize <= nsPresContext::CSSPixelsToAppUnits(1),
michael@0 3133 "FindNextSmallerFontSize failed");
michael@0 3134 }
michael@0 3135 } else {
michael@0 3136 NS_NOTREACHED("unexpected value");
michael@0 3137 }
michael@0 3138 }
michael@0 3139 else if (sizeValue->IsLengthUnit() ||
michael@0 3140 sizeValue->GetUnit() == eCSSUnit_Percent ||
michael@0 3141 sizeValue->IsCalcUnit()) {
michael@0 3142 SetFontSizeCalcOps ops(aParentSize, aParentFont,
michael@0 3143 aPresContext, aAtRoot,
michael@0 3144 aCanStoreInRuleTree);
michael@0 3145 *aSize = css::ComputeCalc(*sizeValue, ops);
michael@0 3146 if (*aSize < 0) {
michael@0 3147 NS_ABORT_IF_FALSE(sizeValue->IsCalcUnit(),
michael@0 3148 "negative lengths and percents should be rejected "
michael@0 3149 "by parser");
michael@0 3150 *aSize = 0;
michael@0 3151 }
michael@0 3152 // The calc ops will always zoom its result according to the value
michael@0 3153 // of aParentFont->mAllowZoom.
michael@0 3154 sizeIsZoomedAccordingToParent = true;
michael@0 3155 }
michael@0 3156 else if (eCSSUnit_System_Font == sizeValue->GetUnit()) {
michael@0 3157 // this becomes our cascading size
michael@0 3158 *aSize = aSystemFont.size;
michael@0 3159 }
michael@0 3160 else if (eCSSUnit_Inherit == sizeValue->GetUnit() ||
michael@0 3161 eCSSUnit_Unset == sizeValue->GetUnit()) {
michael@0 3162 aCanStoreInRuleTree = false;
michael@0 3163 // We apply scriptlevel change for this case, because the default is
michael@0 3164 // to inherit and we don't want explicit "inherit" to differ from the
michael@0 3165 // default.
michael@0 3166 *aSize = aScriptLevelAdjustedParentSize;
michael@0 3167 sizeIsZoomedAccordingToParent = true;
michael@0 3168 }
michael@0 3169 else if (eCSSUnit_Initial == sizeValue->GetUnit()) {
michael@0 3170 // The initial value is 'medium', which has magical sizing based on
michael@0 3171 // the generic font family, so do that here too.
michael@0 3172 *aSize = baseSize;
michael@0 3173 } else {
michael@0 3174 NS_ASSERTION(eCSSUnit_Null == sizeValue->GetUnit(),
michael@0 3175 "What kind of font-size value is this?");
michael@0 3176 // if aUsedStartStruct is true, then every single property in the
michael@0 3177 // font struct is being set all at once. This means scriptlevel is not
michael@0 3178 // going to have any influence on the font size; there is no need to
michael@0 3179 // do anything here.
michael@0 3180 if (!aUsedStartStruct && aParentSize != aScriptLevelAdjustedParentSize) {
michael@0 3181 // There was no rule affecting the size but the size has been
michael@0 3182 // affected by the parent's size via scriptlevel change. So we cannot
michael@0 3183 // store the data in the rule tree.
michael@0 3184 aCanStoreInRuleTree = false;
michael@0 3185 *aSize = aScriptLevelAdjustedParentSize;
michael@0 3186 sizeIsZoomedAccordingToParent = true;
michael@0 3187 } else {
michael@0 3188 return;
michael@0 3189 }
michael@0 3190 }
michael@0 3191
michael@0 3192 // We want to zoom the cascaded size so that em-based measurements,
michael@0 3193 // line-heights, etc., work.
michael@0 3194 bool currentlyZoomed = sizeIsZoomedAccordingToParent &&
michael@0 3195 aParentFont->mAllowZoom;
michael@0 3196 if (!currentlyZoomed && aFont->mAllowZoom) {
michael@0 3197 *aSize = nsStyleFont::ZoomText(aPresContext, *aSize);
michael@0 3198 } else if (currentlyZoomed && !aFont->mAllowZoom) {
michael@0 3199 *aSize = nsStyleFont::UnZoomText(aPresContext, *aSize);
michael@0 3200 }
michael@0 3201 }
michael@0 3202
michael@0 3203 static int8_t ClampTo8Bit(int32_t aValue) {
michael@0 3204 if (aValue < -128)
michael@0 3205 return -128;
michael@0 3206 if (aValue > 127)
michael@0 3207 return 127;
michael@0 3208 return int8_t(aValue);
michael@0 3209 }
michael@0 3210
michael@0 3211 /* static */ void
michael@0 3212 nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
michael@0 3213 uint8_t aGenericFontID, const nsRuleData* aRuleData,
michael@0 3214 const nsStyleFont* aParentFont,
michael@0 3215 nsStyleFont* aFont, bool aUsedStartStruct,
michael@0 3216 bool& aCanStoreInRuleTree)
michael@0 3217 {
michael@0 3218 bool atRoot = !aContext->GetParent();
michael@0 3219
michael@0 3220 // -x-text-zoom: none, inherit, initial
michael@0 3221 bool allowZoom;
michael@0 3222 const nsCSSValue* textZoomValue = aRuleData->ValueForTextZoom();
michael@0 3223 if (eCSSUnit_Null != textZoomValue->GetUnit()) {
michael@0 3224 if (eCSSUnit_Inherit == textZoomValue->GetUnit()) {
michael@0 3225 allowZoom = aParentFont->mAllowZoom;
michael@0 3226 } else if (eCSSUnit_None == textZoomValue->GetUnit()) {
michael@0 3227 allowZoom = false;
michael@0 3228 } else {
michael@0 3229 MOZ_ASSERT(eCSSUnit_Initial == textZoomValue->GetUnit(),
michael@0 3230 "unexpected unit");
michael@0 3231 allowZoom = true;
michael@0 3232 }
michael@0 3233 aFont->EnableZoom(aPresContext, allowZoom);
michael@0 3234 }
michael@0 3235
michael@0 3236 // mLanguage must be set before before any of the CalcLengthWith calls
michael@0 3237 // (direct calls or calls via SetFontSize) for the cases where |aParentFont|
michael@0 3238 // is the same as |aFont|.
michael@0 3239 //
michael@0 3240 // -x-lang: string, inherit
michael@0 3241 // This is not a real CSS property, it is an HTML attribute mapped to CSS.
michael@0 3242 const nsCSSValue* langValue = aRuleData->ValueForLang();
michael@0 3243 if (eCSSUnit_Ident == langValue->GetUnit()) {
michael@0 3244 nsAutoString lang;
michael@0 3245 langValue->GetStringValue(lang);
michael@0 3246
michael@0 3247 nsContentUtils::ASCIIToLower(lang);
michael@0 3248 aFont->mLanguage = do_GetAtom(lang);
michael@0 3249 aFont->mExplicitLanguage = true;
michael@0 3250 }
michael@0 3251
michael@0 3252 const nsFont* defaultVariableFont =
michael@0 3253 aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
michael@0 3254 aFont->mLanguage);
michael@0 3255
michael@0 3256 // XXX: Bleh. Disable these somehow?
michael@0 3257 // -moz-system-font: enum (never inherit!)
michael@0 3258 static_assert(
michael@0 3259 NS_STYLE_FONT_CAPTION == LookAndFeel::eFont_Caption &&
michael@0 3260 NS_STYLE_FONT_ICON == LookAndFeel::eFont_Icon &&
michael@0 3261 NS_STYLE_FONT_MENU == LookAndFeel::eFont_Menu &&
michael@0 3262 NS_STYLE_FONT_MESSAGE_BOX == LookAndFeel::eFont_MessageBox &&
michael@0 3263 NS_STYLE_FONT_SMALL_CAPTION == LookAndFeel::eFont_SmallCaption &&
michael@0 3264 NS_STYLE_FONT_STATUS_BAR == LookAndFeel::eFont_StatusBar &&
michael@0 3265 NS_STYLE_FONT_WINDOW == LookAndFeel::eFont_Window &&
michael@0 3266 NS_STYLE_FONT_DOCUMENT == LookAndFeel::eFont_Document &&
michael@0 3267 NS_STYLE_FONT_WORKSPACE == LookAndFeel::eFont_Workspace &&
michael@0 3268 NS_STYLE_FONT_DESKTOP == LookAndFeel::eFont_Desktop &&
michael@0 3269 NS_STYLE_FONT_INFO == LookAndFeel::eFont_Info &&
michael@0 3270 NS_STYLE_FONT_DIALOG == LookAndFeel::eFont_Dialog &&
michael@0 3271 NS_STYLE_FONT_BUTTON == LookAndFeel::eFont_Button &&
michael@0 3272 NS_STYLE_FONT_PULL_DOWN_MENU == LookAndFeel::eFont_PullDownMenu &&
michael@0 3273 NS_STYLE_FONT_LIST == LookAndFeel::eFont_List &&
michael@0 3274 NS_STYLE_FONT_FIELD == LookAndFeel::eFont_Field,
michael@0 3275 "LookAndFeel.h system-font constants out of sync with nsStyleConsts.h");
michael@0 3276
michael@0 3277 // Fall back to defaultVariableFont.
michael@0 3278 nsFont systemFont = *defaultVariableFont;
michael@0 3279 const nsCSSValue* systemFontValue = aRuleData->ValueForSystemFont();
michael@0 3280 if (eCSSUnit_Enumerated == systemFontValue->GetUnit()) {
michael@0 3281 gfxFontStyle fontStyle;
michael@0 3282 LookAndFeel::FontID fontID =
michael@0 3283 (LookAndFeel::FontID)systemFontValue->GetIntValue();
michael@0 3284 float devPerCSS =
michael@0 3285 (float)nsPresContext::AppUnitsPerCSSPixel() /
michael@0 3286 aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
michael@0 3287 if (LookAndFeel::GetFont(fontID, systemFont.name, fontStyle, devPerCSS)) {
michael@0 3288 systemFont.style = fontStyle.style;
michael@0 3289 systemFont.systemFont = fontStyle.systemFont;
michael@0 3290 systemFont.variant = NS_FONT_VARIANT_NORMAL;
michael@0 3291 systemFont.weight = fontStyle.weight;
michael@0 3292 systemFont.stretch = fontStyle.stretch;
michael@0 3293 systemFont.decorations = NS_FONT_DECORATION_NONE;
michael@0 3294 systemFont.size = NSFloatPixelsToAppUnits(fontStyle.size,
michael@0 3295 aPresContext->DeviceContext()->
michael@0 3296 UnscaledAppUnitsPerDevPixel());
michael@0 3297 //systemFont.langGroup = fontStyle.langGroup;
michael@0 3298 systemFont.sizeAdjust = fontStyle.sizeAdjust;
michael@0 3299
michael@0 3300 #ifdef XP_WIN
michael@0 3301 // XXXldb This platform-specific stuff should be in the
michael@0 3302 // LookAndFeel implementation, not here.
michael@0 3303 // XXXzw Should we even still *have* this code? It looks to be making
michael@0 3304 // old, probably obsolete assumptions.
michael@0 3305
michael@0 3306 if (fontID == LookAndFeel::eFont_Field ||
michael@0 3307 fontID == LookAndFeel::eFont_Button ||
michael@0 3308 fontID == LookAndFeel::eFont_List) {
michael@0 3309 // As far as I can tell the system default fonts and sizes
michael@0 3310 // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
michael@0 3311 // all pre-determined and cannot be changed by either the control panel
michael@0 3312 // or programmatically.
michael@0 3313 // Fields (text fields)
michael@0 3314 // Button and Selects (listboxes/comboboxes)
michael@0 3315 // We use whatever font is defined by the system. Which it appears
michael@0 3316 // (and the assumption is) it is always a proportional font. Then we
michael@0 3317 // always use 2 points smaller than what the browser has defined as
michael@0 3318 // the default proportional font.
michael@0 3319 // Assumption: system defined font is proportional
michael@0 3320 systemFont.size =
michael@0 3321 std::max(defaultVariableFont->size -
michael@0 3322 nsPresContext::CSSPointsToAppUnits(2), 0);
michael@0 3323 }
michael@0 3324 #endif
michael@0 3325 }
michael@0 3326 }
michael@0 3327
michael@0 3328 // font-family: string list, enum, inherit
michael@0 3329 const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
michael@0 3330 NS_ASSERTION(eCSSUnit_Enumerated != familyValue->GetUnit(),
michael@0 3331 "system fonts should not be in mFamily anymore");
michael@0 3332 if (eCSSUnit_Families == familyValue->GetUnit()) {
michael@0 3333 // set the correct font if we are using DocumentFonts OR we are overriding for XUL
michael@0 3334 // MJA: bug 31816
michael@0 3335 if (aGenericFontID == kGenericFont_NONE) {
michael@0 3336 // only bother appending fallback fonts if this isn't a fallback generic font itself
michael@0 3337 if (!aFont->mFont.name.IsEmpty())
michael@0 3338 aFont->mFont.name.Append((char16_t)',');
michael@0 3339 // defaultVariableFont.name should always be "serif" or "sans-serif".
michael@0 3340 aFont->mFont.name.Append(defaultVariableFont->name);
michael@0 3341 }
michael@0 3342 aFont->mFont.systemFont = false;
michael@0 3343 // Technically this is redundant with the code below, but it's good
michael@0 3344 // to have since we'll still want it once we get rid of
michael@0 3345 // SetGenericFont (bug 380915).
michael@0 3346 aFont->mGenericID = aGenericFontID;
michael@0 3347 }
michael@0 3348 else if (eCSSUnit_System_Font == familyValue->GetUnit()) {
michael@0 3349 aFont->mFont.name = systemFont.name;
michael@0 3350 aFont->mFont.systemFont = true;
michael@0 3351 aFont->mGenericID = kGenericFont_NONE;
michael@0 3352 }
michael@0 3353 else if (eCSSUnit_Inherit == familyValue->GetUnit() ||
michael@0 3354 eCSSUnit_Unset == familyValue->GetUnit()) {
michael@0 3355 aCanStoreInRuleTree = false;
michael@0 3356 aFont->mFont.name = aParentFont->mFont.name;
michael@0 3357 aFont->mFont.systemFont = aParentFont->mFont.systemFont;
michael@0 3358 aFont->mGenericID = aParentFont->mGenericID;
michael@0 3359 }
michael@0 3360 else if (eCSSUnit_Initial == familyValue->GetUnit()) {
michael@0 3361 aFont->mFont.name = defaultVariableFont->name;
michael@0 3362 aFont->mFont.systemFont = defaultVariableFont->systemFont;
michael@0 3363 aFont->mGenericID = kGenericFont_NONE;
michael@0 3364 }
michael@0 3365
michael@0 3366 // When we're in the loop in SetGenericFont, we must ensure that we
michael@0 3367 // always keep aFont->mFlags set to the correct generic. But we have
michael@0 3368 // to be careful not to touch it when we're called directly from
michael@0 3369 // ComputeFontData, because we could have a start struct.
michael@0 3370 if (aGenericFontID != kGenericFont_NONE) {
michael@0 3371 aFont->mGenericID = aGenericFontID;
michael@0 3372 }
michael@0 3373
michael@0 3374 // -moz-math-variant: enum, inherit, initial
michael@0 3375 SetDiscrete(*aRuleData->ValueForMathVariant(), aFont->mMathVariant,
michael@0 3376 aCanStoreInRuleTree,
michael@0 3377 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 3378 aParentFont->mMathVariant, NS_MATHML_MATHVARIANT_NONE,
michael@0 3379 0, 0, 0, 0);
michael@0 3380
michael@0 3381 // -moz-math-display: enum, inherit, initial
michael@0 3382 SetDiscrete(*aRuleData->ValueForMathDisplay(), aFont->mMathDisplay,
michael@0 3383 aCanStoreInRuleTree,
michael@0 3384 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 3385 aParentFont->mMathDisplay, NS_MATHML_DISPLAYSTYLE_INLINE,
michael@0 3386 0, 0, 0, 0);
michael@0 3387
michael@0 3388 // font-smoothing: enum, inherit, initial
michael@0 3389 SetDiscrete(*aRuleData->ValueForOSXFontSmoothing(),
michael@0 3390 aFont->mFont.smoothing, aCanStoreInRuleTree,
michael@0 3391 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 3392 aParentFont->mFont.smoothing,
michael@0 3393 defaultVariableFont->smoothing,
michael@0 3394 0, 0, 0, 0);
michael@0 3395
michael@0 3396 // font-style: enum, inherit, initial, -moz-system-font
michael@0 3397 if (aFont->mMathVariant != NS_MATHML_MATHVARIANT_NONE) {
michael@0 3398 // -moz-math-variant overrides font-style
michael@0 3399 aFont->mFont.style = NS_FONT_STYLE_NORMAL;
michael@0 3400 } else {
michael@0 3401 SetDiscrete(*aRuleData->ValueForFontStyle(),
michael@0 3402 aFont->mFont.style, aCanStoreInRuleTree,
michael@0 3403 SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
michael@0 3404 aParentFont->mFont.style,
michael@0 3405 defaultVariableFont->style,
michael@0 3406 0, 0, 0, systemFont.style);
michael@0 3407 }
michael@0 3408
michael@0 3409 // font-variant: enum, inherit, initial, -moz-system-font
michael@0 3410 SetDiscrete(*aRuleData->ValueForFontVariant(),
michael@0 3411 aFont->mFont.variant, aCanStoreInRuleTree,
michael@0 3412 SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
michael@0 3413 aParentFont->mFont.variant,
michael@0 3414 defaultVariableFont->variant,
michael@0 3415 0, 0, 0, systemFont.variant);
michael@0 3416
michael@0 3417 // font-weight: int, enum, inherit, initial, -moz-system-font
michael@0 3418 // special handling for enum
michael@0 3419 const nsCSSValue* weightValue = aRuleData->ValueForFontWeight();
michael@0 3420 if (aFont->mMathVariant != NS_MATHML_MATHVARIANT_NONE) {
michael@0 3421 // -moz-math-variant overrides font-weight
michael@0 3422 aFont->mFont.weight = NS_FONT_WEIGHT_NORMAL;
michael@0 3423 } else if (eCSSUnit_Enumerated == weightValue->GetUnit()) {
michael@0 3424 int32_t value = weightValue->GetIntValue();
michael@0 3425 switch (value) {
michael@0 3426 case NS_STYLE_FONT_WEIGHT_NORMAL:
michael@0 3427 case NS_STYLE_FONT_WEIGHT_BOLD:
michael@0 3428 aFont->mFont.weight = value;
michael@0 3429 break;
michael@0 3430 case NS_STYLE_FONT_WEIGHT_BOLDER: {
michael@0 3431 aCanStoreInRuleTree = false;
michael@0 3432 int32_t inheritedValue = aParentFont->mFont.weight;
michael@0 3433 if (inheritedValue <= 300) {
michael@0 3434 aFont->mFont.weight = 400;
michael@0 3435 } else if (inheritedValue <= 500) {
michael@0 3436 aFont->mFont.weight = 700;
michael@0 3437 } else {
michael@0 3438 aFont->mFont.weight = 900;
michael@0 3439 }
michael@0 3440 break;
michael@0 3441 }
michael@0 3442 case NS_STYLE_FONT_WEIGHT_LIGHTER: {
michael@0 3443 aCanStoreInRuleTree = false;
michael@0 3444 int32_t inheritedValue = aParentFont->mFont.weight;
michael@0 3445 if (inheritedValue < 600) {
michael@0 3446 aFont->mFont.weight = 100;
michael@0 3447 } else if (inheritedValue < 800) {
michael@0 3448 aFont->mFont.weight = 400;
michael@0 3449 } else {
michael@0 3450 aFont->mFont.weight = 700;
michael@0 3451 }
michael@0 3452 break;
michael@0 3453 }
michael@0 3454 }
michael@0 3455 } else
michael@0 3456 SetDiscrete(*weightValue, aFont->mFont.weight, aCanStoreInRuleTree,
michael@0 3457 SETDSC_INTEGER | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
michael@0 3458 aParentFont->mFont.weight,
michael@0 3459 defaultVariableFont->weight,
michael@0 3460 0, 0, 0, systemFont.weight);
michael@0 3461
michael@0 3462 // font-stretch: enum, inherit, initial, -moz-system-font
michael@0 3463 SetDiscrete(*aRuleData->ValueForFontStretch(),
michael@0 3464 aFont->mFont.stretch, aCanStoreInRuleTree,
michael@0 3465 SETDSC_SYSTEM_FONT | SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 3466 aParentFont->mFont.stretch,
michael@0 3467 defaultVariableFont->stretch,
michael@0 3468 0, 0, 0, systemFont.stretch);
michael@0 3469
michael@0 3470 // Compute scriptlevel, scriptminsize and scriptsizemultiplier now so
michael@0 3471 // they're available for font-size computation.
michael@0 3472
michael@0 3473 // -moz-script-min-size: length
michael@0 3474 const nsCSSValue* scriptMinSizeValue = aRuleData->ValueForScriptMinSize();
michael@0 3475 if (scriptMinSizeValue->IsLengthUnit()) {
michael@0 3476 // scriptminsize in font units (em, ex) has to be interpreted relative
michael@0 3477 // to the parent font, or the size definitions are circular and we
michael@0 3478 //
michael@0 3479 aFont->mScriptMinSize =
michael@0 3480 CalcLengthWith(*scriptMinSizeValue, aParentFont->mSize,
michael@0 3481 aParentFont,
michael@0 3482 nullptr, aPresContext, atRoot, true,
michael@0 3483 aCanStoreInRuleTree);
michael@0 3484 }
michael@0 3485
michael@0 3486 // -moz-script-size-multiplier: factor, inherit, initial
michael@0 3487 SetFactor(*aRuleData->ValueForScriptSizeMultiplier(),
michael@0 3488 aFont->mScriptSizeMultiplier,
michael@0 3489 aCanStoreInRuleTree, aParentFont->mScriptSizeMultiplier,
michael@0 3490 NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER,
michael@0 3491 SETFCT_POSITIVE | SETFCT_UNSET_INHERIT);
michael@0 3492
michael@0 3493 // -moz-script-level: integer, number, inherit
michael@0 3494 const nsCSSValue* scriptLevelValue = aRuleData->ValueForScriptLevel();
michael@0 3495 if (eCSSUnit_Integer == scriptLevelValue->GetUnit()) {
michael@0 3496 // "relative"
michael@0 3497 aCanStoreInRuleTree = false;
michael@0 3498 aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel + scriptLevelValue->GetIntValue());
michael@0 3499 }
michael@0 3500 else if (eCSSUnit_Number == scriptLevelValue->GetUnit()) {
michael@0 3501 // "absolute"
michael@0 3502 aFont->mScriptLevel = ClampTo8Bit(int32_t(scriptLevelValue->GetFloatValue()));
michael@0 3503 }
michael@0 3504 else if (eCSSUnit_Auto == scriptLevelValue->GetUnit()) {
michael@0 3505 // auto
michael@0 3506 aCanStoreInRuleTree = false;
michael@0 3507 aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel +
michael@0 3508 (aParentFont->mMathDisplay ==
michael@0 3509 NS_MATHML_DISPLAYSTYLE_INLINE ? 1 : 0));
michael@0 3510 }
michael@0 3511 else if (eCSSUnit_Inherit == scriptLevelValue->GetUnit() ||
michael@0 3512 eCSSUnit_Unset == scriptLevelValue->GetUnit()) {
michael@0 3513 aCanStoreInRuleTree = false;
michael@0 3514 aFont->mScriptLevel = aParentFont->mScriptLevel;
michael@0 3515 }
michael@0 3516 else if (eCSSUnit_Initial == scriptLevelValue->GetUnit()) {
michael@0 3517 aFont->mScriptLevel = 0;
michael@0 3518 }
michael@0 3519
michael@0 3520 // font-kerning: none, enum, inherit, initial, -moz-system-font
michael@0 3521 SetDiscrete(*aRuleData->ValueForFontKerning(),
michael@0 3522 aFont->mFont.kerning, aCanStoreInRuleTree,
michael@0 3523 SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
michael@0 3524 aParentFont->mFont.kerning,
michael@0 3525 defaultVariableFont->kerning,
michael@0 3526 0, 0, 0, systemFont.kerning);
michael@0 3527
michael@0 3528 // font-synthesis: none, enum (bit field), inherit, initial, -moz-system-font
michael@0 3529 SetDiscrete(*aRuleData->ValueForFontSynthesis(),
michael@0 3530 aFont->mFont.synthesis, aCanStoreInRuleTree,
michael@0 3531 SETDSC_NONE | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
michael@0 3532 SETDSC_UNSET_INHERIT,
michael@0 3533 aParentFont->mFont.synthesis,
michael@0 3534 defaultVariableFont->synthesis,
michael@0 3535 0, 0, 0, systemFont.synthesis);
michael@0 3536
michael@0 3537 // font-variant-alternates: normal, enum (bit field) + functions, inherit,
michael@0 3538 // initial, -moz-system-font
michael@0 3539 const nsCSSValue* variantAlternatesValue =
michael@0 3540 aRuleData->ValueForFontVariantAlternates();
michael@0 3541 int32_t variantAlternates = 0;
michael@0 3542
michael@0 3543 switch (variantAlternatesValue->GetUnit()) {
michael@0 3544 case eCSSUnit_Inherit:
michael@0 3545 case eCSSUnit_Unset:
michael@0 3546 aFont->mFont.CopyAlternates(aParentFont->mFont);
michael@0 3547 aCanStoreInRuleTree = false;
michael@0 3548 break;
michael@0 3549
michael@0 3550 case eCSSUnit_Initial:
michael@0 3551 case eCSSUnit_Normal:
michael@0 3552 aFont->mFont.variantAlternates = 0;
michael@0 3553 aFont->mFont.alternateValues.Clear();
michael@0 3554 aFont->mFont.featureValueLookup = nullptr;
michael@0 3555 break;
michael@0 3556
michael@0 3557 case eCSSUnit_Pair:
michael@0 3558 NS_ASSERTION(variantAlternatesValue->GetPairValue().mXValue.GetUnit() ==
michael@0 3559 eCSSUnit_Enumerated, "strange unit for variantAlternates");
michael@0 3560 variantAlternates =
michael@0 3561 variantAlternatesValue->GetPairValue().mXValue.GetIntValue();
michael@0 3562 aFont->mFont.variantAlternates = variantAlternates;
michael@0 3563
michael@0 3564 if (variantAlternates & NS_FONT_VARIANT_ALTERNATES_FUNCTIONAL_MASK) {
michael@0 3565 // fetch the feature lookup object from the styleset
michael@0 3566 aFont->mFont.featureValueLookup =
michael@0 3567 aPresContext->StyleSet()->GetFontFeatureValuesLookup();
michael@0 3568
michael@0 3569 NS_ASSERTION(variantAlternatesValue->GetPairValue().mYValue.GetUnit() ==
michael@0 3570 eCSSUnit_List, "function list not a list value");
michael@0 3571 nsStyleUtil::ComputeFunctionalAlternates(
michael@0 3572 variantAlternatesValue->GetPairValue().mYValue.GetListValue(),
michael@0 3573 aFont->mFont.alternateValues);
michael@0 3574 }
michael@0 3575 break;
michael@0 3576
michael@0 3577 default:
michael@0 3578 break;
michael@0 3579 }
michael@0 3580
michael@0 3581 // font-variant-caps: normal, enum, inherit, initial, -moz-system-font
michael@0 3582 SetDiscrete(*aRuleData->ValueForFontVariantCaps(),
michael@0 3583 aFont->mFont.variantCaps, aCanStoreInRuleTree,
michael@0 3584 SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
michael@0 3585 SETDSC_UNSET_INHERIT,
michael@0 3586 aParentFont->mFont.variantCaps,
michael@0 3587 defaultVariableFont->variantCaps,
michael@0 3588 0, 0, 0, systemFont.variantCaps);
michael@0 3589
michael@0 3590 // font-variant-east-asian: normal, enum (bit field), inherit, initial,
michael@0 3591 // -moz-system-font
michael@0 3592 SetDiscrete(*aRuleData->ValueForFontVariantEastAsian(),
michael@0 3593 aFont->mFont.variantEastAsian, aCanStoreInRuleTree,
michael@0 3594 SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
michael@0 3595 SETDSC_UNSET_INHERIT,
michael@0 3596 aParentFont->mFont.variantEastAsian,
michael@0 3597 defaultVariableFont->variantEastAsian,
michael@0 3598 0, 0, 0, systemFont.variantEastAsian);
michael@0 3599
michael@0 3600 // font-variant-ligatures: normal, enum (bit field), inherit, initial,
michael@0 3601 // -moz-system-font
michael@0 3602 SetDiscrete(*aRuleData->ValueForFontVariantLigatures(),
michael@0 3603 aFont->mFont.variantLigatures, aCanStoreInRuleTree,
michael@0 3604 SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
michael@0 3605 SETDSC_UNSET_INHERIT,
michael@0 3606 aParentFont->mFont.variantLigatures,
michael@0 3607 defaultVariableFont->variantLigatures,
michael@0 3608 0, 0, 0, systemFont.variantLigatures);
michael@0 3609
michael@0 3610 // font-variant-numeric: normal, enum (bit field), inherit, initial,
michael@0 3611 // -moz-system-font
michael@0 3612 SetDiscrete(*aRuleData->ValueForFontVariantNumeric(),
michael@0 3613 aFont->mFont.variantNumeric, aCanStoreInRuleTree,
michael@0 3614 SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
michael@0 3615 SETDSC_UNSET_INHERIT,
michael@0 3616 aParentFont->mFont.variantNumeric,
michael@0 3617 defaultVariableFont->variantNumeric,
michael@0 3618 0, 0, 0, systemFont.variantNumeric);
michael@0 3619
michael@0 3620 // font-variant-position: normal, enum, inherit, initial,
michael@0 3621 // -moz-system-font
michael@0 3622 SetDiscrete(*aRuleData->ValueForFontVariantPosition(),
michael@0 3623 aFont->mFont.variantPosition, aCanStoreInRuleTree,
michael@0 3624 SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
michael@0 3625 SETDSC_UNSET_INHERIT,
michael@0 3626 aParentFont->mFont.variantPosition,
michael@0 3627 defaultVariableFont->variantPosition,
michael@0 3628 0, 0, 0, systemFont.variantPosition);
michael@0 3629
michael@0 3630 // font-feature-settings
michael@0 3631 const nsCSSValue* featureSettingsValue =
michael@0 3632 aRuleData->ValueForFontFeatureSettings();
michael@0 3633
michael@0 3634 switch (featureSettingsValue->GetUnit()) {
michael@0 3635 case eCSSUnit_Null:
michael@0 3636 break;
michael@0 3637
michael@0 3638 case eCSSUnit_Normal:
michael@0 3639 case eCSSUnit_Initial:
michael@0 3640 aFont->mFont.fontFeatureSettings.Clear();
michael@0 3641 break;
michael@0 3642
michael@0 3643 case eCSSUnit_Inherit:
michael@0 3644 case eCSSUnit_Unset:
michael@0 3645 aCanStoreInRuleTree = false;
michael@0 3646 aFont->mFont.fontFeatureSettings = aParentFont->mFont.fontFeatureSettings;
michael@0 3647 break;
michael@0 3648
michael@0 3649 case eCSSUnit_System_Font:
michael@0 3650 aFont->mFont.fontFeatureSettings = systemFont.fontFeatureSettings;
michael@0 3651 break;
michael@0 3652
michael@0 3653 case eCSSUnit_PairList:
michael@0 3654 case eCSSUnit_PairListDep:
michael@0 3655 ComputeFontFeatures(featureSettingsValue->GetPairListValue(),
michael@0 3656 aFont->mFont.fontFeatureSettings);
michael@0 3657 break;
michael@0 3658
michael@0 3659 default:
michael@0 3660 NS_ABORT_IF_FALSE(false, "unexpected value unit");
michael@0 3661 break;
michael@0 3662 }
michael@0 3663
michael@0 3664 // font-language-override
michael@0 3665 const nsCSSValue* languageOverrideValue =
michael@0 3666 aRuleData->ValueForFontLanguageOverride();
michael@0 3667 if (eCSSUnit_Inherit == languageOverrideValue->GetUnit() ||
michael@0 3668 eCSSUnit_Unset == languageOverrideValue->GetUnit()) {
michael@0 3669 aCanStoreInRuleTree = false;
michael@0 3670 aFont->mFont.languageOverride = aParentFont->mFont.languageOverride;
michael@0 3671 } else if (eCSSUnit_Normal == languageOverrideValue->GetUnit() ||
michael@0 3672 eCSSUnit_Initial == languageOverrideValue->GetUnit()) {
michael@0 3673 aFont->mFont.languageOverride.Truncate();
michael@0 3674 } else if (eCSSUnit_System_Font == languageOverrideValue->GetUnit()) {
michael@0 3675 aFont->mFont.languageOverride = systemFont.languageOverride;
michael@0 3676 } else if (eCSSUnit_String == languageOverrideValue->GetUnit()) {
michael@0 3677 languageOverrideValue->GetStringValue(aFont->mFont.languageOverride);
michael@0 3678 }
michael@0 3679
michael@0 3680 // font-size: enum, length, percent, inherit
michael@0 3681 nscoord scriptLevelAdjustedParentSize = aParentFont->mSize;
michael@0 3682 nscoord scriptLevelAdjustedUnconstrainedParentSize;
michael@0 3683 scriptLevelAdjustedParentSize =
michael@0 3684 ComputeScriptLevelSize(aFont, aParentFont, aPresContext,
michael@0 3685 &scriptLevelAdjustedUnconstrainedParentSize);
michael@0 3686 NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize,
michael@0 3687 "If we have a start struct, we should have reset everything coming in here");
michael@0 3688 SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
michael@0 3689 &aFont->mSize,
michael@0 3690 systemFont, aParentFont->mSize, scriptLevelAdjustedParentSize,
michael@0 3691 aUsedStartStruct, atRoot, aCanStoreInRuleTree);
michael@0 3692 if (aParentFont->mSize == aParentFont->mScriptUnconstrainedSize &&
michael@0 3693 scriptLevelAdjustedParentSize == scriptLevelAdjustedUnconstrainedParentSize) {
michael@0 3694 // Fast path: we have not been affected by scriptminsize so we don't
michael@0 3695 // need to call SetFontSize again to compute the
michael@0 3696 // scriptminsize-unconstrained size. This is OK even if we have a
michael@0 3697 // start struct, because if we have a start struct then 'font-size'
michael@0 3698 // was specified and so scriptminsize has no effect.
michael@0 3699 aFont->mScriptUnconstrainedSize = aFont->mSize;
michael@0 3700 } else {
michael@0 3701 SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
michael@0 3702 &aFont->mScriptUnconstrainedSize,
michael@0 3703 systemFont, aParentFont->mScriptUnconstrainedSize,
michael@0 3704 scriptLevelAdjustedUnconstrainedParentSize,
michael@0 3705 aUsedStartStruct, atRoot, aCanStoreInRuleTree);
michael@0 3706 }
michael@0 3707 NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
michael@0 3708 "scriptminsize should never be making things bigger");
michael@0 3709
michael@0 3710 nscoord fontSize = aFont->mSize;
michael@0 3711
michael@0 3712 // enforce the user' specified minimum font-size on the value that we expose
michael@0 3713 // (but don't change font-size:0, since that would unhide hidden text)
michael@0 3714 if (fontSize > 0) {
michael@0 3715 nscoord minFontSize = aPresContext->MinFontSize(aFont->mLanguage);
michael@0 3716 if (minFontSize < 0) {
michael@0 3717 minFontSize = 0;
michael@0 3718 }
michael@0 3719 if (fontSize < minFontSize && !aPresContext->IsChrome()) {
michael@0 3720 // override the minimum font-size constraint
michael@0 3721 fontSize = minFontSize;
michael@0 3722 }
michael@0 3723 }
michael@0 3724 aFont->mFont.size = fontSize;
michael@0 3725
michael@0 3726 // font-size-adjust: number, none, inherit, initial, -moz-system-font
michael@0 3727 const nsCSSValue* sizeAdjustValue = aRuleData->ValueForFontSizeAdjust();
michael@0 3728 if (eCSSUnit_System_Font == sizeAdjustValue->GetUnit()) {
michael@0 3729 aFont->mFont.sizeAdjust = systemFont.sizeAdjust;
michael@0 3730 } else
michael@0 3731 SetFactor(*sizeAdjustValue, aFont->mFont.sizeAdjust,
michael@0 3732 aCanStoreInRuleTree, aParentFont->mFont.sizeAdjust, 0.0f,
michael@0 3733 SETFCT_NONE | SETFCT_UNSET_INHERIT);
michael@0 3734 }
michael@0 3735
michael@0 3736 /* static */ void
michael@0 3737 nsRuleNode::ComputeFontFeatures(const nsCSSValuePairList *aFeaturesList,
michael@0 3738 nsTArray<gfxFontFeature>& aFeatureSettings)
michael@0 3739 {
michael@0 3740 aFeatureSettings.Clear();
michael@0 3741 for (const nsCSSValuePairList* p = aFeaturesList; p; p = p->mNext) {
michael@0 3742 gfxFontFeature feat = {0, 0};
michael@0 3743
michael@0 3744 NS_ABORT_IF_FALSE(aFeaturesList->mXValue.GetUnit() == eCSSUnit_String,
michael@0 3745 "unexpected value unit");
michael@0 3746
michael@0 3747 // tag is a 4-byte ASCII sequence
michael@0 3748 nsAutoString tag;
michael@0 3749 p->mXValue.GetStringValue(tag);
michael@0 3750 if (tag.Length() != 4) {
michael@0 3751 continue;
michael@0 3752 }
michael@0 3753 // parsing validates that these are ASCII chars
michael@0 3754 // tags are always big-endian
michael@0 3755 feat.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8) | tag[3];
michael@0 3756
michael@0 3757 // value
michael@0 3758 NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Integer,
michael@0 3759 "should have found an integer unit");
michael@0 3760 feat.mValue = p->mYValue.GetIntValue();
michael@0 3761
michael@0 3762 aFeatureSettings.AppendElement(feat);
michael@0 3763 }
michael@0 3764 }
michael@0 3765
michael@0 3766 // This should die (bug 380915).
michael@0 3767 //
michael@0 3768 // SetGenericFont:
michael@0 3769 // - backtrack to an ancestor with the same generic font name (possibly
michael@0 3770 // up to the root where default values come from the presentation context)
michael@0 3771 // - re-apply cascading rules from there without caching intermediate values
michael@0 3772 /* static */ void
michael@0 3773 nsRuleNode::SetGenericFont(nsPresContext* aPresContext,
michael@0 3774 nsStyleContext* aContext,
michael@0 3775 uint8_t aGenericFontID,
michael@0 3776 nsStyleFont* aFont)
michael@0 3777 {
michael@0 3778 // walk up the contexts until a context with the desired generic font
michael@0 3779 nsAutoTArray<nsStyleContext*, 8> contextPath;
michael@0 3780 contextPath.AppendElement(aContext);
michael@0 3781 nsStyleContext* higherContext = aContext->GetParent();
michael@0 3782 while (higherContext) {
michael@0 3783 if (higherContext->StyleFont()->mGenericID == aGenericFontID) {
michael@0 3784 // done walking up the higher contexts
michael@0 3785 break;
michael@0 3786 }
michael@0 3787 contextPath.AppendElement(higherContext);
michael@0 3788 higherContext = higherContext->GetParent();
michael@0 3789 }
michael@0 3790
michael@0 3791 // re-apply the cascading rules, starting from the higher context
michael@0 3792
michael@0 3793 // If we stopped earlier because we reached the root of the style tree,
michael@0 3794 // we will start with the default generic font from the presentation
michael@0 3795 // context. Otherwise we start with the higher context.
michael@0 3796 const nsFont* defaultFont =
michael@0 3797 aPresContext->GetDefaultFont(aGenericFontID, aFont->mLanguage);
michael@0 3798 nsStyleFont parentFont(*defaultFont, aPresContext);
michael@0 3799 if (higherContext) {
michael@0 3800 const nsStyleFont* tmpFont = higherContext->StyleFont();
michael@0 3801 parentFont = *tmpFont;
michael@0 3802 }
michael@0 3803 *aFont = parentFont;
michael@0 3804
michael@0 3805 bool dummy;
michael@0 3806 uint32_t fontBit = nsCachedStyleData::GetBitForSID(eStyleStruct_Font);
michael@0 3807
michael@0 3808 // use placement new[] on the result of alloca() to allocate a
michael@0 3809 // variable-sized stack array, including execution of constructors,
michael@0 3810 // and use an RAII class to run the destructors too.
michael@0 3811 size_t nprops = nsCSSProps::PropertyCountInStruct(eStyleStruct_Font);
michael@0 3812 void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
michael@0 3813
michael@0 3814 for (int32_t i = contextPath.Length() - 1; i >= 0; --i) {
michael@0 3815 nsStyleContext* context = contextPath[i];
michael@0 3816 AutoCSSValueArray dataArray(dataStorage, nprops);
michael@0 3817
michael@0 3818 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), dataArray.get(),
michael@0 3819 aPresContext, context);
michael@0 3820 ruleData.mValueOffsets[eStyleStruct_Font] = 0;
michael@0 3821
michael@0 3822 // Trimmed down version of ::WalkRuleTree() to re-apply the style rules
michael@0 3823 // Note that we *do* need to do this for our own data, since what is
michael@0 3824 // in |fontData| in ComputeFontData is only for the rules below
michael@0 3825 // aStartStruct.
michael@0 3826 for (nsRuleNode* ruleNode = context->RuleNode(); ruleNode;
michael@0 3827 ruleNode = ruleNode->GetParent()) {
michael@0 3828 if (ruleNode->mNoneBits & fontBit)
michael@0 3829 // no more font rules on this branch, get out
michael@0 3830 break;
michael@0 3831
michael@0 3832 nsIStyleRule *rule = ruleNode->GetRule();
michael@0 3833 if (rule) {
michael@0 3834 ruleData.mLevel = ruleNode->GetLevel();
michael@0 3835 ruleData.mIsImportantRule = ruleNode->IsImportantRule();
michael@0 3836 rule->MapRuleInfoInto(&ruleData);
michael@0 3837 }
michael@0 3838 }
michael@0 3839
michael@0 3840 // Compute the delta from the information that the rules specified
michael@0 3841
michael@0 3842 // Avoid unnecessary operations in SetFont(). But we care if it's
michael@0 3843 // the final value that we're computing.
michael@0 3844 if (i != 0)
michael@0 3845 ruleData.ValueForFontFamily()->Reset();
michael@0 3846
michael@0 3847 ResolveVariableReferences(eStyleStruct_Font, &ruleData, aContext);
michael@0 3848
michael@0 3849 nsRuleNode::SetFont(aPresContext, context,
michael@0 3850 aGenericFontID, &ruleData, &parentFont, aFont,
michael@0 3851 false, dummy);
michael@0 3852
michael@0 3853 parentFont = *aFont;
michael@0 3854 }
michael@0 3855 }
michael@0 3856
michael@0 3857 static bool ExtractGeneric(const nsString& aFamily, bool aGeneric,
michael@0 3858 void *aData)
michael@0 3859 {
michael@0 3860 nsAutoString *data = static_cast<nsAutoString*>(aData);
michael@0 3861
michael@0 3862 if (aGeneric) {
michael@0 3863 *data = aFamily;
michael@0 3864 return false; // stop enumeration
michael@0 3865 }
michael@0 3866 return true;
michael@0 3867 }
michael@0 3868
michael@0 3869 struct smugglerStruct {
michael@0 3870 nsStyleFont *font;
michael@0 3871 gfxUserFontSet *userFonts;
michael@0 3872 };
michael@0 3873
michael@0 3874 /* This function forces the use of the first @font-face font we find */
michael@0 3875 static bool ForceFirstWebFont(const nsString& aFamily, bool aGeneric,
michael@0 3876 void *smuggled)
michael@0 3877 {
michael@0 3878 smugglerStruct *sm = static_cast<smugglerStruct*>(smuggled);
michael@0 3879
michael@0 3880 if (aGeneric) {
michael@0 3881 return true;
michael@0 3882 }
michael@0 3883
michael@0 3884 if (sm->userFonts->HasFamily(aFamily)) {
michael@0 3885 // Force use of this exact @font-face font since we have it.
michael@0 3886 sm->font->mFont.name = aFamily;
michael@0 3887
michael@0 3888 return false; // Stop enumeration.
michael@0 3889 }
michael@0 3890
michael@0 3891 return true;
michael@0 3892 }
michael@0 3893
michael@0 3894 const void*
michael@0 3895 nsRuleNode::ComputeFontData(void* aStartStruct,
michael@0 3896 const nsRuleData* aRuleData,
michael@0 3897 nsStyleContext* aContext,
michael@0 3898 nsRuleNode* aHighestNode,
michael@0 3899 const RuleDetail aRuleDetail,
michael@0 3900 const bool aCanStoreInRuleTree)
michael@0 3901 {
michael@0 3902 COMPUTE_START_INHERITED(Font, (mPresContext), font, parentFont)
michael@0 3903
michael@0 3904 // NOTE: The |aRuleDetail| passed in is a little bit conservative due
michael@0 3905 // to the -moz-system-font property. We really don't need to consider
michael@0 3906 // it here in determining whether to cache in the rule tree. However,
michael@0 3907 // we do need to consider it in WalkRuleTree when deciding whether to
michael@0 3908 // walk further up the tree. So this means that when the font struct
michael@0 3909 // is fully specified using *longhand* properties (excluding
michael@0 3910 // -moz-system-font), we won't cache in the rule tree even though we
michael@0 3911 // could. However, it's pretty unlikely authors will do that
michael@0 3912 // (although there is a pretty good chance they'll fully specify it
michael@0 3913 // using the 'font' shorthand).
michael@0 3914
michael@0 3915 bool useDocumentFonts =
michael@0 3916 mPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
michael@0 3917 bool isXUL = PR_FALSE;
michael@0 3918 bool forcedWebFont = false;
michael@0 3919
michael@0 3920 // See if we are in the chrome
michael@0 3921 // We only need to know this to determine if we have to use the
michael@0 3922 // document fonts (overriding the useDocumentFonts flag).
michael@0 3923 if (mPresContext->IsChrome()) {
michael@0 3924 // if we are not using document fonts, but this is a XUL document,
michael@0 3925 // then we use the document fonts anyway
michael@0 3926 isXUL = true;
michael@0 3927 }
michael@0 3928
michael@0 3929 // Figure out if we are a generic font
michael@0 3930 uint8_t generic = kGenericFont_NONE;
michael@0 3931 // XXXldb What if we would have had a string if we hadn't been doing
michael@0 3932 // the optimization with a non-null aStartStruct?
michael@0 3933 const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
michael@0 3934 if (eCSSUnit_Families == familyValue->GetUnit()) {
michael@0 3935 familyValue->GetStringValue(font->mFont.name);
michael@0 3936 // XXXldb Do we want to extract the generic for this if it's not only a
michael@0 3937 // generic?
michael@0 3938 nsFont::GetGenericID(font->mFont.name, &generic);
michael@0 3939
michael@0 3940 if (!isXUL) {
michael@0 3941 gfxUserFontSet *userFonts = mPresContext->GetUserFontSet();
michael@0 3942 if (userFonts) {
michael@0 3943 smugglerStruct sm;
michael@0 3944 sm.userFonts = userFonts;
michael@0 3945 sm.font = font;
michael@0 3946
michael@0 3947 if (!sm.font->mFont.EnumerateFamilies(ForceFirstWebFont, &sm)) {
michael@0 3948 isXUL = true; // Always allow WebFont use.
michael@0 3949 forcedWebFont = true;
michael@0 3950 }
michael@0 3951 }
michael@0 3952 }
michael@0 3953
michael@0 3954 if (!forcedWebFont && generic == kGenericFont_NONE)
michael@0 3955 mPresContext->AddFontAttempt(font->mFont);
michael@0 3956
michael@0 3957 // If we aren't allowed to use document fonts, then we are only entitled
michael@0 3958 // to use the user's default variable-width font and fixed-width font
michael@0 3959 if (!isXUL && (!useDocumentFonts ||
michael@0 3960 mPresContext->FontAttemptCountReached(font->mFont) ||
michael@0 3961 mPresContext->FontUseCountReached(font->mFont))) {
michael@0 3962 // Extract the generic from the specified font family...
michael@0 3963 nsAutoString genericName;
michael@0 3964 if (!font->mFont.EnumerateFamilies(ExtractGeneric, &genericName)) {
michael@0 3965 // The specified font had a generic family.
michael@0 3966 font->mFont.name = genericName;
michael@0 3967 nsFont::GetGenericID(genericName, &generic);
michael@0 3968
michael@0 3969 // ... and only use it if it's -moz-fixed or monospace
michael@0 3970 if (generic != kGenericFont_moz_fixed &&
michael@0 3971 generic != kGenericFont_monospace) {
michael@0 3972 font->mFont.name.Truncate();
michael@0 3973 generic = kGenericFont_NONE;
michael@0 3974 }
michael@0 3975 } else {
michael@0 3976 // The specified font did not have a generic family.
michael@0 3977 font->mFont.name.Truncate();
michael@0 3978 generic = kGenericFont_NONE;
michael@0 3979 }
michael@0 3980 }
michael@0 3981 }
michael@0 3982
michael@0 3983 // Now compute our font struct
michael@0 3984 if (generic == kGenericFont_NONE) {
michael@0 3985 // continue the normal processing
michael@0 3986 nsRuleNode::SetFont(mPresContext, aContext, generic,
michael@0 3987 aRuleData, parentFont, font,
michael@0 3988 aStartStruct != nullptr, canStoreInRuleTree);
michael@0 3989 }
michael@0 3990 else {
michael@0 3991 // re-calculate the font as a generic font
michael@0 3992 canStoreInRuleTree = false;
michael@0 3993 nsRuleNode::SetGenericFont(mPresContext, aContext, generic,
michael@0 3994 font);
michael@0 3995 }
michael@0 3996
michael@0 3997 if (!forcedWebFont && font->mGenericID == kGenericFont_NONE)
michael@0 3998 mPresContext->AddFontUse(font->mFont);
michael@0 3999 COMPUTE_END_INHERITED(Font, font)
michael@0 4000 }
michael@0 4001
michael@0 4002 template <typename T>
michael@0 4003 inline uint32_t ListLength(const T* aList)
michael@0 4004 {
michael@0 4005 uint32_t len = 0;
michael@0 4006 while (aList) {
michael@0 4007 len++;
michael@0 4008 aList = aList->mNext;
michael@0 4009 }
michael@0 4010 return len;
michael@0 4011 }
michael@0 4012
michael@0 4013
michael@0 4014
michael@0 4015 already_AddRefed<nsCSSShadowArray>
michael@0 4016 nsRuleNode::GetShadowData(const nsCSSValueList* aList,
michael@0 4017 nsStyleContext* aContext,
michael@0 4018 bool aIsBoxShadow,
michael@0 4019 bool& aCanStoreInRuleTree)
michael@0 4020 {
michael@0 4021 uint32_t arrayLength = ListLength(aList);
michael@0 4022
michael@0 4023 NS_ABORT_IF_FALSE(arrayLength > 0,
michael@0 4024 "Non-null text-shadow list, yet we counted 0 items.");
michael@0 4025 nsRefPtr<nsCSSShadowArray> shadowList =
michael@0 4026 new(arrayLength) nsCSSShadowArray(arrayLength);
michael@0 4027
michael@0 4028 if (!shadowList)
michael@0 4029 return nullptr;
michael@0 4030
michael@0 4031 nsStyleCoord tempCoord;
michael@0 4032 DebugOnly<bool> unitOK;
michael@0 4033 for (nsCSSShadowItem* item = shadowList->ShadowAt(0);
michael@0 4034 aList;
michael@0 4035 aList = aList->mNext, ++item) {
michael@0 4036 NS_ABORT_IF_FALSE(aList->mValue.GetUnit() == eCSSUnit_Array,
michael@0 4037 "expecting a plain array value");
michael@0 4038 nsCSSValue::Array *arr = aList->mValue.GetArrayValue();
michael@0 4039 // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
michael@0 4040 unitOK = SetCoord(arr->Item(0), tempCoord, nsStyleCoord(),
michael@0 4041 SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
michael@0 4042 aContext, mPresContext, aCanStoreInRuleTree);
michael@0 4043 NS_ASSERTION(unitOK, "unexpected unit");
michael@0 4044 item->mXOffset = tempCoord.GetCoordValue();
michael@0 4045
michael@0 4046 unitOK = SetCoord(arr->Item(1), tempCoord, nsStyleCoord(),
michael@0 4047 SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
michael@0 4048 aContext, mPresContext, aCanStoreInRuleTree);
michael@0 4049 NS_ASSERTION(unitOK, "unexpected unit");
michael@0 4050 item->mYOffset = tempCoord.GetCoordValue();
michael@0 4051
michael@0 4052 // Blur radius is optional in the current box-shadow spec
michael@0 4053 if (arr->Item(2).GetUnit() != eCSSUnit_Null) {
michael@0 4054 unitOK = SetCoord(arr->Item(2), tempCoord, nsStyleCoord(),
michael@0 4055 SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY |
michael@0 4056 SETCOORD_CALC_CLAMP_NONNEGATIVE,
michael@0 4057 aContext, mPresContext, aCanStoreInRuleTree);
michael@0 4058 NS_ASSERTION(unitOK, "unexpected unit");
michael@0 4059 item->mRadius = tempCoord.GetCoordValue();
michael@0 4060 } else {
michael@0 4061 item->mRadius = 0;
michael@0 4062 }
michael@0 4063
michael@0 4064 // Find the spread radius
michael@0 4065 if (aIsBoxShadow && arr->Item(3).GetUnit() != eCSSUnit_Null) {
michael@0 4066 unitOK = SetCoord(arr->Item(3), tempCoord, nsStyleCoord(),
michael@0 4067 SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
michael@0 4068 aContext, mPresContext, aCanStoreInRuleTree);
michael@0 4069 NS_ASSERTION(unitOK, "unexpected unit");
michael@0 4070 item->mSpread = tempCoord.GetCoordValue();
michael@0 4071 } else {
michael@0 4072 item->mSpread = 0;
michael@0 4073 }
michael@0 4074
michael@0 4075 if (arr->Item(4).GetUnit() != eCSSUnit_Null) {
michael@0 4076 item->mHasColor = true;
michael@0 4077 // 2nd argument can be bogus since inherit is not a valid color
michael@0 4078 unitOK = SetColor(arr->Item(4), 0, mPresContext, aContext, item->mColor,
michael@0 4079 aCanStoreInRuleTree);
michael@0 4080 NS_ASSERTION(unitOK, "unexpected unit");
michael@0 4081 }
michael@0 4082
michael@0 4083 if (aIsBoxShadow && arr->Item(5).GetUnit() == eCSSUnit_Enumerated) {
michael@0 4084 NS_ASSERTION(arr->Item(5).GetIntValue() == NS_STYLE_BOX_SHADOW_INSET,
michael@0 4085 "invalid keyword type for box shadow");
michael@0 4086 item->mInset = true;
michael@0 4087 } else {
michael@0 4088 item->mInset = false;
michael@0 4089 }
michael@0 4090 }
michael@0 4091
michael@0 4092 return shadowList.forget();
michael@0 4093 }
michael@0 4094
michael@0 4095 const void*
michael@0 4096 nsRuleNode::ComputeTextData(void* aStartStruct,
michael@0 4097 const nsRuleData* aRuleData,
michael@0 4098 nsStyleContext* aContext,
michael@0 4099 nsRuleNode* aHighestNode,
michael@0 4100 const RuleDetail aRuleDetail,
michael@0 4101 const bool aCanStoreInRuleTree)
michael@0 4102 {
michael@0 4103 COMPUTE_START_INHERITED(Text, (), text, parentText)
michael@0 4104
michael@0 4105 // tab-size: integer, inherit
michael@0 4106 SetDiscrete(*aRuleData->ValueForTabSize(),
michael@0 4107 text->mTabSize, canStoreInRuleTree,
michael@0 4108 SETDSC_INTEGER | SETDSC_UNSET_INHERIT, parentText->mTabSize,
michael@0 4109 NS_STYLE_TABSIZE_INITIAL, 0, 0, 0, 0);
michael@0 4110
michael@0 4111 // letter-spacing: normal, length, inherit
michael@0 4112 SetCoord(*aRuleData->ValueForLetterSpacing(),
michael@0 4113 text->mLetterSpacing, parentText->mLetterSpacing,
michael@0 4114 SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
michael@0 4115 SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INHERIT,
michael@0 4116 aContext, mPresContext, canStoreInRuleTree);
michael@0 4117
michael@0 4118 // text-shadow: none, list, inherit, initial
michael@0 4119 const nsCSSValue* textShadowValue = aRuleData->ValueForTextShadow();
michael@0 4120 if (textShadowValue->GetUnit() != eCSSUnit_Null) {
michael@0 4121 text->mTextShadow = nullptr;
michael@0 4122
michael@0 4123 // Don't need to handle none/initial explicitly: The above assignment
michael@0 4124 // takes care of that
michael@0 4125 if (textShadowValue->GetUnit() == eCSSUnit_Inherit ||
michael@0 4126 textShadowValue->GetUnit() == eCSSUnit_Unset) {
michael@0 4127 canStoreInRuleTree = false;
michael@0 4128 text->mTextShadow = parentText->mTextShadow;
michael@0 4129 } else if (textShadowValue->GetUnit() == eCSSUnit_List ||
michael@0 4130 textShadowValue->GetUnit() == eCSSUnit_ListDep) {
michael@0 4131 // List of arrays
michael@0 4132 text->mTextShadow = GetShadowData(textShadowValue->GetListValue(),
michael@0 4133 aContext, false, canStoreInRuleTree);
michael@0 4134 }
michael@0 4135 }
michael@0 4136
michael@0 4137 // line-height: normal, number, length, percent, inherit
michael@0 4138 const nsCSSValue* lineHeightValue = aRuleData->ValueForLineHeight();
michael@0 4139 if (eCSSUnit_Percent == lineHeightValue->GetUnit()) {
michael@0 4140 canStoreInRuleTree = false;
michael@0 4141 // Use |mFont.size| to pick up minimum font size.
michael@0 4142 text->mLineHeight.SetCoordValue(
michael@0 4143 NSToCoordRound(float(aContext->StyleFont()->mFont.size) *
michael@0 4144 lineHeightValue->GetPercentValue()));
michael@0 4145 }
michael@0 4146 else if (eCSSUnit_Initial == lineHeightValue->GetUnit() ||
michael@0 4147 eCSSUnit_System_Font == lineHeightValue->GetUnit()) {
michael@0 4148 text->mLineHeight.SetNormalValue();
michael@0 4149 }
michael@0 4150 else {
michael@0 4151 SetCoord(*lineHeightValue, text->mLineHeight, parentText->mLineHeight,
michael@0 4152 SETCOORD_LEH | SETCOORD_FACTOR | SETCOORD_NORMAL |
michael@0 4153 SETCOORD_UNSET_INHERIT,
michael@0 4154 aContext, mPresContext, canStoreInRuleTree);
michael@0 4155 if (lineHeightValue->IsLengthUnit() &&
michael@0 4156 !lineHeightValue->IsRelativeLengthUnit()) {
michael@0 4157 nscoord lh = nsStyleFont::ZoomText(mPresContext,
michael@0 4158 text->mLineHeight.GetCoordValue());
michael@0 4159
michael@0 4160 canStoreInRuleTree = false;
michael@0 4161 const nsStyleFont *font = aContext->StyleFont();
michael@0 4162 nscoord minimumFontSize = mPresContext->MinFontSize(font->mLanguage);
michael@0 4163
michael@0 4164 if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
michael@0 4165 if (font->mSize != 0) {
michael@0 4166 lh = nscoord(float(lh) * float(font->mFont.size) / float(font->mSize));
michael@0 4167 } else {
michael@0 4168 lh = minimumFontSize;
michael@0 4169 }
michael@0 4170 }
michael@0 4171 text->mLineHeight.SetCoordValue(lh);
michael@0 4172 }
michael@0 4173 }
michael@0 4174
michael@0 4175
michael@0 4176 // text-align: enum, string, pair(enum|string), inherit, initial
michael@0 4177 // NOTE: string is not implemented yet.
michael@0 4178 const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
michael@0 4179 text->mTextAlignTrue = false;
michael@0 4180 if (eCSSUnit_String == textAlignValue->GetUnit()) {
michael@0 4181 NS_NOTYETIMPLEMENTED("align string");
michael@0 4182 } else if (eCSSUnit_Enumerated == textAlignValue->GetUnit() &&
michael@0 4183 NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT ==
michael@0 4184 textAlignValue->GetIntValue()) {
michael@0 4185 canStoreInRuleTree = false;
michael@0 4186 uint8_t parentAlign = parentText->mTextAlign;
michael@0 4187 text->mTextAlign = (NS_STYLE_TEXT_ALIGN_DEFAULT == parentAlign) ?
michael@0 4188 NS_STYLE_TEXT_ALIGN_CENTER : parentAlign;
michael@0 4189 } else {
michael@0 4190 if (eCSSUnit_Pair == textAlignValue->GetUnit()) {
michael@0 4191 // Two values were specified, one must be 'true'.
michael@0 4192 text->mTextAlignTrue = true;
michael@0 4193 const nsCSSValuePair& textAlignValuePair = textAlignValue->GetPairValue();
michael@0 4194 textAlignValue = &textAlignValuePair.mXValue;
michael@0 4195 if (eCSSUnit_Enumerated == textAlignValue->GetUnit()) {
michael@0 4196 if (textAlignValue->GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) {
michael@0 4197 textAlignValue = &textAlignValuePair.mYValue;
michael@0 4198 }
michael@0 4199 } else if (eCSSUnit_String == textAlignValue->GetUnit()) {
michael@0 4200 NS_NOTYETIMPLEMENTED("align string");
michael@0 4201 }
michael@0 4202 } else if (eCSSUnit_Inherit == textAlignValue->GetUnit() ||
michael@0 4203 eCSSUnit_Unset == textAlignValue->GetUnit()) {
michael@0 4204 text->mTextAlignTrue = parentText->mTextAlignTrue;
michael@0 4205 }
michael@0 4206 SetDiscrete(*textAlignValue, text->mTextAlign, canStoreInRuleTree,
michael@0 4207 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 4208 parentText->mTextAlign,
michael@0 4209 NS_STYLE_TEXT_ALIGN_DEFAULT, 0, 0, 0, 0);
michael@0 4210 }
michael@0 4211
michael@0 4212 // text-align-last: enum, pair(enum), inherit, initial
michael@0 4213 const nsCSSValue* textAlignLastValue = aRuleData->ValueForTextAlignLast();
michael@0 4214 text->mTextAlignLastTrue = false;
michael@0 4215 if (eCSSUnit_Pair == textAlignLastValue->GetUnit()) {
michael@0 4216 // Two values were specified, one must be 'true'.
michael@0 4217 text->mTextAlignLastTrue = true;
michael@0 4218 const nsCSSValuePair& textAlignLastValuePair = textAlignLastValue->GetPairValue();
michael@0 4219 textAlignLastValue = &textAlignLastValuePair.mXValue;
michael@0 4220 if (eCSSUnit_Enumerated == textAlignLastValue->GetUnit()) {
michael@0 4221 if (textAlignLastValue->GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) {
michael@0 4222 textAlignLastValue = &textAlignLastValuePair.mYValue;
michael@0 4223 }
michael@0 4224 }
michael@0 4225 } else if (eCSSUnit_Inherit == textAlignLastValue->GetUnit() ||
michael@0 4226 eCSSUnit_Unset == textAlignLastValue->GetUnit()) {
michael@0 4227 text->mTextAlignLastTrue = parentText->mTextAlignLastTrue;
michael@0 4228 }
michael@0 4229 SetDiscrete(*textAlignLastValue, text->mTextAlignLast,
michael@0 4230 canStoreInRuleTree,
michael@0 4231 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 4232 parentText->mTextAlignLast,
michael@0 4233 NS_STYLE_TEXT_ALIGN_AUTO, 0, 0, 0, 0);
michael@0 4234
michael@0 4235 // text-indent: length, percent, calc, inherit, initial
michael@0 4236 SetCoord(*aRuleData->ValueForTextIndent(), text->mTextIndent, parentText->mTextIndent,
michael@0 4237 SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
michael@0 4238 SETCOORD_UNSET_INHERIT,
michael@0 4239 aContext, mPresContext, canStoreInRuleTree);
michael@0 4240
michael@0 4241 // text-transform: enum, inherit, initial
michael@0 4242 SetDiscrete(*aRuleData->ValueForTextTransform(), text->mTextTransform, canStoreInRuleTree,
michael@0 4243 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 4244 parentText->mTextTransform,
michael@0 4245 NS_STYLE_TEXT_TRANSFORM_NONE, 0, 0, 0, 0);
michael@0 4246
michael@0 4247 // white-space: enum, inherit, initial
michael@0 4248 SetDiscrete(*aRuleData->ValueForWhiteSpace(), text->mWhiteSpace, canStoreInRuleTree,
michael@0 4249 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 4250 parentText->mWhiteSpace,
michael@0 4251 NS_STYLE_WHITESPACE_NORMAL, 0, 0, 0, 0);
michael@0 4252
michael@0 4253 // word-break: enum, inherit, initial
michael@0 4254 SetDiscrete(*aRuleData->ValueForWordBreak(), text->mWordBreak, canStoreInRuleTree,
michael@0 4255 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 4256 parentText->mWordBreak,
michael@0 4257 NS_STYLE_WORDBREAK_NORMAL, 0, 0, 0, 0);
michael@0 4258
michael@0 4259 // word-spacing: normal, length, inherit
michael@0 4260 nsStyleCoord tempCoord;
michael@0 4261 const nsCSSValue* wordSpacingValue = aRuleData->ValueForWordSpacing();
michael@0 4262 if (SetCoord(*wordSpacingValue, tempCoord,
michael@0 4263 nsStyleCoord(parentText->mWordSpacing,
michael@0 4264 nsStyleCoord::CoordConstructor),
michael@0 4265 SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
michael@0 4266 SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INHERIT,
michael@0 4267 aContext, mPresContext, canStoreInRuleTree)) {
michael@0 4268 if (tempCoord.GetUnit() == eStyleUnit_Coord) {
michael@0 4269 text->mWordSpacing = tempCoord.GetCoordValue();
michael@0 4270 } else if (tempCoord.GetUnit() == eStyleUnit_Normal) {
michael@0 4271 text->mWordSpacing = 0;
michael@0 4272 } else {
michael@0 4273 NS_NOTREACHED("unexpected unit");
michael@0 4274 }
michael@0 4275 } else {
michael@0 4276 NS_ASSERTION(wordSpacingValue->GetUnit() == eCSSUnit_Null,
michael@0 4277 "unexpected unit");
michael@0 4278 }
michael@0 4279
michael@0 4280 // word-wrap: enum, inherit, initial
michael@0 4281 SetDiscrete(*aRuleData->ValueForWordWrap(), text->mWordWrap, canStoreInRuleTree,
michael@0 4282 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 4283 parentText->mWordWrap,
michael@0 4284 NS_STYLE_WORDWRAP_NORMAL, 0, 0, 0, 0);
michael@0 4285
michael@0 4286 // hyphens: enum, inherit, initial
michael@0 4287 SetDiscrete(*aRuleData->ValueForHyphens(), text->mHyphens, canStoreInRuleTree,
michael@0 4288 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 4289 parentText->mHyphens,
michael@0 4290 NS_STYLE_HYPHENS_MANUAL, 0, 0, 0, 0);
michael@0 4291
michael@0 4292 // text-size-adjust: none, auto, inherit, initial
michael@0 4293 SetDiscrete(*aRuleData->ValueForTextSizeAdjust(), text->mTextSizeAdjust,
michael@0 4294 canStoreInRuleTree,
michael@0 4295 SETDSC_NONE | SETDSC_AUTO | SETDSC_UNSET_INHERIT,
michael@0 4296 parentText->mTextSizeAdjust,
michael@0 4297 NS_STYLE_TEXT_SIZE_ADJUST_AUTO, // initial value
michael@0 4298 NS_STYLE_TEXT_SIZE_ADJUST_AUTO, // auto value
michael@0 4299 NS_STYLE_TEXT_SIZE_ADJUST_NONE, // none value
michael@0 4300 0, 0);
michael@0 4301
michael@0 4302 // -moz-text-discard: enum, inherit, initial
michael@0 4303 SetDiscrete(*aRuleData->ValueForControlCharacterVisibility(),
michael@0 4304 text->mControlCharacterVisibility,
michael@0 4305 canStoreInRuleTree,
michael@0 4306 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 4307 parentText->mControlCharacterVisibility,
michael@0 4308 NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN, 0, 0, 0, 0);
michael@0 4309
michael@0 4310 // text-orientation: enum, inherit, initial
michael@0 4311 SetDiscrete(*aRuleData->ValueForTextOrientation(), text->mTextOrientation,
michael@0 4312 canStoreInRuleTree,
michael@0 4313 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 4314 parentText->mTextOrientation,
michael@0 4315 NS_STYLE_TEXT_ORIENTATION_AUTO, 0, 0, 0, 0);
michael@0 4316
michael@0 4317 // text-combine-upright: enum, inherit, initial
michael@0 4318 SetDiscrete(*aRuleData->ValueForTextCombineUpright(),
michael@0 4319 text->mTextCombineUpright,
michael@0 4320 canStoreInRuleTree,
michael@0 4321 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 4322 parentText->mTextCombineUpright,
michael@0 4323 NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE, 0, 0, 0, 0);
michael@0 4324
michael@0 4325 COMPUTE_END_INHERITED(Text, text)
michael@0 4326 }
michael@0 4327
michael@0 4328 const void*
michael@0 4329 nsRuleNode::ComputeTextResetData(void* aStartStruct,
michael@0 4330 const nsRuleData* aRuleData,
michael@0 4331 nsStyleContext* aContext,
michael@0 4332 nsRuleNode* aHighestNode,
michael@0 4333 const RuleDetail aRuleDetail,
michael@0 4334 const bool aCanStoreInRuleTree)
michael@0 4335 {
michael@0 4336 COMPUTE_START_RESET(TextReset, (), text, parentText)
michael@0 4337
michael@0 4338 // vertical-align: enum, length, percent, calc, inherit
michael@0 4339 const nsCSSValue* verticalAlignValue = aRuleData->ValueForVerticalAlign();
michael@0 4340 if (!SetCoord(*verticalAlignValue, text->mVerticalAlign,
michael@0 4341 parentText->mVerticalAlign,
michael@0 4342 SETCOORD_LPH | SETCOORD_ENUMERATED | SETCOORD_STORE_CALC,
michael@0 4343 aContext, mPresContext, canStoreInRuleTree)) {
michael@0 4344 if (eCSSUnit_Initial == verticalAlignValue->GetUnit() ||
michael@0 4345 eCSSUnit_Unset == verticalAlignValue->GetUnit()) {
michael@0 4346 text->mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE,
michael@0 4347 eStyleUnit_Enumerated);
michael@0 4348 }
michael@0 4349 }
michael@0 4350
michael@0 4351 // text-decoration-line: enum (bit field), inherit, initial
michael@0 4352 const nsCSSValue* decorationLineValue =
michael@0 4353 aRuleData->ValueForTextDecorationLine();
michael@0 4354 if (eCSSUnit_Enumerated == decorationLineValue->GetUnit()) {
michael@0 4355 int32_t td = decorationLineValue->GetIntValue();
michael@0 4356 text->mTextDecorationLine = td;
michael@0 4357 if (td & NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS) {
michael@0 4358 bool underlineLinks =
michael@0 4359 mPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
michael@0 4360 if (underlineLinks) {
michael@0 4361 text->mTextDecorationLine |= NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
michael@0 4362 }
michael@0 4363 else {
michael@0 4364 text->mTextDecorationLine &= ~NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
michael@0 4365 }
michael@0 4366 }
michael@0 4367 } else if (eCSSUnit_Inherit == decorationLineValue->GetUnit()) {
michael@0 4368 canStoreInRuleTree = false;
michael@0 4369 text->mTextDecorationLine = parentText->mTextDecorationLine;
michael@0 4370 } else if (eCSSUnit_Initial == decorationLineValue->GetUnit() ||
michael@0 4371 eCSSUnit_Unset == decorationLineValue->GetUnit()) {
michael@0 4372 text->mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE;
michael@0 4373 }
michael@0 4374
michael@0 4375 // text-decoration-color: color, string, enum, inherit, initial
michael@0 4376 const nsCSSValue* decorationColorValue =
michael@0 4377 aRuleData->ValueForTextDecorationColor();
michael@0 4378 nscolor decorationColor;
michael@0 4379 if (eCSSUnit_Inherit == decorationColorValue->GetUnit()) {
michael@0 4380 canStoreInRuleTree = false;
michael@0 4381 if (parentContext) {
michael@0 4382 bool isForeground;
michael@0 4383 parentText->GetDecorationColor(decorationColor, isForeground);
michael@0 4384 if (isForeground) {
michael@0 4385 text->SetDecorationColor(parentContext->StyleColor()->mColor);
michael@0 4386 } else {
michael@0 4387 text->SetDecorationColor(decorationColor);
michael@0 4388 }
michael@0 4389 } else {
michael@0 4390 text->SetDecorationColorToForeground();
michael@0 4391 }
michael@0 4392 }
michael@0 4393 else if (eCSSUnit_EnumColor == decorationColorValue->GetUnit() &&
michael@0 4394 decorationColorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
michael@0 4395 text->SetDecorationColorToForeground();
michael@0 4396 }
michael@0 4397 else if (SetColor(*decorationColorValue, 0, mPresContext, aContext,
michael@0 4398 decorationColor, canStoreInRuleTree)) {
michael@0 4399 text->SetDecorationColor(decorationColor);
michael@0 4400 }
michael@0 4401 else if (eCSSUnit_Initial == decorationColorValue->GetUnit() ||
michael@0 4402 eCSSUnit_Unset == decorationColorValue->GetUnit() ||
michael@0 4403 eCSSUnit_Enumerated == decorationColorValue->GetUnit()) {
michael@0 4404 NS_ABORT_IF_FALSE(eCSSUnit_Enumerated != decorationColorValue->GetUnit() ||
michael@0 4405 decorationColorValue->GetIntValue() ==
michael@0 4406 NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR,
michael@0 4407 "unexpected enumerated value");
michael@0 4408 text->SetDecorationColorToForeground();
michael@0 4409 }
michael@0 4410
michael@0 4411 // text-decoration-style: enum, inherit, initial
michael@0 4412 const nsCSSValue* decorationStyleValue =
michael@0 4413 aRuleData->ValueForTextDecorationStyle();
michael@0 4414 if (eCSSUnit_Enumerated == decorationStyleValue->GetUnit()) {
michael@0 4415 text->SetDecorationStyle(decorationStyleValue->GetIntValue());
michael@0 4416 } else if (eCSSUnit_Inherit == decorationStyleValue->GetUnit()) {
michael@0 4417 text->SetDecorationStyle(parentText->GetDecorationStyle());
michael@0 4418 canStoreInRuleTree = false;
michael@0 4419 } else if (eCSSUnit_Initial == decorationStyleValue->GetUnit() ||
michael@0 4420 eCSSUnit_Unset == decorationStyleValue->GetUnit()) {
michael@0 4421 text->SetDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID);
michael@0 4422 }
michael@0 4423
michael@0 4424 // text-overflow: enum, string, pair(enum|string), inherit, initial
michael@0 4425 const nsCSSValue* textOverflowValue =
michael@0 4426 aRuleData->ValueForTextOverflow();
michael@0 4427 if (eCSSUnit_Initial == textOverflowValue->GetUnit() ||
michael@0 4428 eCSSUnit_Unset == textOverflowValue->GetUnit()) {
michael@0 4429 text->mTextOverflow = nsStyleTextOverflow();
michael@0 4430 } else if (eCSSUnit_Inherit == textOverflowValue->GetUnit()) {
michael@0 4431 canStoreInRuleTree = false;
michael@0 4432 text->mTextOverflow = parentText->mTextOverflow;
michael@0 4433 } else if (eCSSUnit_Enumerated == textOverflowValue->GetUnit()) {
michael@0 4434 // A single enumerated value.
michael@0 4435 SetDiscrete(*textOverflowValue, text->mTextOverflow.mRight.mType,
michael@0 4436 canStoreInRuleTree,
michael@0 4437 SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
michael@0 4438 NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
michael@0 4439 text->mTextOverflow.mRight.mString.Truncate();
michael@0 4440 text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
michael@0 4441 text->mTextOverflow.mLeft.mString.Truncate();
michael@0 4442 text->mTextOverflow.mLogicalDirections = true;
michael@0 4443 } else if (eCSSUnit_String == textOverflowValue->GetUnit()) {
michael@0 4444 // A single string value.
michael@0 4445 text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
michael@0 4446 textOverflowValue->GetStringValue(text->mTextOverflow.mRight.mString);
michael@0 4447 text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
michael@0 4448 text->mTextOverflow.mLeft.mString.Truncate();
michael@0 4449 text->mTextOverflow.mLogicalDirections = true;
michael@0 4450 } else if (eCSSUnit_Pair == textOverflowValue->GetUnit()) {
michael@0 4451 // Two values were specified.
michael@0 4452 text->mTextOverflow.mLogicalDirections = false;
michael@0 4453 const nsCSSValuePair& textOverflowValuePair =
michael@0 4454 textOverflowValue->GetPairValue();
michael@0 4455
michael@0 4456 const nsCSSValue *textOverflowLeftValue = &textOverflowValuePair.mXValue;
michael@0 4457 if (eCSSUnit_Enumerated == textOverflowLeftValue->GetUnit()) {
michael@0 4458 SetDiscrete(*textOverflowLeftValue, text->mTextOverflow.mLeft.mType,
michael@0 4459 canStoreInRuleTree,
michael@0 4460 SETDSC_ENUMERATED, parentText->mTextOverflow.mLeft.mType,
michael@0 4461 NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
michael@0 4462 text->mTextOverflow.mLeft.mString.Truncate();
michael@0 4463 } else if (eCSSUnit_String == textOverflowLeftValue->GetUnit()) {
michael@0 4464 textOverflowLeftValue->GetStringValue(text->mTextOverflow.mLeft.mString);
michael@0 4465 text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
michael@0 4466 }
michael@0 4467
michael@0 4468 const nsCSSValue *textOverflowRightValue = &textOverflowValuePair.mYValue;
michael@0 4469 if (eCSSUnit_Enumerated == textOverflowRightValue->GetUnit()) {
michael@0 4470 SetDiscrete(*textOverflowRightValue, text->mTextOverflow.mRight.mType,
michael@0 4471 canStoreInRuleTree,
michael@0 4472 SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
michael@0 4473 NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
michael@0 4474 text->mTextOverflow.mRight.mString.Truncate();
michael@0 4475 } else if (eCSSUnit_String == textOverflowRightValue->GetUnit()) {
michael@0 4476 textOverflowRightValue->GetStringValue(text->mTextOverflow.mRight.mString);
michael@0 4477 text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
michael@0 4478 }
michael@0 4479 }
michael@0 4480
michael@0 4481 // unicode-bidi: enum, inherit, initial
michael@0 4482 SetDiscrete(*aRuleData->ValueForUnicodeBidi(), text->mUnicodeBidi, canStoreInRuleTree,
michael@0 4483 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 4484 parentText->mUnicodeBidi,
michael@0 4485 NS_STYLE_UNICODE_BIDI_NORMAL, 0, 0, 0, 0);
michael@0 4486
michael@0 4487 COMPUTE_END_RESET(TextReset, text)
michael@0 4488 }
michael@0 4489
michael@0 4490 const void*
michael@0 4491 nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
michael@0 4492 const nsRuleData* aRuleData,
michael@0 4493 nsStyleContext* aContext,
michael@0 4494 nsRuleNode* aHighestNode,
michael@0 4495 const RuleDetail aRuleDetail,
michael@0 4496 const bool aCanStoreInRuleTree)
michael@0 4497 {
michael@0 4498 COMPUTE_START_INHERITED(UserInterface, (), ui, parentUI)
michael@0 4499
michael@0 4500 // cursor: enum, url, inherit
michael@0 4501 const nsCSSValue* cursorValue = aRuleData->ValueForCursor();
michael@0 4502 nsCSSUnit cursorUnit = cursorValue->GetUnit();
michael@0 4503 if (cursorUnit != eCSSUnit_Null) {
michael@0 4504 delete [] ui->mCursorArray;
michael@0 4505 ui->mCursorArray = nullptr;
michael@0 4506 ui->mCursorArrayLength = 0;
michael@0 4507
michael@0 4508 if (cursorUnit == eCSSUnit_Inherit ||
michael@0 4509 cursorUnit == eCSSUnit_Unset) {
michael@0 4510 canStoreInRuleTree = false;
michael@0 4511 ui->mCursor = parentUI->mCursor;
michael@0 4512 ui->CopyCursorArrayFrom(*parentUI);
michael@0 4513 }
michael@0 4514 else if (cursorUnit == eCSSUnit_Initial) {
michael@0 4515 ui->mCursor = NS_STYLE_CURSOR_AUTO;
michael@0 4516 }
michael@0 4517 else {
michael@0 4518 // The parser will never create a list that is *all* URL values --
michael@0 4519 // that's invalid.
michael@0 4520 NS_ABORT_IF_FALSE(cursorUnit == eCSSUnit_List ||
michael@0 4521 cursorUnit == eCSSUnit_ListDep,
michael@0 4522 nsPrintfCString("unrecognized cursor unit %d",
michael@0 4523 cursorUnit).get());
michael@0 4524 const nsCSSValueList* list = cursorValue->GetListValue();
michael@0 4525 const nsCSSValueList* list2 = list;
michael@0 4526 nsIDocument* doc = aContext->PresContext()->Document();
michael@0 4527 uint32_t arrayLength = 0;
michael@0 4528 for ( ; list->mValue.GetUnit() == eCSSUnit_Array; list = list->mNext)
michael@0 4529 if (list->mValue.GetArrayValue()->Item(0).GetImageValue(doc))
michael@0 4530 ++arrayLength;
michael@0 4531
michael@0 4532 if (arrayLength != 0) {
michael@0 4533 ui->mCursorArray = new nsCursorImage[arrayLength];
michael@0 4534 if (ui->mCursorArray) {
michael@0 4535 ui->mCursorArrayLength = arrayLength;
michael@0 4536
michael@0 4537 for (nsCursorImage *item = ui->mCursorArray;
michael@0 4538 list2->mValue.GetUnit() == eCSSUnit_Array;
michael@0 4539 list2 = list2->mNext) {
michael@0 4540 nsCSSValue::Array *arr = list2->mValue.GetArrayValue();
michael@0 4541 imgIRequest *req = arr->Item(0).GetImageValue(doc);
michael@0 4542 if (req) {
michael@0 4543 item->SetImage(req);
michael@0 4544 if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
michael@0 4545 item->mHaveHotspot = true;
michael@0 4546 item->mHotspotX = arr->Item(1).GetFloatValue(),
michael@0 4547 item->mHotspotY = arr->Item(2).GetFloatValue();
michael@0 4548 }
michael@0 4549 ++item;
michael@0 4550 }
michael@0 4551 }
michael@0 4552 }
michael@0 4553 }
michael@0 4554
michael@0 4555 NS_ASSERTION(list, "Must have non-array value at the end");
michael@0 4556 NS_ASSERTION(list->mValue.GetUnit() == eCSSUnit_Enumerated,
michael@0 4557 "Unexpected fallback value at end of cursor list");
michael@0 4558 ui->mCursor = list->mValue.GetIntValue();
michael@0 4559 }
michael@0 4560 }
michael@0 4561
michael@0 4562 // user-input: enum, inherit, initial
michael@0 4563 SetDiscrete(*aRuleData->ValueForUserInput(),
michael@0 4564 ui->mUserInput, canStoreInRuleTree,
michael@0 4565 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 4566 parentUI->mUserInput,
michael@0 4567 NS_STYLE_USER_INPUT_AUTO, 0, 0, 0, 0);
michael@0 4568
michael@0 4569 // user-modify: enum, inherit, initial
michael@0 4570 SetDiscrete(*aRuleData->ValueForUserModify(),
michael@0 4571 ui->mUserModify, canStoreInRuleTree,
michael@0 4572 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 4573 parentUI->mUserModify,
michael@0 4574 NS_STYLE_USER_MODIFY_READ_ONLY,
michael@0 4575 0, 0, 0, 0);
michael@0 4576
michael@0 4577 // user-focus: enum, inherit, initial
michael@0 4578 SetDiscrete(*aRuleData->ValueForUserFocus(),
michael@0 4579 ui->mUserFocus, canStoreInRuleTree,
michael@0 4580 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 4581 parentUI->mUserFocus,
michael@0 4582 NS_STYLE_USER_FOCUS_NONE, 0, 0, 0, 0);
michael@0 4583
michael@0 4584 COMPUTE_END_INHERITED(UserInterface, ui)
michael@0 4585 }
michael@0 4586
michael@0 4587 const void*
michael@0 4588 nsRuleNode::ComputeUIResetData(void* aStartStruct,
michael@0 4589 const nsRuleData* aRuleData,
michael@0 4590 nsStyleContext* aContext,
michael@0 4591 nsRuleNode* aHighestNode,
michael@0 4592 const RuleDetail aRuleDetail,
michael@0 4593 const bool aCanStoreInRuleTree)
michael@0 4594 {
michael@0 4595 COMPUTE_START_RESET(UIReset, (), ui, parentUI)
michael@0 4596
michael@0 4597 // user-select: enum, inherit, initial
michael@0 4598 SetDiscrete(*aRuleData->ValueForUserSelect(),
michael@0 4599 ui->mUserSelect, canStoreInRuleTree,
michael@0 4600 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 4601 parentUI->mUserSelect,
michael@0 4602 NS_STYLE_USER_SELECT_AUTO, 0, 0, 0, 0);
michael@0 4603
michael@0 4604 // ime-mode: enum, inherit, initial
michael@0 4605 SetDiscrete(*aRuleData->ValueForImeMode(),
michael@0 4606 ui->mIMEMode, canStoreInRuleTree,
michael@0 4607 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 4608 parentUI->mIMEMode,
michael@0 4609 NS_STYLE_IME_MODE_AUTO, 0, 0, 0, 0);
michael@0 4610
michael@0 4611 // force-broken-image-icons: integer, inherit, initial
michael@0 4612 SetDiscrete(*aRuleData->ValueForForceBrokenImageIcon(),
michael@0 4613 ui->mForceBrokenImageIcon,
michael@0 4614 canStoreInRuleTree,
michael@0 4615 SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
michael@0 4616 parentUI->mForceBrokenImageIcon,
michael@0 4617 0, 0, 0, 0, 0);
michael@0 4618
michael@0 4619 // -moz-window-shadow: enum, inherit, initial
michael@0 4620 SetDiscrete(*aRuleData->ValueForWindowShadow(),
michael@0 4621 ui->mWindowShadow, canStoreInRuleTree,
michael@0 4622 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 4623 parentUI->mWindowShadow,
michael@0 4624 NS_STYLE_WINDOW_SHADOW_DEFAULT, 0, 0, 0, 0);
michael@0 4625
michael@0 4626 COMPUTE_END_RESET(UIReset, ui)
michael@0 4627 }
michael@0 4628
michael@0 4629 // Information about each transition or animation property that is
michael@0 4630 // constant.
michael@0 4631 struct TransitionPropInfo {
michael@0 4632 nsCSSProperty property;
michael@0 4633 // Location of the count of the property's computed value.
michael@0 4634 uint32_t nsStyleDisplay::* sdCount;
michael@0 4635 };
michael@0 4636
michael@0 4637 // Each property's index in this array must match its index in the
michael@0 4638 // mutable array |transitionPropData| below.
michael@0 4639 static const TransitionPropInfo transitionPropInfo[4] = {
michael@0 4640 { eCSSProperty_transition_delay,
michael@0 4641 &nsStyleDisplay::mTransitionDelayCount },
michael@0 4642 { eCSSProperty_transition_duration,
michael@0 4643 &nsStyleDisplay::mTransitionDurationCount },
michael@0 4644 { eCSSProperty_transition_property,
michael@0 4645 &nsStyleDisplay::mTransitionPropertyCount },
michael@0 4646 { eCSSProperty_transition_timing_function,
michael@0 4647 &nsStyleDisplay::mTransitionTimingFunctionCount },
michael@0 4648 };
michael@0 4649
michael@0 4650 // Each property's index in this array must match its index in the
michael@0 4651 // mutable array |animationPropData| below.
michael@0 4652 static const TransitionPropInfo animationPropInfo[8] = {
michael@0 4653 { eCSSProperty_animation_delay,
michael@0 4654 &nsStyleDisplay::mAnimationDelayCount },
michael@0 4655 { eCSSProperty_animation_duration,
michael@0 4656 &nsStyleDisplay::mAnimationDurationCount },
michael@0 4657 { eCSSProperty_animation_name,
michael@0 4658 &nsStyleDisplay::mAnimationNameCount },
michael@0 4659 { eCSSProperty_animation_timing_function,
michael@0 4660 &nsStyleDisplay::mAnimationTimingFunctionCount },
michael@0 4661 { eCSSProperty_animation_direction,
michael@0 4662 &nsStyleDisplay::mAnimationDirectionCount },
michael@0 4663 { eCSSProperty_animation_fill_mode,
michael@0 4664 &nsStyleDisplay::mAnimationFillModeCount },
michael@0 4665 { eCSSProperty_animation_play_state,
michael@0 4666 &nsStyleDisplay::mAnimationPlayStateCount },
michael@0 4667 { eCSSProperty_animation_iteration_count,
michael@0 4668 &nsStyleDisplay::mAnimationIterationCountCount },
michael@0 4669 };
michael@0 4670
michael@0 4671 // Information about each transition or animation property that changes
michael@0 4672 // during ComputeDisplayData.
michael@0 4673 struct TransitionPropData {
michael@0 4674 const nsCSSValueList *list;
michael@0 4675 nsCSSUnit unit;
michael@0 4676 uint32_t num;
michael@0 4677 };
michael@0 4678
michael@0 4679 static uint32_t
michael@0 4680 CountTransitionProps(const TransitionPropInfo* aInfo,
michael@0 4681 TransitionPropData* aData,
michael@0 4682 size_t aLength,
michael@0 4683 nsStyleDisplay* aDisplay,
michael@0 4684 const nsStyleDisplay* aParentDisplay,
michael@0 4685 const nsRuleData* aRuleData,
michael@0 4686 bool& aCanStoreInRuleTree)
michael@0 4687 {
michael@0 4688 // The four transition properties or eight animation properties are
michael@0 4689 // stored in nsCSSDisplay in a single array for all properties. The
michael@0 4690 // number of transitions is equal to the number of items in the
michael@0 4691 // longest property's value. Properties that have fewer values than
michael@0 4692 // the longest are filled in by repeating the list. However, this
michael@0 4693 // repetition does not extend the computed value of that particular
michael@0 4694 // property (for purposes of inheritance, or, in our code, for when
michael@0 4695 // other properties are overridden by a more specific rule).
michael@0 4696
michael@0 4697 // But actually, since the spec isn't clear yet, we'll fully compute
michael@0 4698 // all of them (so we can switch easily later), but only care about
michael@0 4699 // the ones up to the number of items for 'transition-property', per
michael@0 4700 // http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html .
michael@0 4701
michael@0 4702 // Transitions are difficult to handle correctly because of this. For
michael@0 4703 // example, we need to handle scenarios such as:
michael@0 4704 // * a more general rule specifies transition-property: a, b, c;
michael@0 4705 // * a more specific rule overrides as transition-property: d;
michael@0 4706 //
michael@0 4707 // If only the general rule applied, we would fill in the extra
michael@0 4708 // properties (duration, delay, etc) with initial values to create 3
michael@0 4709 // fully-specified transitions. But when the more specific rule
michael@0 4710 // applies, we should only create a single transition. In order to do
michael@0 4711 // this we need to remember which properties were explicitly specified
michael@0 4712 // and which ones were just filled in with initial values to get a
michael@0 4713 // fully-specified transition, which we do by remembering the number
michael@0 4714 // of values for each property.
michael@0 4715
michael@0 4716 uint32_t numTransitions = 0;
michael@0 4717 for (size_t i = 0; i < aLength; ++i) {
michael@0 4718 const TransitionPropInfo& info = aInfo[i];
michael@0 4719 TransitionPropData& data = aData[i];
michael@0 4720
michael@0 4721 // cache whether any of the properties are specified as 'inherit' so
michael@0 4722 // we can use it below
michael@0 4723
michael@0 4724 const nsCSSValue& value = *aRuleData->ValueFor(info.property);
michael@0 4725 data.unit = value.GetUnit();
michael@0 4726 data.list = (value.GetUnit() == eCSSUnit_List ||
michael@0 4727 value.GetUnit() == eCSSUnit_ListDep)
michael@0 4728 ? value.GetListValue() : nullptr;
michael@0 4729
michael@0 4730 // General algorithm to determine how many total transitions we need
michael@0 4731 // to build. For each property:
michael@0 4732 // - if there is no value specified in for the property in
michael@0 4733 // displayData, use the values from the start struct, but only if
michael@0 4734 // they were explicitly specified
michael@0 4735 // - if there is a value specified for the property in displayData:
michael@0 4736 // - if the value is 'inherit', count the number of values for
michael@0 4737 // that property are specified by the parent, but only those
michael@0 4738 // that were explicitly specified
michael@0 4739 // - otherwise, count the number of values specified in displayData
michael@0 4740
michael@0 4741
michael@0 4742 // calculate number of elements
michael@0 4743 if (data.unit == eCSSUnit_Inherit) {
michael@0 4744 data.num = aParentDisplay->*(info.sdCount);
michael@0 4745 aCanStoreInRuleTree = false;
michael@0 4746 } else if (data.list) {
michael@0 4747 data.num = ListLength(data.list);
michael@0 4748 } else {
michael@0 4749 data.num = aDisplay->*(info.sdCount);
michael@0 4750 }
michael@0 4751 if (data.num > numTransitions)
michael@0 4752 numTransitions = data.num;
michael@0 4753 }
michael@0 4754
michael@0 4755 return numTransitions;
michael@0 4756 }
michael@0 4757
michael@0 4758 static void
michael@0 4759 ComputeTimingFunction(const nsCSSValue& aValue, nsTimingFunction& aResult)
michael@0 4760 {
michael@0 4761 switch (aValue.GetUnit()) {
michael@0 4762 case eCSSUnit_Enumerated:
michael@0 4763 aResult = nsTimingFunction(aValue.GetIntValue());
michael@0 4764 break;
michael@0 4765 case eCSSUnit_Cubic_Bezier:
michael@0 4766 {
michael@0 4767 nsCSSValue::Array* array = aValue.GetArrayValue();
michael@0 4768 NS_ASSERTION(array && array->Count() == 4,
michael@0 4769 "Need 4 control points");
michael@0 4770 aResult = nsTimingFunction(array->Item(0).GetFloatValue(),
michael@0 4771 array->Item(1).GetFloatValue(),
michael@0 4772 array->Item(2).GetFloatValue(),
michael@0 4773 array->Item(3).GetFloatValue());
michael@0 4774 }
michael@0 4775 break;
michael@0 4776 case eCSSUnit_Steps:
michael@0 4777 {
michael@0 4778 nsCSSValue::Array* array = aValue.GetArrayValue();
michael@0 4779 NS_ASSERTION(array && array->Count() == 2,
michael@0 4780 "Need 2 items");
michael@0 4781 NS_ASSERTION(array->Item(0).GetUnit() == eCSSUnit_Integer,
michael@0 4782 "unexpected first value");
michael@0 4783 NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Enumerated &&
michael@0 4784 (array->Item(1).GetIntValue() ==
michael@0 4785 NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START ||
michael@0 4786 array->Item(1).GetIntValue() ==
michael@0 4787 NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END),
michael@0 4788 "unexpected second value");
michael@0 4789 nsTimingFunction::Type type =
michael@0 4790 (array->Item(1).GetIntValue() ==
michael@0 4791 NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END)
michael@0 4792 ? nsTimingFunction::StepEnd : nsTimingFunction::StepStart;
michael@0 4793 aResult = nsTimingFunction(type, array->Item(0).GetIntValue());
michael@0 4794 }
michael@0 4795 break;
michael@0 4796 default:
michael@0 4797 NS_NOTREACHED("Invalid transition property unit");
michael@0 4798 }
michael@0 4799 }
michael@0 4800
michael@0 4801 const void*
michael@0 4802 nsRuleNode::ComputeDisplayData(void* aStartStruct,
michael@0 4803 const nsRuleData* aRuleData,
michael@0 4804 nsStyleContext* aContext,
michael@0 4805 nsRuleNode* aHighestNode,
michael@0 4806 const RuleDetail aRuleDetail,
michael@0 4807 const bool aCanStoreInRuleTree)
michael@0 4808 {
michael@0 4809 COMPUTE_START_RESET(Display, (), display, parentDisplay)
michael@0 4810
michael@0 4811 // We may have ended up with aStartStruct's values of mDisplay and
michael@0 4812 // mFloats, but those may not be correct if our style data overrides
michael@0 4813 // its position or float properties. Reset to mOriginalDisplay and
michael@0 4814 // mOriginalFloats; it if turns out we still need the display/floats
michael@0 4815 // adjustments we'll do them below.
michael@0 4816 display->mDisplay = display->mOriginalDisplay;
michael@0 4817 display->mFloats = display->mOriginalFloats;
michael@0 4818
michael@0 4819 // Each property's index in this array must match its index in the
michael@0 4820 // const array |transitionPropInfo| above.
michael@0 4821 TransitionPropData transitionPropData[4];
michael@0 4822 TransitionPropData& delay = transitionPropData[0];
michael@0 4823 TransitionPropData& duration = transitionPropData[1];
michael@0 4824 TransitionPropData& property = transitionPropData[2];
michael@0 4825 TransitionPropData& timingFunction = transitionPropData[3];
michael@0 4826
michael@0 4827 #define FOR_ALL_TRANSITION_PROPS(var_) \
michael@0 4828 for (uint32_t var_ = 0; var_ < 4; ++var_)
michael@0 4829
michael@0 4830 // CSS Transitions
michael@0 4831 uint32_t numTransitions =
michael@0 4832 CountTransitionProps(transitionPropInfo, transitionPropData,
michael@0 4833 ArrayLength(transitionPropData),
michael@0 4834 display, parentDisplay, aRuleData,
michael@0 4835 canStoreInRuleTree);
michael@0 4836
michael@0 4837 display->mTransitions.SetLength(numTransitions);
michael@0 4838
michael@0 4839 FOR_ALL_TRANSITION_PROPS(p) {
michael@0 4840 const TransitionPropInfo& i = transitionPropInfo[p];
michael@0 4841 TransitionPropData& d = transitionPropData[p];
michael@0 4842
michael@0 4843 display->*(i.sdCount) = d.num;
michael@0 4844 }
michael@0 4845
michael@0 4846 // Fill in the transitions we just allocated with the appropriate values.
michael@0 4847 for (uint32_t i = 0; i < numTransitions; ++i) {
michael@0 4848 nsTransition *transition = &display->mTransitions[i];
michael@0 4849
michael@0 4850 if (i >= delay.num) {
michael@0 4851 transition->SetDelay(display->mTransitions[i % delay.num].GetDelay());
michael@0 4852 } else if (delay.unit == eCSSUnit_Inherit) {
michael@0 4853 // FIXME (Bug 522599) (for all transition properties): write a test that
michael@0 4854 // detects when this was wrong for i >= delay.num if parent had
michael@0 4855 // count for this property not equal to length
michael@0 4856 NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionDelayCount,
michael@0 4857 "delay.num computed incorrectly");
michael@0 4858 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
michael@0 4859 "should have made canStoreInRuleTree false above");
michael@0 4860 transition->SetDelay(parentDisplay->mTransitions[i].GetDelay());
michael@0 4861 } else if (delay.unit == eCSSUnit_Initial ||
michael@0 4862 delay.unit == eCSSUnit_Unset) {
michael@0 4863 transition->SetDelay(0.0);
michael@0 4864 } else if (delay.list) {
michael@0 4865 switch (delay.list->mValue.GetUnit()) {
michael@0 4866 case eCSSUnit_Seconds:
michael@0 4867 transition->SetDelay(PR_MSEC_PER_SEC *
michael@0 4868 delay.list->mValue.GetFloatValue());
michael@0 4869 break;
michael@0 4870 case eCSSUnit_Milliseconds:
michael@0 4871 transition->SetDelay(delay.list->mValue.GetFloatValue());
michael@0 4872 break;
michael@0 4873 default:
michael@0 4874 NS_NOTREACHED("Invalid delay unit");
michael@0 4875 }
michael@0 4876 }
michael@0 4877
michael@0 4878 if (i >= duration.num) {
michael@0 4879 transition->SetDuration(
michael@0 4880 display->mTransitions[i % duration.num].GetDuration());
michael@0 4881 } else if (duration.unit == eCSSUnit_Inherit) {
michael@0 4882 NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionDurationCount,
michael@0 4883 "duration.num computed incorrectly");
michael@0 4884 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
michael@0 4885 "should have made canStoreInRuleTree false above");
michael@0 4886 transition->SetDuration(parentDisplay->mTransitions[i].GetDuration());
michael@0 4887 } else if (duration.unit == eCSSUnit_Initial ||
michael@0 4888 duration.unit == eCSSUnit_Unset) {
michael@0 4889 transition->SetDuration(0.0);
michael@0 4890 } else if (duration.list) {
michael@0 4891 switch (duration.list->mValue.GetUnit()) {
michael@0 4892 case eCSSUnit_Seconds:
michael@0 4893 transition->SetDuration(PR_MSEC_PER_SEC *
michael@0 4894 duration.list->mValue.GetFloatValue());
michael@0 4895 break;
michael@0 4896 case eCSSUnit_Milliseconds:
michael@0 4897 transition->SetDuration(duration.list->mValue.GetFloatValue());
michael@0 4898 break;
michael@0 4899 default:
michael@0 4900 NS_NOTREACHED("Invalid duration unit");
michael@0 4901 }
michael@0 4902 }
michael@0 4903
michael@0 4904 if (i >= property.num) {
michael@0 4905 transition->CopyPropertyFrom(display->mTransitions[i % property.num]);
michael@0 4906 } else if (property.unit == eCSSUnit_Inherit) {
michael@0 4907 NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionPropertyCount,
michael@0 4908 "property.num computed incorrectly");
michael@0 4909 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
michael@0 4910 "should have made canStoreInRuleTree false above");
michael@0 4911 transition->CopyPropertyFrom(parentDisplay->mTransitions[i]);
michael@0 4912 } else if (property.unit == eCSSUnit_Initial ||
michael@0 4913 property.unit == eCSSUnit_Unset) {
michael@0 4914 transition->SetProperty(eCSSPropertyExtra_all_properties);
michael@0 4915 } else if (property.unit == eCSSUnit_None) {
michael@0 4916 transition->SetProperty(eCSSPropertyExtra_no_properties);
michael@0 4917 } else if (property.list) {
michael@0 4918 const nsCSSValue &val = property.list->mValue;
michael@0 4919
michael@0 4920 if (val.GetUnit() == eCSSUnit_Ident) {
michael@0 4921 nsDependentString
michael@0 4922 propertyStr(property.list->mValue.GetStringBufferValue());
michael@0 4923 nsCSSProperty prop =
michael@0 4924 nsCSSProps::LookupProperty(propertyStr,
michael@0 4925 nsCSSProps::eEnabledForAllContent);
michael@0 4926 if (prop == eCSSProperty_UNKNOWN) {
michael@0 4927 transition->SetUnknownProperty(propertyStr);
michael@0 4928 } else {
michael@0 4929 transition->SetProperty(prop);
michael@0 4930 }
michael@0 4931 } else {
michael@0 4932 NS_ABORT_IF_FALSE(val.GetUnit() == eCSSUnit_All,
michael@0 4933 nsPrintfCString("Invalid transition property unit %d",
michael@0 4934 val.GetUnit()).get());
michael@0 4935 transition->SetProperty(eCSSPropertyExtra_all_properties);
michael@0 4936 }
michael@0 4937 }
michael@0 4938
michael@0 4939 if (i >= timingFunction.num) {
michael@0 4940 transition->SetTimingFunction(
michael@0 4941 display->mTransitions[i % timingFunction.num].GetTimingFunction());
michael@0 4942 } else if (timingFunction.unit == eCSSUnit_Inherit) {
michael@0 4943 NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionTimingFunctionCount,
michael@0 4944 "timingFunction.num computed incorrectly");
michael@0 4945 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
michael@0 4946 "should have made canStoreInRuleTree false above");
michael@0 4947 transition->SetTimingFunction(
michael@0 4948 parentDisplay->mTransitions[i].GetTimingFunction());
michael@0 4949 } else if (timingFunction.unit == eCSSUnit_Initial ||
michael@0 4950 timingFunction.unit == eCSSUnit_Unset) {
michael@0 4951 transition->SetTimingFunction(
michael@0 4952 nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
michael@0 4953 } else if (timingFunction.list) {
michael@0 4954 ComputeTimingFunction(timingFunction.list->mValue,
michael@0 4955 transition->TimingFunctionSlot());
michael@0 4956 }
michael@0 4957
michael@0 4958 FOR_ALL_TRANSITION_PROPS(p) {
michael@0 4959 const TransitionPropInfo& info = transitionPropInfo[p];
michael@0 4960 TransitionPropData& d = transitionPropData[p];
michael@0 4961
michael@0 4962 // if we're at the end of the list, start at the beginning and repeat
michael@0 4963 // until we're out of transitions to populate
michael@0 4964 if (d.list) {
michael@0 4965 d.list = d.list->mNext ? d.list->mNext :
michael@0 4966 aRuleData->ValueFor(info.property)->GetListValue();
michael@0 4967 }
michael@0 4968 }
michael@0 4969 }
michael@0 4970
michael@0 4971 // Each property's index in this array must match its index in the
michael@0 4972 // const array |animationPropInfo| above.
michael@0 4973 TransitionPropData animationPropData[8];
michael@0 4974 TransitionPropData& animDelay = animationPropData[0];
michael@0 4975 TransitionPropData& animDuration = animationPropData[1];
michael@0 4976 TransitionPropData& animName = animationPropData[2];
michael@0 4977 TransitionPropData& animTimingFunction = animationPropData[3];
michael@0 4978 TransitionPropData& animDirection = animationPropData[4];
michael@0 4979 TransitionPropData& animFillMode = animationPropData[5];
michael@0 4980 TransitionPropData& animPlayState = animationPropData[6];
michael@0 4981 TransitionPropData& animIterationCount = animationPropData[7];
michael@0 4982
michael@0 4983 #define FOR_ALL_ANIMATION_PROPS(var_) \
michael@0 4984 for (uint32_t var_ = 0; var_ < 8; ++var_)
michael@0 4985
michael@0 4986 // CSS Animations.
michael@0 4987
michael@0 4988 uint32_t numAnimations =
michael@0 4989 CountTransitionProps(animationPropInfo, animationPropData,
michael@0 4990 ArrayLength(animationPropData),
michael@0 4991 display, parentDisplay, aRuleData,
michael@0 4992 canStoreInRuleTree);
michael@0 4993
michael@0 4994 display->mAnimations.SetLength(numAnimations);
michael@0 4995
michael@0 4996 FOR_ALL_ANIMATION_PROPS(p) {
michael@0 4997 const TransitionPropInfo& i = animationPropInfo[p];
michael@0 4998 TransitionPropData& d = animationPropData[p];
michael@0 4999
michael@0 5000 display->*(i.sdCount) = d.num;
michael@0 5001 }
michael@0 5002
michael@0 5003 // Fill in the animations we just allocated with the appropriate values.
michael@0 5004 for (uint32_t i = 0; i < numAnimations; ++i) {
michael@0 5005 nsAnimation *animation = &display->mAnimations[i];
michael@0 5006
michael@0 5007 if (i >= animDelay.num) {
michael@0 5008 animation->SetDelay(display->mAnimations[i % animDelay.num].GetDelay());
michael@0 5009 } else if (animDelay.unit == eCSSUnit_Inherit) {
michael@0 5010 // FIXME (Bug 522599) (for all animation properties): write a test that
michael@0 5011 // detects when this was wrong for i >= animDelay.num if parent had
michael@0 5012 // count for this property not equal to length
michael@0 5013 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDelayCount,
michael@0 5014 "animDelay.num computed incorrectly");
michael@0 5015 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
michael@0 5016 "should have made canStoreInRuleTree false above");
michael@0 5017 animation->SetDelay(parentDisplay->mAnimations[i].GetDelay());
michael@0 5018 } else if (animDelay.unit == eCSSUnit_Initial ||
michael@0 5019 animDelay.unit == eCSSUnit_Unset) {
michael@0 5020 animation->SetDelay(0.0);
michael@0 5021 } else if (animDelay.list) {
michael@0 5022 switch (animDelay.list->mValue.GetUnit()) {
michael@0 5023 case eCSSUnit_Seconds:
michael@0 5024 animation->SetDelay(PR_MSEC_PER_SEC *
michael@0 5025 animDelay.list->mValue.GetFloatValue());
michael@0 5026 break;
michael@0 5027 case eCSSUnit_Milliseconds:
michael@0 5028 animation->SetDelay(animDelay.list->mValue.GetFloatValue());
michael@0 5029 break;
michael@0 5030 default:
michael@0 5031 NS_NOTREACHED("Invalid delay unit");
michael@0 5032 }
michael@0 5033 }
michael@0 5034
michael@0 5035 if (i >= animDuration.num) {
michael@0 5036 animation->SetDuration(
michael@0 5037 display->mAnimations[i % animDuration.num].GetDuration());
michael@0 5038 } else if (animDuration.unit == eCSSUnit_Inherit) {
michael@0 5039 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDurationCount,
michael@0 5040 "animDuration.num computed incorrectly");
michael@0 5041 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
michael@0 5042 "should have made canStoreInRuleTree false above");
michael@0 5043 animation->SetDuration(parentDisplay->mAnimations[i].GetDuration());
michael@0 5044 } else if (animDuration.unit == eCSSUnit_Initial ||
michael@0 5045 animDuration.unit == eCSSUnit_Unset) {
michael@0 5046 animation->SetDuration(0.0);
michael@0 5047 } else if (animDuration.list) {
michael@0 5048 switch (animDuration.list->mValue.GetUnit()) {
michael@0 5049 case eCSSUnit_Seconds:
michael@0 5050 animation->SetDuration(PR_MSEC_PER_SEC *
michael@0 5051 animDuration.list->mValue.GetFloatValue());
michael@0 5052 break;
michael@0 5053 case eCSSUnit_Milliseconds:
michael@0 5054 animation->SetDuration(animDuration.list->mValue.GetFloatValue());
michael@0 5055 break;
michael@0 5056 default:
michael@0 5057 NS_NOTREACHED("Invalid duration unit");
michael@0 5058 }
michael@0 5059 }
michael@0 5060
michael@0 5061 if (i >= animName.num) {
michael@0 5062 animation->SetName(display->mAnimations[i % animName.num].GetName());
michael@0 5063 } else if (animName.unit == eCSSUnit_Inherit) {
michael@0 5064 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationNameCount,
michael@0 5065 "animName.num computed incorrectly");
michael@0 5066 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
michael@0 5067 "should have made canStoreInRuleTree false above");
michael@0 5068 animation->SetName(parentDisplay->mAnimations[i].GetName());
michael@0 5069 } else if (animName.unit == eCSSUnit_Initial ||
michael@0 5070 animName.unit == eCSSUnit_Unset) {
michael@0 5071 animation->SetName(EmptyString());
michael@0 5072 } else if (animName.list) {
michael@0 5073 switch (animName.list->mValue.GetUnit()) {
michael@0 5074 case eCSSUnit_Ident: {
michael@0 5075 nsDependentString
michael@0 5076 nameStr(animName.list->mValue.GetStringBufferValue());
michael@0 5077 animation->SetName(nameStr);
michael@0 5078 break;
michael@0 5079 }
michael@0 5080 case eCSSUnit_None: {
michael@0 5081 animation->SetName(EmptyString());
michael@0 5082 break;
michael@0 5083 }
michael@0 5084 default:
michael@0 5085 NS_ABORT_IF_FALSE(false,
michael@0 5086 nsPrintfCString("Invalid animation-name unit %d",
michael@0 5087 animName.list->mValue.GetUnit()).get());
michael@0 5088 }
michael@0 5089 }
michael@0 5090
michael@0 5091 if (i >= animTimingFunction.num) {
michael@0 5092 animation->SetTimingFunction(
michael@0 5093 display->mAnimations[i % animTimingFunction.num].GetTimingFunction());
michael@0 5094 } else if (animTimingFunction.unit == eCSSUnit_Inherit) {
michael@0 5095 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationTimingFunctionCount,
michael@0 5096 "animTimingFunction.num computed incorrectly");
michael@0 5097 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
michael@0 5098 "should have made canStoreInRuleTree false above");
michael@0 5099 animation->SetTimingFunction(
michael@0 5100 parentDisplay->mAnimations[i].GetTimingFunction());
michael@0 5101 } else if (animTimingFunction.unit == eCSSUnit_Initial ||
michael@0 5102 animTimingFunction.unit == eCSSUnit_Unset) {
michael@0 5103 animation->SetTimingFunction(
michael@0 5104 nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
michael@0 5105 } else if (animTimingFunction.list) {
michael@0 5106 ComputeTimingFunction(animTimingFunction.list->mValue,
michael@0 5107 animation->TimingFunctionSlot());
michael@0 5108 }
michael@0 5109
michael@0 5110 if (i >= animDirection.num) {
michael@0 5111 animation->SetDirection(display->mAnimations[i % animDirection.num].GetDirection());
michael@0 5112 } else if (animDirection.unit == eCSSUnit_Inherit) {
michael@0 5113 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDirectionCount,
michael@0 5114 "animDirection.num computed incorrectly");
michael@0 5115 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
michael@0 5116 "should have made canStoreInRuleTree false above");
michael@0 5117 animation->SetDirection(parentDisplay->mAnimations[i].GetDirection());
michael@0 5118 } else if (animDirection.unit == eCSSUnit_Initial ||
michael@0 5119 animDirection.unit == eCSSUnit_Unset) {
michael@0 5120 animation->SetDirection(NS_STYLE_ANIMATION_DIRECTION_NORMAL);
michael@0 5121 } else if (animDirection.list) {
michael@0 5122 NS_ABORT_IF_FALSE(animDirection.list->mValue.GetUnit() == eCSSUnit_Enumerated,
michael@0 5123 nsPrintfCString("Invalid animation-direction unit %d",
michael@0 5124 animDirection.list->mValue.GetUnit()).get());
michael@0 5125
michael@0 5126 animation->SetDirection(animDirection.list->mValue.GetIntValue());
michael@0 5127 }
michael@0 5128
michael@0 5129 if (i >= animFillMode.num) {
michael@0 5130 animation->SetFillMode(display->mAnimations[i % animFillMode.num].GetFillMode());
michael@0 5131 } else if (animFillMode.unit == eCSSUnit_Inherit) {
michael@0 5132 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationFillModeCount,
michael@0 5133 "animFillMode.num computed incorrectly");
michael@0 5134 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
michael@0 5135 "should have made canStoreInRuleTree false above");
michael@0 5136 animation->SetFillMode(parentDisplay->mAnimations[i].GetFillMode());
michael@0 5137 } else if (animFillMode.unit == eCSSUnit_Initial ||
michael@0 5138 animFillMode.unit == eCSSUnit_Unset) {
michael@0 5139 animation->SetFillMode(NS_STYLE_ANIMATION_FILL_MODE_NONE);
michael@0 5140 } else if (animFillMode.list) {
michael@0 5141 NS_ABORT_IF_FALSE(animFillMode.list->mValue.GetUnit() == eCSSUnit_Enumerated,
michael@0 5142 nsPrintfCString("Invalid animation-fill-mode unit %d",
michael@0 5143 animFillMode.list->mValue.GetUnit()).get());
michael@0 5144
michael@0 5145 animation->SetFillMode(animFillMode.list->mValue.GetIntValue());
michael@0 5146 }
michael@0 5147
michael@0 5148 if (i >= animPlayState.num) {
michael@0 5149 animation->SetPlayState(display->mAnimations[i % animPlayState.num].GetPlayState());
michael@0 5150 } else if (animPlayState.unit == eCSSUnit_Inherit) {
michael@0 5151 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationPlayStateCount,
michael@0 5152 "animPlayState.num computed incorrectly");
michael@0 5153 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
michael@0 5154 "should have made canStoreInRuleTree false above");
michael@0 5155 animation->SetPlayState(parentDisplay->mAnimations[i].GetPlayState());
michael@0 5156 } else if (animPlayState.unit == eCSSUnit_Initial ||
michael@0 5157 animPlayState.unit == eCSSUnit_Unset) {
michael@0 5158 animation->SetPlayState(NS_STYLE_ANIMATION_PLAY_STATE_RUNNING);
michael@0 5159 } else if (animPlayState.list) {
michael@0 5160 NS_ABORT_IF_FALSE(animPlayState.list->mValue.GetUnit() == eCSSUnit_Enumerated,
michael@0 5161 nsPrintfCString("Invalid animation-play-state unit %d",
michael@0 5162 animPlayState.list->mValue.GetUnit()).get());
michael@0 5163
michael@0 5164 animation->SetPlayState(animPlayState.list->mValue.GetIntValue());
michael@0 5165 }
michael@0 5166
michael@0 5167 if (i >= animIterationCount.num) {
michael@0 5168 animation->SetIterationCount(display->mAnimations[i % animIterationCount.num].GetIterationCount());
michael@0 5169 } else if (animIterationCount.unit == eCSSUnit_Inherit) {
michael@0 5170 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationIterationCountCount,
michael@0 5171 "animIterationCount.num computed incorrectly");
michael@0 5172 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
michael@0 5173 "should have made canStoreInRuleTree false above");
michael@0 5174 animation->SetIterationCount(parentDisplay->mAnimations[i].GetIterationCount());
michael@0 5175 } else if (animIterationCount.unit == eCSSUnit_Initial ||
michael@0 5176 animIterationCount.unit == eCSSUnit_Unset) {
michael@0 5177 animation->SetIterationCount(1.0f);
michael@0 5178 } else if (animIterationCount.list) {
michael@0 5179 switch (animIterationCount.list->mValue.GetUnit()) {
michael@0 5180 case eCSSUnit_Enumerated:
michael@0 5181 NS_ABORT_IF_FALSE(animIterationCount.list->mValue.GetIntValue() ==
michael@0 5182 NS_STYLE_ANIMATION_ITERATION_COUNT_INFINITE,
michael@0 5183 "unexpected value");
michael@0 5184 animation->SetIterationCount(NS_IEEEPositiveInfinity());
michael@0 5185 break;
michael@0 5186 case eCSSUnit_Number:
michael@0 5187 animation->SetIterationCount(
michael@0 5188 animIterationCount.list->mValue.GetFloatValue());
michael@0 5189 break;
michael@0 5190 default:
michael@0 5191 NS_ABORT_IF_FALSE(false,
michael@0 5192 "unexpected animation-iteration-count unit");
michael@0 5193 }
michael@0 5194 }
michael@0 5195
michael@0 5196 FOR_ALL_ANIMATION_PROPS(p) {
michael@0 5197 const TransitionPropInfo& info = animationPropInfo[p];
michael@0 5198 TransitionPropData& d = animationPropData[p];
michael@0 5199
michael@0 5200 // if we're at the end of the list, start at the beginning and repeat
michael@0 5201 // until we're out of animations to populate
michael@0 5202 if (d.list) {
michael@0 5203 d.list = d.list->mNext ? d.list->mNext :
michael@0 5204 aRuleData->ValueFor(info.property)->GetListValue();
michael@0 5205 }
michael@0 5206 }
michael@0 5207 }
michael@0 5208
michael@0 5209 // opacity: factor, inherit, initial
michael@0 5210 SetFactor(*aRuleData->ValueForOpacity(), display->mOpacity, canStoreInRuleTree,
michael@0 5211 parentDisplay->mOpacity, 1.0f,
michael@0 5212 SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
michael@0 5213
michael@0 5214 // display: enum, inherit, initial
michael@0 5215 SetDiscrete(*aRuleData->ValueForDisplay(), display->mDisplay, canStoreInRuleTree,
michael@0 5216 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5217 parentDisplay->mDisplay,
michael@0 5218 NS_STYLE_DISPLAY_INLINE, 0, 0, 0, 0);
michael@0 5219
michael@0 5220 // mix-blend-mode: enum, inherit, initial
michael@0 5221 SetDiscrete(*aRuleData->ValueForMixBlendMode(), display->mMixBlendMode,
michael@0 5222 canStoreInRuleTree,
michael@0 5223 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5224 parentDisplay->mMixBlendMode, NS_STYLE_BLEND_NORMAL,
michael@0 5225 0, 0, 0, 0);
michael@0 5226
michael@0 5227 // Backup original display value for calculation of a hypothetical
michael@0 5228 // box (CSS2 10.6.4/10.6.5), in addition to getting our style data right later.
michael@0 5229 // See nsHTMLReflowState::CalculateHypotheticalBox
michael@0 5230 display->mOriginalDisplay = display->mDisplay;
michael@0 5231
michael@0 5232 // appearance: enum, inherit, initial
michael@0 5233 SetDiscrete(*aRuleData->ValueForAppearance(),
michael@0 5234 display->mAppearance, canStoreInRuleTree,
michael@0 5235 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5236 parentDisplay->mAppearance,
michael@0 5237 NS_THEME_NONE, 0, 0, 0, 0);
michael@0 5238
michael@0 5239 // binding: url, none, inherit
michael@0 5240 const nsCSSValue* bindingValue = aRuleData->ValueForBinding();
michael@0 5241 if (eCSSUnit_URL == bindingValue->GetUnit()) {
michael@0 5242 mozilla::css::URLValue* url = bindingValue->GetURLStructValue();
michael@0 5243 NS_ASSERTION(url, "What's going on here?");
michael@0 5244
michael@0 5245 if (MOZ_LIKELY(url->GetURI())) {
michael@0 5246 display->mBinding = url;
michael@0 5247 } else {
michael@0 5248 display->mBinding = nullptr;
michael@0 5249 }
michael@0 5250 }
michael@0 5251 else if (eCSSUnit_None == bindingValue->GetUnit() ||
michael@0 5252 eCSSUnit_Initial == bindingValue->GetUnit() ||
michael@0 5253 eCSSUnit_Unset == bindingValue->GetUnit()) {
michael@0 5254 display->mBinding = nullptr;
michael@0 5255 }
michael@0 5256 else if (eCSSUnit_Inherit == bindingValue->GetUnit()) {
michael@0 5257 canStoreInRuleTree = false;
michael@0 5258 display->mBinding = parentDisplay->mBinding;
michael@0 5259 }
michael@0 5260
michael@0 5261 // position: enum, inherit, initial
michael@0 5262 SetDiscrete(*aRuleData->ValueForPosition(), display->mPosition, canStoreInRuleTree,
michael@0 5263 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5264 parentDisplay->mPosition,
michael@0 5265 NS_STYLE_POSITION_STATIC, 0, 0, 0, 0);
michael@0 5266
michael@0 5267 // clear: enum, inherit, initial
michael@0 5268 SetDiscrete(*aRuleData->ValueForClear(), display->mBreakType, canStoreInRuleTree,
michael@0 5269 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5270 parentDisplay->mBreakType,
michael@0 5271 NS_STYLE_CLEAR_NONE, 0, 0, 0, 0);
michael@0 5272
michael@0 5273 // temp fix for bug 24000
michael@0 5274 // Map 'auto' and 'avoid' to false, and 'always', 'left', and
michael@0 5275 // 'right' to true.
michael@0 5276 // "A conforming user agent may interpret the values 'left' and
michael@0 5277 // 'right' as 'always'." - CSS2.1, section 13.3.1
michael@0 5278 const nsCSSValue* breakBeforeValue = aRuleData->ValueForPageBreakBefore();
michael@0 5279 if (eCSSUnit_Enumerated == breakBeforeValue->GetUnit()) {
michael@0 5280 display->mBreakBefore =
michael@0 5281 (NS_STYLE_PAGE_BREAK_AVOID != breakBeforeValue->GetIntValue() &&
michael@0 5282 NS_STYLE_PAGE_BREAK_AUTO != breakBeforeValue->GetIntValue());
michael@0 5283 }
michael@0 5284 else if (eCSSUnit_Initial == breakBeforeValue->GetUnit() ||
michael@0 5285 eCSSUnit_Unset == breakBeforeValue->GetUnit()) {
michael@0 5286 display->mBreakBefore = false;
michael@0 5287 }
michael@0 5288 else if (eCSSUnit_Inherit == breakBeforeValue->GetUnit()) {
michael@0 5289 canStoreInRuleTree = false;
michael@0 5290 display->mBreakBefore = parentDisplay->mBreakBefore;
michael@0 5291 }
michael@0 5292
michael@0 5293 const nsCSSValue* breakAfterValue = aRuleData->ValueForPageBreakAfter();
michael@0 5294 if (eCSSUnit_Enumerated == breakAfterValue->GetUnit()) {
michael@0 5295 display->mBreakAfter =
michael@0 5296 (NS_STYLE_PAGE_BREAK_AVOID != breakAfterValue->GetIntValue() &&
michael@0 5297 NS_STYLE_PAGE_BREAK_AUTO != breakAfterValue->GetIntValue());
michael@0 5298 }
michael@0 5299 else if (eCSSUnit_Initial == breakAfterValue->GetUnit() ||
michael@0 5300 eCSSUnit_Unset == breakAfterValue->GetUnit()) {
michael@0 5301 display->mBreakAfter = false;
michael@0 5302 }
michael@0 5303 else if (eCSSUnit_Inherit == breakAfterValue->GetUnit()) {
michael@0 5304 canStoreInRuleTree = false;
michael@0 5305 display->mBreakAfter = parentDisplay->mBreakAfter;
michael@0 5306 }
michael@0 5307 // end temp fix
michael@0 5308
michael@0 5309 // page-break-inside: enum, inherit, initial
michael@0 5310 SetDiscrete(*aRuleData->ValueForPageBreakInside(),
michael@0 5311 display->mBreakInside, canStoreInRuleTree,
michael@0 5312 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5313 parentDisplay->mBreakInside,
michael@0 5314 NS_STYLE_PAGE_BREAK_AUTO, 0, 0, 0, 0);
michael@0 5315
michael@0 5316 // touch-action: none, auto, enum, inherit, initial
michael@0 5317 SetDiscrete(*aRuleData->ValueForTouchAction(), display->mTouchAction,
michael@0 5318 canStoreInRuleTree,
michael@0 5319 SETDSC_ENUMERATED | SETDSC_AUTO | SETDSC_NONE |
michael@0 5320 SETDSC_UNSET_INITIAL,
michael@0 5321 parentDisplay->mTouchAction,
michael@0 5322 NS_STYLE_TOUCH_ACTION_AUTO,
michael@0 5323 NS_STYLE_TOUCH_ACTION_AUTO,
michael@0 5324 NS_STYLE_TOUCH_ACTION_NONE, 0, 0);
michael@0 5325
michael@0 5326 // float: enum, inherit, initial
michael@0 5327 SetDiscrete(*aRuleData->ValueForFloat(),
michael@0 5328 display->mFloats, canStoreInRuleTree,
michael@0 5329 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5330 parentDisplay->mFloats,
michael@0 5331 NS_STYLE_FLOAT_NONE, 0, 0, 0, 0);
michael@0 5332 // Save mFloats in mOriginalFloats in case we need it later
michael@0 5333 display->mOriginalFloats = display->mFloats;
michael@0 5334
michael@0 5335 // overflow-x: enum, inherit, initial
michael@0 5336 SetDiscrete(*aRuleData->ValueForOverflowX(),
michael@0 5337 display->mOverflowX, canStoreInRuleTree,
michael@0 5338 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5339 parentDisplay->mOverflowX,
michael@0 5340 NS_STYLE_OVERFLOW_VISIBLE, 0, 0, 0, 0);
michael@0 5341
michael@0 5342 // overflow-y: enum, inherit, initial
michael@0 5343 SetDiscrete(*aRuleData->ValueForOverflowY(),
michael@0 5344 display->mOverflowY, canStoreInRuleTree,
michael@0 5345 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5346 parentDisplay->mOverflowY,
michael@0 5347 NS_STYLE_OVERFLOW_VISIBLE, 0, 0, 0, 0);
michael@0 5348
michael@0 5349 // CSS3 overflow-x and overflow-y require some fixup as well in some
michael@0 5350 // cases. NS_STYLE_OVERFLOW_VISIBLE and NS_STYLE_OVERFLOW_CLIP are
michael@0 5351 // meaningful only when used in both dimensions.
michael@0 5352 if (display->mOverflowX != display->mOverflowY &&
michael@0 5353 (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE ||
michael@0 5354 display->mOverflowX == NS_STYLE_OVERFLOW_CLIP ||
michael@0 5355 display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE ||
michael@0 5356 display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)) {
michael@0 5357 // We can't store in the rule tree since a more specific rule might
michael@0 5358 // change these conditions.
michael@0 5359 canStoreInRuleTree = false;
michael@0 5360
michael@0 5361 // NS_STYLE_OVERFLOW_CLIP is a deprecated value, so if it's specified
michael@0 5362 // in only one dimension, convert it to NS_STYLE_OVERFLOW_HIDDEN.
michael@0 5363 if (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
michael@0 5364 display->mOverflowX = NS_STYLE_OVERFLOW_HIDDEN;
michael@0 5365 if (display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)
michael@0 5366 display->mOverflowY = NS_STYLE_OVERFLOW_HIDDEN;
michael@0 5367
michael@0 5368 // If 'visible' is specified but doesn't match the other dimension, it
michael@0 5369 // turns into 'auto'.
michael@0 5370 if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
michael@0 5371 display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
michael@0 5372 if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE)
michael@0 5373 display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
michael@0 5374 }
michael@0 5375
michael@0 5376 SetDiscrete(*aRuleData->ValueForOverflowClipBox(), display->mOverflowClipBox,
michael@0 5377 canStoreInRuleTree,
michael@0 5378 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5379 parentDisplay->mOverflowClipBox,
michael@0 5380 NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX, 0, 0, 0, 0);
michael@0 5381
michael@0 5382 SetDiscrete(*aRuleData->ValueForResize(), display->mResize, canStoreInRuleTree,
michael@0 5383 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5384 parentDisplay->mResize,
michael@0 5385 NS_STYLE_RESIZE_NONE, 0, 0, 0, 0);
michael@0 5386
michael@0 5387 // clip property: length, auto, inherit
michael@0 5388 const nsCSSValue* clipValue = aRuleData->ValueForClip();
michael@0 5389 switch (clipValue->GetUnit()) {
michael@0 5390 case eCSSUnit_Inherit:
michael@0 5391 canStoreInRuleTree = false;
michael@0 5392 display->mClipFlags = parentDisplay->mClipFlags;
michael@0 5393 display->mClip = parentDisplay->mClip;
michael@0 5394 break;
michael@0 5395
michael@0 5396 case eCSSUnit_Initial:
michael@0 5397 case eCSSUnit_Unset:
michael@0 5398 case eCSSUnit_Auto:
michael@0 5399 display->mClipFlags = NS_STYLE_CLIP_AUTO;
michael@0 5400 display->mClip.SetRect(0,0,0,0);
michael@0 5401 break;
michael@0 5402
michael@0 5403 case eCSSUnit_Null:
michael@0 5404 break;
michael@0 5405
michael@0 5406 case eCSSUnit_Rect: {
michael@0 5407 const nsCSSRect& clipRect = clipValue->GetRectValue();
michael@0 5408
michael@0 5409 display->mClipFlags = NS_STYLE_CLIP_RECT;
michael@0 5410
michael@0 5411 if (clipRect.mTop.GetUnit() == eCSSUnit_Auto) {
michael@0 5412 display->mClip.y = 0;
michael@0 5413 display->mClipFlags |= NS_STYLE_CLIP_TOP_AUTO;
michael@0 5414 }
michael@0 5415 else if (clipRect.mTop.IsLengthUnit()) {
michael@0 5416 display->mClip.y = CalcLength(clipRect.mTop, aContext,
michael@0 5417 mPresContext, canStoreInRuleTree);
michael@0 5418 }
michael@0 5419
michael@0 5420 if (clipRect.mBottom.GetUnit() == eCSSUnit_Auto) {
michael@0 5421 // Setting to NS_MAXSIZE for the 'auto' case ensures that
michael@0 5422 // the clip rect is nonempty. It is important that mClip be
michael@0 5423 // nonempty if the actual clip rect could be nonempty.
michael@0 5424 display->mClip.height = NS_MAXSIZE;
michael@0 5425 display->mClipFlags |= NS_STYLE_CLIP_BOTTOM_AUTO;
michael@0 5426 }
michael@0 5427 else if (clipRect.mBottom.IsLengthUnit()) {
michael@0 5428 display->mClip.height = CalcLength(clipRect.mBottom, aContext,
michael@0 5429 mPresContext, canStoreInRuleTree) -
michael@0 5430 display->mClip.y;
michael@0 5431 }
michael@0 5432
michael@0 5433 if (clipRect.mLeft.GetUnit() == eCSSUnit_Auto) {
michael@0 5434 display->mClip.x = 0;
michael@0 5435 display->mClipFlags |= NS_STYLE_CLIP_LEFT_AUTO;
michael@0 5436 }
michael@0 5437 else if (clipRect.mLeft.IsLengthUnit()) {
michael@0 5438 display->mClip.x = CalcLength(clipRect.mLeft, aContext,
michael@0 5439 mPresContext, canStoreInRuleTree);
michael@0 5440 }
michael@0 5441
michael@0 5442 if (clipRect.mRight.GetUnit() == eCSSUnit_Auto) {
michael@0 5443 // Setting to NS_MAXSIZE for the 'auto' case ensures that
michael@0 5444 // the clip rect is nonempty. It is important that mClip be
michael@0 5445 // nonempty if the actual clip rect could be nonempty.
michael@0 5446 display->mClip.width = NS_MAXSIZE;
michael@0 5447 display->mClipFlags |= NS_STYLE_CLIP_RIGHT_AUTO;
michael@0 5448 }
michael@0 5449 else if (clipRect.mRight.IsLengthUnit()) {
michael@0 5450 display->mClip.width = CalcLength(clipRect.mRight, aContext,
michael@0 5451 mPresContext, canStoreInRuleTree) -
michael@0 5452 display->mClip.x;
michael@0 5453 }
michael@0 5454 break;
michael@0 5455 }
michael@0 5456
michael@0 5457 default:
michael@0 5458 NS_ABORT_IF_FALSE(false, "unrecognized clip unit");
michael@0 5459 }
michael@0 5460
michael@0 5461 if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
michael@0 5462 // CSS2 9.7 specifies display type corrections dealing with 'float'
michael@0 5463 // and 'position'. Since generated content can't be floated or
michael@0 5464 // positioned, we can deal with it here.
michael@0 5465
michael@0 5466 if (nsCSSPseudoElements::firstLetter == aContext->GetPseudo()) {
michael@0 5467 // a non-floating first-letter must be inline
michael@0 5468 // XXX this fix can go away once bug 103189 is fixed correctly
michael@0 5469 // Note that we reset mOriginalDisplay to enforce the invariant that it equals mDisplay if we're not positioned or floating.
michael@0 5470 display->mOriginalDisplay = display->mDisplay = NS_STYLE_DISPLAY_INLINE;
michael@0 5471
michael@0 5472 // We can't cache the data in the rule tree since if a more specific
michael@0 5473 // rule has 'float: left' we'll end up with the wrong 'display'
michael@0 5474 // property.
michael@0 5475 canStoreInRuleTree = false;
michael@0 5476 }
michael@0 5477
michael@0 5478 if (display->IsAbsolutelyPositionedStyle()) {
michael@0 5479 // 1) if position is 'absolute' or 'fixed' then display must be
michael@0 5480 // block-level and float must be 'none'
michael@0 5481 EnsureBlockDisplay(display->mDisplay);
michael@0 5482 display->mFloats = NS_STYLE_FLOAT_NONE;
michael@0 5483
michael@0 5484 // Note that it's OK to cache this struct in the ruletree
michael@0 5485 // because it's fine as-is for any style context that points to
michael@0 5486 // it directly, and any use of it as aStartStruct (e.g. if a
michael@0 5487 // more specific rule sets "position: static") will use
michael@0 5488 // mOriginalDisplay and mOriginalFloats, which we have carefully
michael@0 5489 // not changed.
michael@0 5490 } else if (display->mFloats != NS_STYLE_FLOAT_NONE) {
michael@0 5491 // 2) if float is not none, and display is not none, then we must
michael@0 5492 // set a block-level 'display' type per CSS2.1 section 9.7.
michael@0 5493 EnsureBlockDisplay(display->mDisplay);
michael@0 5494
michael@0 5495 // Note that it's OK to cache this struct in the ruletree
michael@0 5496 // because it's fine as-is for any style context that points to
michael@0 5497 // it directly, and any use of it as aStartStruct (e.g. if a
michael@0 5498 // more specific rule sets "float: none") will use
michael@0 5499 // mOriginalDisplay, which we have carefully not changed.
michael@0 5500 }
michael@0 5501
michael@0 5502 }
michael@0 5503
michael@0 5504 /* Convert the nsCSSValueList into an nsTArray<nsTransformFunction *>. */
michael@0 5505 const nsCSSValue* transformValue = aRuleData->ValueForTransform();
michael@0 5506 switch (transformValue->GetUnit()) {
michael@0 5507 case eCSSUnit_Null:
michael@0 5508 break;
michael@0 5509
michael@0 5510 case eCSSUnit_Initial:
michael@0 5511 case eCSSUnit_Unset:
michael@0 5512 case eCSSUnit_None:
michael@0 5513 display->mSpecifiedTransform = nullptr;
michael@0 5514 break;
michael@0 5515
michael@0 5516 case eCSSUnit_Inherit:
michael@0 5517 display->mSpecifiedTransform = parentDisplay->mSpecifiedTransform;
michael@0 5518 canStoreInRuleTree = false;
michael@0 5519 break;
michael@0 5520
michael@0 5521 case eCSSUnit_SharedList: {
michael@0 5522 nsCSSValueSharedList* list = transformValue->GetSharedListValue();
michael@0 5523 nsCSSValueList* head = list->mHead;
michael@0 5524 MOZ_ASSERT(head, "transform list must have at least one item");
michael@0 5525 // can get a _None in here from transform animation
michael@0 5526 if (head->mValue.GetUnit() == eCSSUnit_None) {
michael@0 5527 NS_ABORT_IF_FALSE(head->mNext == nullptr, "none must be alone");
michael@0 5528 display->mSpecifiedTransform = nullptr;
michael@0 5529 } else {
michael@0 5530 display->mSpecifiedTransform = list;
michael@0 5531 }
michael@0 5532 break;
michael@0 5533 }
michael@0 5534
michael@0 5535 default:
michael@0 5536 NS_ABORT_IF_FALSE(false, "unrecognized transform unit");
michael@0 5537 }
michael@0 5538
michael@0 5539 /* Convert the nsCSSValueList into a will-change bitfield for fast lookup */
michael@0 5540 const nsCSSValue* willChangeValue = aRuleData->ValueForWillChange();
michael@0 5541 switch (willChangeValue->GetUnit()) {
michael@0 5542 case eCSSUnit_Null:
michael@0 5543 break;
michael@0 5544
michael@0 5545 case eCSSUnit_List:
michael@0 5546 case eCSSUnit_ListDep: {
michael@0 5547 display->mWillChange.Clear();
michael@0 5548 display->mWillChangeBitField = 0;
michael@0 5549 for (const nsCSSValueList* item = willChangeValue->GetListValue();
michael@0 5550 item; item = item->mNext)
michael@0 5551 {
michael@0 5552 if (item->mValue.UnitHasStringValue()) {
michael@0 5553 nsAutoString buffer;
michael@0 5554 item->mValue.GetStringValue(buffer);
michael@0 5555 display->mWillChange.AppendElement(buffer);
michael@0 5556
michael@0 5557 if (buffer.EqualsLiteral("transform")) {
michael@0 5558 display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_TRANSFORM;
michael@0 5559 }
michael@0 5560 if (buffer.EqualsLiteral("opacity")) {
michael@0 5561 display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_OPACITY;
michael@0 5562 }
michael@0 5563 if (buffer.EqualsLiteral("scroll-position")) {
michael@0 5564 display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_SCROLL;
michael@0 5565 }
michael@0 5566
michael@0 5567 nsCSSProperty prop =
michael@0 5568 nsCSSProps::LookupProperty(buffer,
michael@0 5569 nsCSSProps::eEnabledForAllContent);
michael@0 5570 if (prop != eCSSProperty_UNKNOWN &&
michael@0 5571 nsCSSProps::PropHasFlags(prop,
michael@0 5572 CSS_PROPERTY_CREATES_STACKING_CONTEXT))
michael@0 5573 {
michael@0 5574 display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_STACKING_CONTEXT;
michael@0 5575 }
michael@0 5576 }
michael@0 5577 }
michael@0 5578 break;
michael@0 5579 }
michael@0 5580
michael@0 5581 case eCSSUnit_Inherit:
michael@0 5582 display->mWillChange = parentDisplay->mWillChange;
michael@0 5583 display->mWillChangeBitField = parentDisplay->mWillChangeBitField;
michael@0 5584 canStoreInRuleTree = false;
michael@0 5585 break;
michael@0 5586
michael@0 5587 case eCSSUnit_Initial:
michael@0 5588 case eCSSUnit_Unset:
michael@0 5589 case eCSSUnit_Auto:
michael@0 5590 display->mWillChange.Clear();
michael@0 5591 display->mWillChangeBitField = 0;
michael@0 5592 break;
michael@0 5593
michael@0 5594 default:
michael@0 5595 MOZ_ASSERT(false, "unrecognized will-change unit");
michael@0 5596 }
michael@0 5597
michael@0 5598 /* Convert -moz-transform-origin. */
michael@0 5599 const nsCSSValue* transformOriginValue =
michael@0 5600 aRuleData->ValueForTransformOrigin();
michael@0 5601 if (transformOriginValue->GetUnit() != eCSSUnit_Null) {
michael@0 5602 const nsCSSValue& valX =
michael@0 5603 transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
michael@0 5604 transformOriginValue->GetTripletValue().mXValue : *transformOriginValue;
michael@0 5605 const nsCSSValue& valY =
michael@0 5606 transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
michael@0 5607 transformOriginValue->GetTripletValue().mYValue : *transformOriginValue;
michael@0 5608 const nsCSSValue& valZ =
michael@0 5609 transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
michael@0 5610 transformOriginValue->GetTripletValue().mZValue : *transformOriginValue;
michael@0 5611
michael@0 5612 mozilla::DebugOnly<bool> cX =
michael@0 5613 SetCoord(valX, display->mTransformOrigin[0],
michael@0 5614 parentDisplay->mTransformOrigin[0],
michael@0 5615 SETCOORD_LPH | SETCOORD_INITIAL_HALF |
michael@0 5616 SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
michael@0 5617 SETCOORD_UNSET_INITIAL,
michael@0 5618 aContext, mPresContext, canStoreInRuleTree);
michael@0 5619
michael@0 5620 mozilla::DebugOnly<bool> cY =
michael@0 5621 SetCoord(valY, display->mTransformOrigin[1],
michael@0 5622 parentDisplay->mTransformOrigin[1],
michael@0 5623 SETCOORD_LPH | SETCOORD_INITIAL_HALF |
michael@0 5624 SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
michael@0 5625 SETCOORD_UNSET_INITIAL,
michael@0 5626 aContext, mPresContext, canStoreInRuleTree);
michael@0 5627
michael@0 5628 if (valZ.GetUnit() == eCSSUnit_Null) {
michael@0 5629 // Null for the z component means a 0 translation, not
michael@0 5630 // unspecified, as we have already checked the triplet
michael@0 5631 // value for Null.
michael@0 5632 display->mTransformOrigin[2].SetCoordValue(0);
michael@0 5633 } else {
michael@0 5634 mozilla::DebugOnly<bool> cZ =
michael@0 5635 SetCoord(valZ, display->mTransformOrigin[2],
michael@0 5636 parentDisplay->mTransformOrigin[2],
michael@0 5637 SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
michael@0 5638 SETCOORD_UNSET_INITIAL,
michael@0 5639 aContext, mPresContext, canStoreInRuleTree);
michael@0 5640 NS_ABORT_IF_FALSE(cY == cZ, "changed one but not the other");
michael@0 5641 }
michael@0 5642 NS_ABORT_IF_FALSE(cX == cY, "changed one but not the other");
michael@0 5643 NS_ASSERTION(cX, "Malformed -moz-transform-origin parse!");
michael@0 5644 }
michael@0 5645
michael@0 5646 const nsCSSValue* perspectiveOriginValue =
michael@0 5647 aRuleData->ValueForPerspectiveOrigin();
michael@0 5648 if (perspectiveOriginValue->GetUnit() != eCSSUnit_Null) {
michael@0 5649 mozilla::DebugOnly<bool> result =
michael@0 5650 SetPairCoords(*perspectiveOriginValue,
michael@0 5651 display->mPerspectiveOrigin[0],
michael@0 5652 display->mPerspectiveOrigin[1],
michael@0 5653 parentDisplay->mPerspectiveOrigin[0],
michael@0 5654 parentDisplay->mPerspectiveOrigin[1],
michael@0 5655 SETCOORD_LPH | SETCOORD_INITIAL_HALF |
michael@0 5656 SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
michael@0 5657 SETCOORD_UNSET_INITIAL,
michael@0 5658 aContext, mPresContext, canStoreInRuleTree);
michael@0 5659 NS_ASSERTION(result, "Malformed -moz-perspective-origin parse!");
michael@0 5660 }
michael@0 5661
michael@0 5662 SetCoord(*aRuleData->ValueForPerspective(),
michael@0 5663 display->mChildPerspective, parentDisplay->mChildPerspective,
michael@0 5664 SETCOORD_LAH | SETCOORD_INITIAL_NONE | SETCOORD_NONE |
michael@0 5665 SETCOORD_UNSET_INITIAL,
michael@0 5666 aContext, mPresContext, canStoreInRuleTree);
michael@0 5667
michael@0 5668 SetDiscrete(*aRuleData->ValueForBackfaceVisibility(),
michael@0 5669 display->mBackfaceVisibility, canStoreInRuleTree,
michael@0 5670 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5671 parentDisplay->mBackfaceVisibility,
michael@0 5672 NS_STYLE_BACKFACE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
michael@0 5673
michael@0 5674 // transform-style: enum, inherit, initial
michael@0 5675 SetDiscrete(*aRuleData->ValueForTransformStyle(),
michael@0 5676 display->mTransformStyle, canStoreInRuleTree,
michael@0 5677 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5678 parentDisplay->mTransformStyle,
michael@0 5679 NS_STYLE_TRANSFORM_STYLE_FLAT, 0, 0, 0, 0);
michael@0 5680
michael@0 5681 // orient: enum, inherit, initial
michael@0 5682 SetDiscrete(*aRuleData->ValueForOrient(),
michael@0 5683 display->mOrient, canStoreInRuleTree,
michael@0 5684 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 5685 parentDisplay->mOrient,
michael@0 5686 NS_STYLE_ORIENT_AUTO, 0, 0, 0, 0);
michael@0 5687
michael@0 5688 COMPUTE_END_RESET(Display, display)
michael@0 5689 }
michael@0 5690
michael@0 5691 const void*
michael@0 5692 nsRuleNode::ComputeVisibilityData(void* aStartStruct,
michael@0 5693 const nsRuleData* aRuleData,
michael@0 5694 nsStyleContext* aContext,
michael@0 5695 nsRuleNode* aHighestNode,
michael@0 5696 const RuleDetail aRuleDetail,
michael@0 5697 const bool aCanStoreInRuleTree)
michael@0 5698 {
michael@0 5699 COMPUTE_START_INHERITED(Visibility, (mPresContext),
michael@0 5700 visibility, parentVisibility)
michael@0 5701
michael@0 5702 // IMPORTANT: No properties in this struct have lengths in them. We
michael@0 5703 // depend on this since CalcLengthWith can call StyleVisibility()
michael@0 5704 // to get the language for resolving fonts!
michael@0 5705
michael@0 5706 // direction: enum, inherit, initial
michael@0 5707 SetDiscrete(*aRuleData->ValueForDirection(), visibility->mDirection,
michael@0 5708 canStoreInRuleTree,
michael@0 5709 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 5710 parentVisibility->mDirection,
michael@0 5711 (GET_BIDI_OPTION_DIRECTION(mPresContext->GetBidi())
michael@0 5712 == IBMBIDI_TEXTDIRECTION_RTL)
michael@0 5713 ? NS_STYLE_DIRECTION_RTL : NS_STYLE_DIRECTION_LTR,
michael@0 5714 0, 0, 0, 0);
michael@0 5715
michael@0 5716 // visibility: enum, inherit, initial
michael@0 5717 SetDiscrete(*aRuleData->ValueForVisibility(), visibility->mVisible,
michael@0 5718 canStoreInRuleTree,
michael@0 5719 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 5720 parentVisibility->mVisible,
michael@0 5721 NS_STYLE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
michael@0 5722
michael@0 5723 // pointer-events: enum, inherit, initial
michael@0 5724 SetDiscrete(*aRuleData->ValueForPointerEvents(), visibility->mPointerEvents,
michael@0 5725 canStoreInRuleTree,
michael@0 5726 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 5727 parentVisibility->mPointerEvents,
michael@0 5728 NS_STYLE_POINTER_EVENTS_AUTO, 0, 0, 0, 0);
michael@0 5729
michael@0 5730 // writing-mode: enum, inherit, initial
michael@0 5731 SetDiscrete(*aRuleData->ValueForWritingMode(), visibility->mWritingMode,
michael@0 5732 canStoreInRuleTree,
michael@0 5733 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 5734 parentVisibility->mWritingMode,
michael@0 5735 NS_STYLE_WRITING_MODE_HORIZONTAL_TB, 0, 0, 0, 0);
michael@0 5736
michael@0 5737 // image-orientation: enum, inherit, initial
michael@0 5738 const nsCSSValue* orientation = aRuleData->ValueForImageOrientation();
michael@0 5739 if (orientation->GetUnit() == eCSSUnit_Inherit ||
michael@0 5740 orientation->GetUnit() == eCSSUnit_Unset) {
michael@0 5741 canStoreInRuleTree = false;
michael@0 5742 visibility->mImageOrientation = parentVisibility->mImageOrientation;
michael@0 5743 } else if (orientation->GetUnit() == eCSSUnit_Initial) {
michael@0 5744 visibility->mImageOrientation = nsStyleImageOrientation();
michael@0 5745 } else if (orientation->IsAngularUnit()) {
michael@0 5746 double angle = orientation->GetAngleValueInRadians();
michael@0 5747 visibility->mImageOrientation =
michael@0 5748 nsStyleImageOrientation::CreateAsAngleAndFlip(angle, false);
michael@0 5749 } else if (orientation->GetUnit() == eCSSUnit_Array) {
michael@0 5750 const nsCSSValue::Array* array = orientation->GetArrayValue();
michael@0 5751 MOZ_ASSERT(array->Item(0).IsAngularUnit(),
michael@0 5752 "First image-orientation value is not an angle");
michael@0 5753 MOZ_ASSERT(array->Item(1).GetUnit() == eCSSUnit_Enumerated &&
michael@0 5754 array->Item(1).GetIntValue() == NS_STYLE_IMAGE_ORIENTATION_FLIP,
michael@0 5755 "Second image-orientation value is not 'flip'");
michael@0 5756 double angle = array->Item(0).GetAngleValueInRadians();
michael@0 5757 visibility->mImageOrientation =
michael@0 5758 nsStyleImageOrientation::CreateAsAngleAndFlip(angle, true);
michael@0 5759
michael@0 5760 } else if (orientation->GetUnit() == eCSSUnit_Enumerated) {
michael@0 5761 switch (orientation->GetIntValue()) {
michael@0 5762 case NS_STYLE_IMAGE_ORIENTATION_FLIP:
michael@0 5763 visibility->mImageOrientation = nsStyleImageOrientation::CreateAsFlip();
michael@0 5764 break;
michael@0 5765 case NS_STYLE_IMAGE_ORIENTATION_FROM_IMAGE:
michael@0 5766 visibility->mImageOrientation = nsStyleImageOrientation::CreateAsFromImage();
michael@0 5767 break;
michael@0 5768 default:
michael@0 5769 NS_NOTREACHED("Invalid image-orientation enumerated value");
michael@0 5770 }
michael@0 5771 } else {
michael@0 5772 MOZ_ASSERT(orientation->GetUnit() == eCSSUnit_Null, "Should be null unit");
michael@0 5773 }
michael@0 5774
michael@0 5775 COMPUTE_END_INHERITED(Visibility, visibility)
michael@0 5776 }
michael@0 5777
michael@0 5778 const void*
michael@0 5779 nsRuleNode::ComputeColorData(void* aStartStruct,
michael@0 5780 const nsRuleData* aRuleData,
michael@0 5781 nsStyleContext* aContext,
michael@0 5782 nsRuleNode* aHighestNode,
michael@0 5783 const RuleDetail aRuleDetail,
michael@0 5784 const bool aCanStoreInRuleTree)
michael@0 5785 {
michael@0 5786 COMPUTE_START_INHERITED(Color, (mPresContext), color, parentColor)
michael@0 5787
michael@0 5788 // color: color, string, inherit
michael@0 5789 // Special case for currentColor. According to CSS3, setting color to 'currentColor'
michael@0 5790 // should behave as if it is inherited
michael@0 5791 const nsCSSValue* colorValue = aRuleData->ValueForColor();
michael@0 5792 if ((colorValue->GetUnit() == eCSSUnit_EnumColor &&
michael@0 5793 colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) ||
michael@0 5794 colorValue->GetUnit() == eCSSUnit_Unset) {
michael@0 5795 color->mColor = parentColor->mColor;
michael@0 5796 canStoreInRuleTree = false;
michael@0 5797 }
michael@0 5798 else if (colorValue->GetUnit() == eCSSUnit_Initial) {
michael@0 5799 color->mColor = mPresContext->DefaultColor();
michael@0 5800 }
michael@0 5801 else {
michael@0 5802 SetColor(*colorValue, parentColor->mColor, mPresContext, aContext,
michael@0 5803 color->mColor, canStoreInRuleTree);
michael@0 5804 }
michael@0 5805
michael@0 5806 COMPUTE_END_INHERITED(Color, color)
michael@0 5807 }
michael@0 5808
michael@0 5809 // information about how to compute values for background-* properties
michael@0 5810 template <class SpecifiedValueItem, class ComputedValueItem>
michael@0 5811 struct BackgroundItemComputer {
michael@0 5812 };
michael@0 5813
michael@0 5814 template <>
michael@0 5815 struct BackgroundItemComputer<nsCSSValueList, uint8_t>
michael@0 5816 {
michael@0 5817 static void ComputeValue(nsStyleContext* aStyleContext,
michael@0 5818 const nsCSSValueList* aSpecifiedValue,
michael@0 5819 uint8_t& aComputedValue,
michael@0 5820 bool& aCanStoreInRuleTree)
michael@0 5821 {
michael@0 5822 SetDiscrete(aSpecifiedValue->mValue, aComputedValue, aCanStoreInRuleTree,
michael@0 5823 SETDSC_ENUMERATED, uint8_t(0), 0, 0, 0, 0, 0);
michael@0 5824 }
michael@0 5825 };
michael@0 5826
michael@0 5827 template <>
michael@0 5828 struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Repeat>
michael@0 5829 {
michael@0 5830 static void ComputeValue(nsStyleContext* aStyleContext,
michael@0 5831 const nsCSSValuePairList* aSpecifiedValue,
michael@0 5832 nsStyleBackground::Repeat& aComputedValue,
michael@0 5833 bool& aCanStoreInRuleTree)
michael@0 5834 {
michael@0 5835 NS_ASSERTION(aSpecifiedValue->mXValue.GetUnit() == eCSSUnit_Enumerated &&
michael@0 5836 (aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Enumerated ||
michael@0 5837 aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null),
michael@0 5838 "Invalid unit");
michael@0 5839
michael@0 5840 bool hasContraction = true;
michael@0 5841 uint8_t value = aSpecifiedValue->mXValue.GetIntValue();
michael@0 5842 switch (value) {
michael@0 5843 case NS_STYLE_BG_REPEAT_REPEAT_X:
michael@0 5844 aComputedValue.mXRepeat = NS_STYLE_BG_REPEAT_REPEAT;
michael@0 5845 aComputedValue.mYRepeat = NS_STYLE_BG_REPEAT_NO_REPEAT;
michael@0 5846 break;
michael@0 5847 case NS_STYLE_BG_REPEAT_REPEAT_Y:
michael@0 5848 aComputedValue.mXRepeat = NS_STYLE_BG_REPEAT_NO_REPEAT;
michael@0 5849 aComputedValue.mYRepeat = NS_STYLE_BG_REPEAT_REPEAT;
michael@0 5850 break;
michael@0 5851 default:
michael@0 5852 aComputedValue.mXRepeat = value;
michael@0 5853 hasContraction = false;
michael@0 5854 break;
michael@0 5855 }
michael@0 5856
michael@0 5857 if (hasContraction) {
michael@0 5858 NS_ASSERTION(aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null,
michael@0 5859 "Invalid unit.");
michael@0 5860 return;
michael@0 5861 }
michael@0 5862
michael@0 5863 switch (aSpecifiedValue->mYValue.GetUnit()) {
michael@0 5864 case eCSSUnit_Null:
michael@0 5865 aComputedValue.mYRepeat = aComputedValue.mXRepeat;
michael@0 5866 break;
michael@0 5867 case eCSSUnit_Enumerated:
michael@0 5868 value = aSpecifiedValue->mYValue.GetIntValue();
michael@0 5869 NS_ASSERTION(value == NS_STYLE_BG_REPEAT_NO_REPEAT ||
michael@0 5870 value == NS_STYLE_BG_REPEAT_REPEAT, "Unexpected value");
michael@0 5871 aComputedValue.mYRepeat = value;
michael@0 5872 break;
michael@0 5873 default:
michael@0 5874 NS_NOTREACHED("Unexpected CSS value");
michael@0 5875 break;
michael@0 5876 }
michael@0 5877 }
michael@0 5878 };
michael@0 5879
michael@0 5880 template <>
michael@0 5881 struct BackgroundItemComputer<nsCSSValueList, nsStyleImage>
michael@0 5882 {
michael@0 5883 static void ComputeValue(nsStyleContext* aStyleContext,
michael@0 5884 const nsCSSValueList* aSpecifiedValue,
michael@0 5885 nsStyleImage& aComputedValue,
michael@0 5886 bool& aCanStoreInRuleTree)
michael@0 5887 {
michael@0 5888 SetStyleImage(aStyleContext, aSpecifiedValue->mValue, aComputedValue,
michael@0 5889 aCanStoreInRuleTree);
michael@0 5890 }
michael@0 5891 };
michael@0 5892
michael@0 5893 /* Helper function for
michael@0 5894 * BackgroundItemComputer<nsCSSValue, nsStyleBackground::Position>
michael@0 5895 * It computes a single PositionCoord from an nsCSSValue object
michael@0 5896 * (contained in a list).
michael@0 5897 */
michael@0 5898 typedef nsStyleBackground::Position::PositionCoord PositionCoord;
michael@0 5899 static void
michael@0 5900 ComputeBackgroundPositionCoord(nsStyleContext* aStyleContext,
michael@0 5901 const nsCSSValue& aEdge,
michael@0 5902 const nsCSSValue& aOffset,
michael@0 5903 PositionCoord* aResult,
michael@0 5904 bool& aCanStoreInRuleTree)
michael@0 5905 {
michael@0 5906 if (eCSSUnit_Percent == aOffset.GetUnit()) {
michael@0 5907 aResult->mLength = 0;
michael@0 5908 aResult->mPercent = aOffset.GetPercentValue();
michael@0 5909 aResult->mHasPercent = true;
michael@0 5910 } else if (aOffset.IsLengthUnit()) {
michael@0 5911 aResult->mLength = CalcLength(aOffset, aStyleContext,
michael@0 5912 aStyleContext->PresContext(),
michael@0 5913 aCanStoreInRuleTree);
michael@0 5914 aResult->mPercent = 0.0f;
michael@0 5915 aResult->mHasPercent = false;
michael@0 5916 } else if (aOffset.IsCalcUnit()) {
michael@0 5917 LengthPercentPairCalcOps ops(aStyleContext,
michael@0 5918 aStyleContext->PresContext(),
michael@0 5919 aCanStoreInRuleTree);
michael@0 5920 nsRuleNode::ComputedCalc vals = ComputeCalc(aOffset, ops);
michael@0 5921 aResult->mLength = vals.mLength;
michael@0 5922 aResult->mPercent = vals.mPercent;
michael@0 5923 aResult->mHasPercent = ops.mHasPercent;
michael@0 5924 } else {
michael@0 5925 aResult->mLength = 0;
michael@0 5926 aResult->mPercent = 0.0f;
michael@0 5927 aResult->mHasPercent = false;
michael@0 5928 NS_ASSERTION(aOffset.GetUnit() == eCSSUnit_Null, "unexpected unit");
michael@0 5929 }
michael@0 5930
michael@0 5931 if (eCSSUnit_Enumerated == aEdge.GetUnit()) {
michael@0 5932 int sign;
michael@0 5933 if (aEdge.GetIntValue() & (NS_STYLE_BG_POSITION_BOTTOM |
michael@0 5934 NS_STYLE_BG_POSITION_RIGHT)) {
michael@0 5935 sign = -1;
michael@0 5936 } else {
michael@0 5937 sign = 1;
michael@0 5938 }
michael@0 5939 aResult->mPercent = GetFloatFromBoxPosition(aEdge.GetIntValue()) +
michael@0 5940 sign * aResult->mPercent;
michael@0 5941 aResult->mLength = sign * aResult->mLength;
michael@0 5942 aResult->mHasPercent = true;
michael@0 5943 } else {
michael@0 5944 NS_ASSERTION(eCSSUnit_Null == aEdge.GetUnit(), "unexpected unit");
michael@0 5945 }
michael@0 5946 }
michael@0 5947
michael@0 5948 template <>
michael@0 5949 struct BackgroundItemComputer<nsCSSValueList, nsStyleBackground::Position>
michael@0 5950 {
michael@0 5951 static void ComputeValue(nsStyleContext* aStyleContext,
michael@0 5952 const nsCSSValueList* aSpecifiedValue,
michael@0 5953 nsStyleBackground::Position& aComputedValue,
michael@0 5954 bool& aCanStoreInRuleTree)
michael@0 5955 {
michael@0 5956 NS_ASSERTION(aSpecifiedValue->mValue.GetUnit() == eCSSUnit_Array, "bg-position not an array");
michael@0 5957
michael@0 5958 nsRefPtr<nsCSSValue::Array> bgPositionArray =
michael@0 5959 aSpecifiedValue->mValue.GetArrayValue();
michael@0 5960 const nsCSSValue &xEdge = bgPositionArray->Item(0);
michael@0 5961 const nsCSSValue &xOffset = bgPositionArray->Item(1);
michael@0 5962 const nsCSSValue &yEdge = bgPositionArray->Item(2);
michael@0 5963 const nsCSSValue &yOffset = bgPositionArray->Item(3);
michael@0 5964
michael@0 5965 NS_ASSERTION((eCSSUnit_Enumerated == xEdge.GetUnit() ||
michael@0 5966 eCSSUnit_Null == xEdge.GetUnit()) &&
michael@0 5967 (eCSSUnit_Enumerated == yEdge.GetUnit() ||
michael@0 5968 eCSSUnit_Null == yEdge.GetUnit()) &&
michael@0 5969 eCSSUnit_Enumerated != xOffset.GetUnit() &&
michael@0 5970 eCSSUnit_Enumerated != yOffset.GetUnit(),
michael@0 5971 "Invalid background position");
michael@0 5972
michael@0 5973 ComputeBackgroundPositionCoord(aStyleContext, xEdge, xOffset,
michael@0 5974 &aComputedValue.mXPosition,
michael@0 5975 aCanStoreInRuleTree);
michael@0 5976
michael@0 5977 ComputeBackgroundPositionCoord(aStyleContext, yEdge, yOffset,
michael@0 5978 &aComputedValue.mYPosition,
michael@0 5979 aCanStoreInRuleTree);
michael@0 5980 }
michael@0 5981 };
michael@0 5982
michael@0 5983
michael@0 5984 struct BackgroundSizeAxis {
michael@0 5985 nsCSSValue nsCSSValuePairList::* specified;
michael@0 5986 nsStyleBackground::Size::Dimension nsStyleBackground::Size::* result;
michael@0 5987 uint8_t nsStyleBackground::Size::* type;
michael@0 5988 };
michael@0 5989
michael@0 5990 static const BackgroundSizeAxis gBGSizeAxes[] = {
michael@0 5991 { &nsCSSValuePairList::mXValue,
michael@0 5992 &nsStyleBackground::Size::mWidth,
michael@0 5993 &nsStyleBackground::Size::mWidthType },
michael@0 5994 { &nsCSSValuePairList::mYValue,
michael@0 5995 &nsStyleBackground::Size::mHeight,
michael@0 5996 &nsStyleBackground::Size::mHeightType }
michael@0 5997 };
michael@0 5998
michael@0 5999 template <>
michael@0 6000 struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Size>
michael@0 6001 {
michael@0 6002 static void ComputeValue(nsStyleContext* aStyleContext,
michael@0 6003 const nsCSSValuePairList* aSpecifiedValue,
michael@0 6004 nsStyleBackground::Size& aComputedValue,
michael@0 6005 bool& aCanStoreInRuleTree)
michael@0 6006 {
michael@0 6007 nsStyleBackground::Size &size = aComputedValue;
michael@0 6008 for (const BackgroundSizeAxis *axis = gBGSizeAxes,
michael@0 6009 *axis_end = ArrayEnd(gBGSizeAxes);
michael@0 6010 axis < axis_end; ++axis) {
michael@0 6011 const nsCSSValue &specified = aSpecifiedValue->*(axis->specified);
michael@0 6012 if (eCSSUnit_Auto == specified.GetUnit()) {
michael@0 6013 size.*(axis->type) = nsStyleBackground::Size::eAuto;
michael@0 6014 }
michael@0 6015 else if (eCSSUnit_Enumerated == specified.GetUnit()) {
michael@0 6016 static_assert(nsStyleBackground::Size::eContain ==
michael@0 6017 NS_STYLE_BG_SIZE_CONTAIN &&
michael@0 6018 nsStyleBackground::Size::eCover ==
michael@0 6019 NS_STYLE_BG_SIZE_COVER,
michael@0 6020 "background size constants out of sync");
michael@0 6021 NS_ABORT_IF_FALSE(specified.GetIntValue() == NS_STYLE_BG_SIZE_CONTAIN ||
michael@0 6022 specified.GetIntValue() == NS_STYLE_BG_SIZE_COVER,
michael@0 6023 "invalid enumerated value for size coordinate");
michael@0 6024 size.*(axis->type) = specified.GetIntValue();
michael@0 6025 }
michael@0 6026 else if (eCSSUnit_Null == specified.GetUnit()) {
michael@0 6027 NS_ABORT_IF_FALSE(axis == gBGSizeAxes + 1,
michael@0 6028 "null allowed only as height value, and only "
michael@0 6029 "for contain/cover/initial/inherit");
michael@0 6030 #ifdef DEBUG
michael@0 6031 {
michael@0 6032 const nsCSSValue &widthValue = aSpecifiedValue->mXValue;
michael@0 6033 NS_ABORT_IF_FALSE(widthValue.GetUnit() != eCSSUnit_Inherit &&
michael@0 6034 widthValue.GetUnit() != eCSSUnit_Initial &&
michael@0 6035 widthValue.GetUnit() != eCSSUnit_Unset,
michael@0 6036 "initial/inherit/unset should already have been handled");
michael@0 6037 NS_ABORT_IF_FALSE(widthValue.GetUnit() == eCSSUnit_Enumerated &&
michael@0 6038 (widthValue.GetIntValue() == NS_STYLE_BG_SIZE_CONTAIN ||
michael@0 6039 widthValue.GetIntValue() == NS_STYLE_BG_SIZE_COVER),
michael@0 6040 "null height value not corresponding to allowable "
michael@0 6041 "non-null width value");
michael@0 6042 }
michael@0 6043 #endif
michael@0 6044 size.*(axis->type) = size.mWidthType;
michael@0 6045 }
michael@0 6046 else if (eCSSUnit_Percent == specified.GetUnit()) {
michael@0 6047 (size.*(axis->result)).mLength = 0;
michael@0 6048 (size.*(axis->result)).mPercent = specified.GetPercentValue();
michael@0 6049 (size.*(axis->result)).mHasPercent = true;
michael@0 6050 size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
michael@0 6051 }
michael@0 6052 else if (specified.IsLengthUnit()) {
michael@0 6053 (size.*(axis->result)).mLength =
michael@0 6054 CalcLength(specified, aStyleContext, aStyleContext->PresContext(),
michael@0 6055 aCanStoreInRuleTree);
michael@0 6056 (size.*(axis->result)).mPercent = 0.0f;
michael@0 6057 (size.*(axis->result)).mHasPercent = false;
michael@0 6058 size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
michael@0 6059 } else {
michael@0 6060 NS_ABORT_IF_FALSE(specified.IsCalcUnit(), "unexpected unit");
michael@0 6061 LengthPercentPairCalcOps ops(aStyleContext,
michael@0 6062 aStyleContext->PresContext(),
michael@0 6063 aCanStoreInRuleTree);
michael@0 6064 nsRuleNode::ComputedCalc vals = ComputeCalc(specified, ops);
michael@0 6065 (size.*(axis->result)).mLength = vals.mLength;
michael@0 6066 (size.*(axis->result)).mPercent = vals.mPercent;
michael@0 6067 (size.*(axis->result)).mHasPercent = ops.mHasPercent;
michael@0 6068 size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
michael@0 6069 }
michael@0 6070 }
michael@0 6071
michael@0 6072 NS_ABORT_IF_FALSE(size.mWidthType < nsStyleBackground::Size::eDimensionType_COUNT,
michael@0 6073 "bad width type");
michael@0 6074 NS_ABORT_IF_FALSE(size.mHeightType < nsStyleBackground::Size::eDimensionType_COUNT,
michael@0 6075 "bad height type");
michael@0 6076 NS_ABORT_IF_FALSE((size.mWidthType != nsStyleBackground::Size::eContain &&
michael@0 6077 size.mWidthType != nsStyleBackground::Size::eCover) ||
michael@0 6078 size.mWidthType == size.mHeightType,
michael@0 6079 "contain/cover apply to both dimensions or to neither");
michael@0 6080 }
michael@0 6081 };
michael@0 6082
michael@0 6083 template <class ComputedValueItem>
michael@0 6084 static void
michael@0 6085 SetBackgroundList(nsStyleContext* aStyleContext,
michael@0 6086 const nsCSSValue& aValue,
michael@0 6087 nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
michael@0 6088 const nsAutoTArray<nsStyleBackground::Layer, 1> &aParentLayers,
michael@0 6089 ComputedValueItem nsStyleBackground::Layer::* aResultLocation,
michael@0 6090 ComputedValueItem aInitialValue,
michael@0 6091 uint32_t aParentItemCount,
michael@0 6092 uint32_t& aItemCount,
michael@0 6093 uint32_t& aMaxItemCount,
michael@0 6094 bool& aRebuild,
michael@0 6095 bool& aCanStoreInRuleTree)
michael@0 6096 {
michael@0 6097 switch (aValue.GetUnit()) {
michael@0 6098 case eCSSUnit_Null:
michael@0 6099 break;
michael@0 6100
michael@0 6101 case eCSSUnit_Inherit:
michael@0 6102 aRebuild = true;
michael@0 6103 aCanStoreInRuleTree = false;
michael@0 6104 aLayers.EnsureLengthAtLeast(aParentItemCount);
michael@0 6105 aItemCount = aParentItemCount;
michael@0 6106 for (uint32_t i = 0; i < aParentItemCount; ++i) {
michael@0 6107 aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
michael@0 6108 }
michael@0 6109 break;
michael@0 6110
michael@0 6111 case eCSSUnit_Initial:
michael@0 6112 case eCSSUnit_Unset:
michael@0 6113 aRebuild = true;
michael@0 6114 aItemCount = 1;
michael@0 6115 aLayers[0].*aResultLocation = aInitialValue;
michael@0 6116 break;
michael@0 6117
michael@0 6118 case eCSSUnit_List:
michael@0 6119 case eCSSUnit_ListDep: {
michael@0 6120 aRebuild = true;
michael@0 6121 aItemCount = 0;
michael@0 6122 const nsCSSValueList* item = aValue.GetListValue();
michael@0 6123 do {
michael@0 6124 NS_ASSERTION(item->mValue.GetUnit() != eCSSUnit_Null &&
michael@0 6125 item->mValue.GetUnit() != eCSSUnit_Inherit &&
michael@0 6126 item->mValue.GetUnit() != eCSSUnit_Initial &&
michael@0 6127 item->mValue.GetUnit() != eCSSUnit_Unset,
michael@0 6128 "unexpected unit");
michael@0 6129 ++aItemCount;
michael@0 6130 aLayers.EnsureLengthAtLeast(aItemCount);
michael@0 6131 BackgroundItemComputer<nsCSSValueList, ComputedValueItem>
michael@0 6132 ::ComputeValue(aStyleContext, item,
michael@0 6133 aLayers[aItemCount-1].*aResultLocation,
michael@0 6134 aCanStoreInRuleTree);
michael@0 6135 item = item->mNext;
michael@0 6136 } while (item);
michael@0 6137 break;
michael@0 6138 }
michael@0 6139
michael@0 6140 default:
michael@0 6141 NS_ABORT_IF_FALSE(false,
michael@0 6142 nsPrintfCString("unexpected unit %d",
michael@0 6143 aValue.GetUnit()).get());
michael@0 6144 }
michael@0 6145
michael@0 6146 if (aItemCount > aMaxItemCount)
michael@0 6147 aMaxItemCount = aItemCount;
michael@0 6148 }
michael@0 6149
michael@0 6150 template <class ComputedValueItem>
michael@0 6151 static void
michael@0 6152 SetBackgroundPairList(nsStyleContext* aStyleContext,
michael@0 6153 const nsCSSValue& aValue,
michael@0 6154 nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
michael@0 6155 const nsAutoTArray<nsStyleBackground::Layer, 1>
michael@0 6156 &aParentLayers,
michael@0 6157 ComputedValueItem nsStyleBackground::Layer::*
michael@0 6158 aResultLocation,
michael@0 6159 ComputedValueItem aInitialValue,
michael@0 6160 uint32_t aParentItemCount,
michael@0 6161 uint32_t& aItemCount,
michael@0 6162 uint32_t& aMaxItemCount,
michael@0 6163 bool& aRebuild,
michael@0 6164 bool& aCanStoreInRuleTree)
michael@0 6165 {
michael@0 6166 switch (aValue.GetUnit()) {
michael@0 6167 case eCSSUnit_Null:
michael@0 6168 break;
michael@0 6169
michael@0 6170 case eCSSUnit_Inherit:
michael@0 6171 aRebuild = true;
michael@0 6172 aCanStoreInRuleTree = false;
michael@0 6173 aLayers.EnsureLengthAtLeast(aParentItemCount);
michael@0 6174 aItemCount = aParentItemCount;
michael@0 6175 for (uint32_t i = 0; i < aParentItemCount; ++i) {
michael@0 6176 aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
michael@0 6177 }
michael@0 6178 break;
michael@0 6179
michael@0 6180 case eCSSUnit_Initial:
michael@0 6181 case eCSSUnit_Unset:
michael@0 6182 aRebuild = true;
michael@0 6183 aItemCount = 1;
michael@0 6184 aLayers[0].*aResultLocation = aInitialValue;
michael@0 6185 break;
michael@0 6186
michael@0 6187 case eCSSUnit_PairList:
michael@0 6188 case eCSSUnit_PairListDep: {
michael@0 6189 aRebuild = true;
michael@0 6190 aItemCount = 0;
michael@0 6191 const nsCSSValuePairList* item = aValue.GetPairListValue();
michael@0 6192 do {
michael@0 6193 NS_ASSERTION(item->mXValue.GetUnit() != eCSSUnit_Inherit &&
michael@0 6194 item->mXValue.GetUnit() != eCSSUnit_Initial &&
michael@0 6195 item->mXValue.GetUnit() != eCSSUnit_Unset &&
michael@0 6196 item->mYValue.GetUnit() != eCSSUnit_Inherit &&
michael@0 6197 item->mYValue.GetUnit() != eCSSUnit_Initial &&
michael@0 6198 item->mYValue.GetUnit() != eCSSUnit_Unset,
michael@0 6199 "unexpected unit");
michael@0 6200 ++aItemCount;
michael@0 6201 aLayers.EnsureLengthAtLeast(aItemCount);
michael@0 6202 BackgroundItemComputer<nsCSSValuePairList, ComputedValueItem>
michael@0 6203 ::ComputeValue(aStyleContext, item,
michael@0 6204 aLayers[aItemCount-1].*aResultLocation,
michael@0 6205 aCanStoreInRuleTree);
michael@0 6206 item = item->mNext;
michael@0 6207 } while (item);
michael@0 6208 break;
michael@0 6209 }
michael@0 6210
michael@0 6211 default:
michael@0 6212 NS_ABORT_IF_FALSE(false,
michael@0 6213 nsPrintfCString("unexpected unit %d",
michael@0 6214 aValue.GetUnit()).get());
michael@0 6215 }
michael@0 6216
michael@0 6217 if (aItemCount > aMaxItemCount)
michael@0 6218 aMaxItemCount = aItemCount;
michael@0 6219 }
michael@0 6220
michael@0 6221 template <class ComputedValueItem>
michael@0 6222 static void
michael@0 6223 FillBackgroundList(nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
michael@0 6224 ComputedValueItem nsStyleBackground::Layer::* aResultLocation,
michael@0 6225 uint32_t aItemCount, uint32_t aFillCount)
michael@0 6226 {
michael@0 6227 NS_PRECONDITION(aFillCount <= aLayers.Length(), "unexpected array length");
michael@0 6228 for (uint32_t sourceLayer = 0, destLayer = aItemCount;
michael@0 6229 destLayer < aFillCount;
michael@0 6230 ++sourceLayer, ++destLayer) {
michael@0 6231 aLayers[destLayer].*aResultLocation =
michael@0 6232 aLayers[sourceLayer].*aResultLocation;
michael@0 6233 }
michael@0 6234 }
michael@0 6235
michael@0 6236 const void*
michael@0 6237 nsRuleNode::ComputeBackgroundData(void* aStartStruct,
michael@0 6238 const nsRuleData* aRuleData,
michael@0 6239 nsStyleContext* aContext,
michael@0 6240 nsRuleNode* aHighestNode,
michael@0 6241 const RuleDetail aRuleDetail,
michael@0 6242 const bool aCanStoreInRuleTree)
michael@0 6243 {
michael@0 6244 COMPUTE_START_RESET(Background, (), bg, parentBG)
michael@0 6245
michael@0 6246 // background-color: color, string, inherit
michael@0 6247 const nsCSSValue* backColorValue = aRuleData->ValueForBackgroundColor();
michael@0 6248 if (eCSSUnit_Initial == backColorValue->GetUnit() ||
michael@0 6249 eCSSUnit_Unset == backColorValue->GetUnit()) {
michael@0 6250 bg->mBackgroundColor = NS_RGBA(0, 0, 0, 0);
michael@0 6251 } else if (!SetColor(*backColorValue, parentBG->mBackgroundColor,
michael@0 6252 mPresContext, aContext, bg->mBackgroundColor,
michael@0 6253 canStoreInRuleTree)) {
michael@0 6254 NS_ASSERTION(eCSSUnit_Null == backColorValue->GetUnit(),
michael@0 6255 "unexpected color unit");
michael@0 6256 }
michael@0 6257
michael@0 6258 uint32_t maxItemCount = 1;
michael@0 6259 bool rebuild = false;
michael@0 6260
michael@0 6261 // background-image: url (stored as image), none, inherit [list]
michael@0 6262 nsStyleImage initialImage;
michael@0 6263 SetBackgroundList(aContext, *aRuleData->ValueForBackgroundImage(),
michael@0 6264 bg->mLayers,
michael@0 6265 parentBG->mLayers, &nsStyleBackground::Layer::mImage,
michael@0 6266 initialImage, parentBG->mImageCount, bg->mImageCount,
michael@0 6267 maxItemCount, rebuild, canStoreInRuleTree);
michael@0 6268
michael@0 6269 // background-repeat: enum, inherit, initial [pair list]
michael@0 6270 nsStyleBackground::Repeat initialRepeat;
michael@0 6271 initialRepeat.SetInitialValues();
michael@0 6272 SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundRepeat(),
michael@0 6273 bg->mLayers,
michael@0 6274 parentBG->mLayers, &nsStyleBackground::Layer::mRepeat,
michael@0 6275 initialRepeat, parentBG->mRepeatCount,
michael@0 6276 bg->mRepeatCount, maxItemCount, rebuild,
michael@0 6277 canStoreInRuleTree);
michael@0 6278
michael@0 6279 // background-attachment: enum, inherit, initial [list]
michael@0 6280 SetBackgroundList(aContext, *aRuleData->ValueForBackgroundAttachment(),
michael@0 6281 bg->mLayers, parentBG->mLayers,
michael@0 6282 &nsStyleBackground::Layer::mAttachment,
michael@0 6283 uint8_t(NS_STYLE_BG_ATTACHMENT_SCROLL),
michael@0 6284 parentBG->mAttachmentCount,
michael@0 6285 bg->mAttachmentCount, maxItemCount, rebuild,
michael@0 6286 canStoreInRuleTree);
michael@0 6287
michael@0 6288 // background-clip: enum, inherit, initial [list]
michael@0 6289 SetBackgroundList(aContext, *aRuleData->ValueForBackgroundClip(),
michael@0 6290 bg->mLayers,
michael@0 6291 parentBG->mLayers, &nsStyleBackground::Layer::mClip,
michael@0 6292 uint8_t(NS_STYLE_BG_CLIP_BORDER), parentBG->mClipCount,
michael@0 6293 bg->mClipCount, maxItemCount, rebuild, canStoreInRuleTree);
michael@0 6294
michael@0 6295 // background-inline-policy: enum, inherit, initial
michael@0 6296 SetDiscrete(*aRuleData->ValueForBackgroundInlinePolicy(),
michael@0 6297 bg->mBackgroundInlinePolicy,
michael@0 6298 canStoreInRuleTree,
michael@0 6299 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 6300 parentBG->mBackgroundInlinePolicy,
michael@0 6301 NS_STYLE_BG_INLINE_POLICY_CONTINUOUS, 0, 0, 0, 0);
michael@0 6302
michael@0 6303 // background-blend-mode: enum, inherit, initial [list]
michael@0 6304 SetBackgroundList(aContext, *aRuleData->ValueForBackgroundBlendMode(),
michael@0 6305 bg->mLayers,
michael@0 6306 parentBG->mLayers, &nsStyleBackground::Layer::mBlendMode,
michael@0 6307 uint8_t(NS_STYLE_BLEND_NORMAL), parentBG->mBlendModeCount,
michael@0 6308 bg->mBlendModeCount, maxItemCount, rebuild,
michael@0 6309 canStoreInRuleTree);
michael@0 6310
michael@0 6311 // background-origin: enum, inherit, initial [list]
michael@0 6312 SetBackgroundList(aContext, *aRuleData->ValueForBackgroundOrigin(),
michael@0 6313 bg->mLayers,
michael@0 6314 parentBG->mLayers, &nsStyleBackground::Layer::mOrigin,
michael@0 6315 uint8_t(NS_STYLE_BG_ORIGIN_PADDING), parentBG->mOriginCount,
michael@0 6316 bg->mOriginCount, maxItemCount, rebuild,
michael@0 6317 canStoreInRuleTree);
michael@0 6318
michael@0 6319 // background-position: enum, length, percent (flags), inherit [pair list]
michael@0 6320 nsStyleBackground::Position initialPosition;
michael@0 6321 initialPosition.SetInitialValues();
michael@0 6322 SetBackgroundList(aContext, *aRuleData->ValueForBackgroundPosition(),
michael@0 6323 bg->mLayers,
michael@0 6324 parentBG->mLayers, &nsStyleBackground::Layer::mPosition,
michael@0 6325 initialPosition, parentBG->mPositionCount,
michael@0 6326 bg->mPositionCount, maxItemCount, rebuild,
michael@0 6327 canStoreInRuleTree);
michael@0 6328
michael@0 6329 // background-size: enum, length, auto, inherit, initial [pair list]
michael@0 6330 nsStyleBackground::Size initialSize;
michael@0 6331 initialSize.SetInitialValues();
michael@0 6332 SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundSize(),
michael@0 6333 bg->mLayers,
michael@0 6334 parentBG->mLayers, &nsStyleBackground::Layer::mSize,
michael@0 6335 initialSize, parentBG->mSizeCount,
michael@0 6336 bg->mSizeCount, maxItemCount, rebuild,
michael@0 6337 canStoreInRuleTree);
michael@0 6338
michael@0 6339 if (rebuild) {
michael@0 6340 // Delete any extra items. We need to keep layers in which any
michael@0 6341 // property was specified.
michael@0 6342 bg->mLayers.TruncateLength(maxItemCount);
michael@0 6343
michael@0 6344 uint32_t fillCount = bg->mImageCount;
michael@0 6345 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mImage,
michael@0 6346 bg->mImageCount, fillCount);
michael@0 6347 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mRepeat,
michael@0 6348 bg->mRepeatCount, fillCount);
michael@0 6349 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mAttachment,
michael@0 6350 bg->mAttachmentCount, fillCount);
michael@0 6351 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mClip,
michael@0 6352 bg->mClipCount, fillCount);
michael@0 6353 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mBlendMode,
michael@0 6354 bg->mBlendModeCount, fillCount);
michael@0 6355 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mOrigin,
michael@0 6356 bg->mOriginCount, fillCount);
michael@0 6357 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mPosition,
michael@0 6358 bg->mPositionCount, fillCount);
michael@0 6359 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mSize,
michael@0 6360 bg->mSizeCount, fillCount);
michael@0 6361 }
michael@0 6362
michael@0 6363 // Now that the dust has settled, register the images with the document
michael@0 6364 for (uint32_t i = 0; i < bg->mImageCount; ++i)
michael@0 6365 bg->mLayers[i].TrackImages(aContext->PresContext());
michael@0 6366
michael@0 6367 COMPUTE_END_RESET(Background, bg)
michael@0 6368 }
michael@0 6369
michael@0 6370 const void*
michael@0 6371 nsRuleNode::ComputeMarginData(void* aStartStruct,
michael@0 6372 const nsRuleData* aRuleData,
michael@0 6373 nsStyleContext* aContext,
michael@0 6374 nsRuleNode* aHighestNode,
michael@0 6375 const RuleDetail aRuleDetail,
michael@0 6376 const bool aCanStoreInRuleTree)
michael@0 6377 {
michael@0 6378 COMPUTE_START_RESET(Margin, (), margin, parentMargin)
michael@0 6379
michael@0 6380 // margin: length, percent, auto, inherit
michael@0 6381 nsStyleCoord coord;
michael@0 6382 nsCSSRect ourMargin;
michael@0 6383 ourMargin.mTop = *aRuleData->ValueForMarginTop();
michael@0 6384 ourMargin.mRight = *aRuleData->ValueForMarginRightValue();
michael@0 6385 ourMargin.mBottom = *aRuleData->ValueForMarginBottom();
michael@0 6386 ourMargin.mLeft = *aRuleData->ValueForMarginLeftValue();
michael@0 6387 AdjustLogicalBoxProp(aContext,
michael@0 6388 *aRuleData->ValueForMarginLeftLTRSource(),
michael@0 6389 *aRuleData->ValueForMarginLeftRTLSource(),
michael@0 6390 *aRuleData->ValueForMarginStartValue(),
michael@0 6391 *aRuleData->ValueForMarginEndValue(),
michael@0 6392 NS_SIDE_LEFT, ourMargin, canStoreInRuleTree);
michael@0 6393 AdjustLogicalBoxProp(aContext,
michael@0 6394 *aRuleData->ValueForMarginRightLTRSource(),
michael@0 6395 *aRuleData->ValueForMarginRightRTLSource(),
michael@0 6396 *aRuleData->ValueForMarginEndValue(),
michael@0 6397 *aRuleData->ValueForMarginStartValue(),
michael@0 6398 NS_SIDE_RIGHT, ourMargin, canStoreInRuleTree);
michael@0 6399 NS_FOR_CSS_SIDES(side) {
michael@0 6400 nsStyleCoord parentCoord = parentMargin->mMargin.Get(side);
michael@0 6401 if (SetCoord(ourMargin.*(nsCSSRect::sides[side]),
michael@0 6402 coord, parentCoord,
michael@0 6403 SETCOORD_LPAH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
michael@0 6404 SETCOORD_UNSET_INITIAL,
michael@0 6405 aContext, mPresContext, canStoreInRuleTree)) {
michael@0 6406 margin->mMargin.Set(side, coord);
michael@0 6407 }
michael@0 6408 }
michael@0 6409
michael@0 6410 margin->RecalcData();
michael@0 6411 COMPUTE_END_RESET(Margin, margin)
michael@0 6412 }
michael@0 6413
michael@0 6414 static void
michael@0 6415 SetBorderImageRect(const nsCSSValue& aValue,
michael@0 6416 /** outparam */ nsCSSRect& aRect)
michael@0 6417 {
michael@0 6418 switch (aValue.GetUnit()) {
michael@0 6419 case eCSSUnit_Null:
michael@0 6420 aRect.Reset();
michael@0 6421 break;
michael@0 6422 case eCSSUnit_Rect:
michael@0 6423 aRect = aValue.GetRectValue();
michael@0 6424 break;
michael@0 6425 case eCSSUnit_Inherit:
michael@0 6426 case eCSSUnit_Initial:
michael@0 6427 case eCSSUnit_Unset:
michael@0 6428 aRect.SetAllSidesTo(aValue);
michael@0 6429 break;
michael@0 6430 default:
michael@0 6431 NS_ASSERTION(false, "Unexpected border image value for rect.");
michael@0 6432 }
michael@0 6433 }
michael@0 6434
michael@0 6435 static void
michael@0 6436 SetBorderImagePair(const nsCSSValue& aValue,
michael@0 6437 /** outparam */ nsCSSValuePair& aPair)
michael@0 6438 {
michael@0 6439 switch (aValue.GetUnit()) {
michael@0 6440 case eCSSUnit_Null:
michael@0 6441 aPair.Reset();
michael@0 6442 break;
michael@0 6443 case eCSSUnit_Pair:
michael@0 6444 aPair = aValue.GetPairValue();
michael@0 6445 break;
michael@0 6446 case eCSSUnit_Inherit:
michael@0 6447 case eCSSUnit_Initial:
michael@0 6448 case eCSSUnit_Unset:
michael@0 6449 aPair.SetBothValuesTo(aValue);
michael@0 6450 break;
michael@0 6451 default:
michael@0 6452 NS_ASSERTION(false, "Unexpected border image value for pair.");
michael@0 6453 }
michael@0 6454 }
michael@0 6455
michael@0 6456 static void
michael@0 6457 SetBorderImageSlice(const nsCSSValue& aValue,
michael@0 6458 /** outparam */ nsCSSValue& aSlice,
michael@0 6459 /** outparam */ nsCSSValue& aFill)
michael@0 6460 {
michael@0 6461 const nsCSSValueList* valueList;
michael@0 6462 switch (aValue.GetUnit()) {
michael@0 6463 case eCSSUnit_Null:
michael@0 6464 aSlice.Reset();
michael@0 6465 aFill.Reset();
michael@0 6466 break;
michael@0 6467 case eCSSUnit_List:
michael@0 6468 // Get slice dimensions.
michael@0 6469 valueList = aValue.GetListValue();
michael@0 6470 aSlice = valueList->mValue;
michael@0 6471
michael@0 6472 // Get "fill" keyword.
michael@0 6473 valueList = valueList->mNext;
michael@0 6474 if (valueList) {
michael@0 6475 aFill = valueList->mValue;
michael@0 6476 } else {
michael@0 6477 aFill.SetInitialValue();
michael@0 6478 }
michael@0 6479 break;
michael@0 6480 case eCSSUnit_Inherit:
michael@0 6481 case eCSSUnit_Initial:
michael@0 6482 case eCSSUnit_Unset:
michael@0 6483 aSlice = aValue;
michael@0 6484 aFill = aValue;
michael@0 6485 break;
michael@0 6486 default:
michael@0 6487 NS_ASSERTION(false, "Unexpected border image value for pair.");
michael@0 6488 }
michael@0 6489 }
michael@0 6490
michael@0 6491 const void*
michael@0 6492 nsRuleNode::ComputeBorderData(void* aStartStruct,
michael@0 6493 const nsRuleData* aRuleData,
michael@0 6494 nsStyleContext* aContext,
michael@0 6495 nsRuleNode* aHighestNode,
michael@0 6496 const RuleDetail aRuleDetail,
michael@0 6497 const bool aCanStoreInRuleTree)
michael@0 6498 {
michael@0 6499 COMPUTE_START_RESET(Border, (mPresContext), border, parentBorder)
michael@0 6500
michael@0 6501 // box-shadow: none, list, inherit, initial
michael@0 6502 const nsCSSValue* boxShadowValue = aRuleData->ValueForBoxShadow();
michael@0 6503 switch (boxShadowValue->GetUnit()) {
michael@0 6504 case eCSSUnit_Null:
michael@0 6505 break;
michael@0 6506
michael@0 6507 case eCSSUnit_Initial:
michael@0 6508 case eCSSUnit_Unset:
michael@0 6509 case eCSSUnit_None:
michael@0 6510 border->mBoxShadow = nullptr;
michael@0 6511 break;
michael@0 6512
michael@0 6513 case eCSSUnit_Inherit:
michael@0 6514 border->mBoxShadow = parentBorder->mBoxShadow;
michael@0 6515 canStoreInRuleTree = false;
michael@0 6516 break;
michael@0 6517
michael@0 6518 case eCSSUnit_List:
michael@0 6519 case eCSSUnit_ListDep:
michael@0 6520 border->mBoxShadow = GetShadowData(boxShadowValue->GetListValue(),
michael@0 6521 aContext, true, canStoreInRuleTree);
michael@0 6522 break;
michael@0 6523
michael@0 6524 default:
michael@0 6525 NS_ABORT_IF_FALSE(false,
michael@0 6526 nsPrintfCString("unrecognized shadow unit %d",
michael@0 6527 boxShadowValue->GetUnit()).get());
michael@0 6528 }
michael@0 6529
michael@0 6530 // border-width, border-*-width: length, enum, inherit
michael@0 6531 nsStyleCoord coord;
michael@0 6532 nsCSSRect ourBorderWidth;
michael@0 6533 ourBorderWidth.mTop = *aRuleData->ValueForBorderTopWidth();
michael@0 6534 ourBorderWidth.mRight = *aRuleData->ValueForBorderRightWidthValue();
michael@0 6535 ourBorderWidth.mBottom = *aRuleData->ValueForBorderBottomWidth();
michael@0 6536 ourBorderWidth.mLeft = *aRuleData->ValueForBorderLeftWidthValue();
michael@0 6537 AdjustLogicalBoxProp(aContext,
michael@0 6538 *aRuleData->ValueForBorderLeftWidthLTRSource(),
michael@0 6539 *aRuleData->ValueForBorderLeftWidthRTLSource(),
michael@0 6540 *aRuleData->ValueForBorderStartWidthValue(),
michael@0 6541 *aRuleData->ValueForBorderEndWidthValue(),
michael@0 6542 NS_SIDE_LEFT, ourBorderWidth, canStoreInRuleTree);
michael@0 6543 AdjustLogicalBoxProp(aContext,
michael@0 6544 *aRuleData->ValueForBorderRightWidthLTRSource(),
michael@0 6545 *aRuleData->ValueForBorderRightWidthRTLSource(),
michael@0 6546 *aRuleData->ValueForBorderEndWidthValue(),
michael@0 6547 *aRuleData->ValueForBorderStartWidthValue(),
michael@0 6548 NS_SIDE_RIGHT, ourBorderWidth, canStoreInRuleTree);
michael@0 6549 { // scope for compilers with broken |for| loop scoping
michael@0 6550 NS_FOR_CSS_SIDES(side) {
michael@0 6551 const nsCSSValue &value = ourBorderWidth.*(nsCSSRect::sides[side]);
michael@0 6552 NS_ASSERTION(eCSSUnit_Percent != value.GetUnit(),
michael@0 6553 "Percentage borders not implemented yet "
michael@0 6554 "If implementing, make sure to fix all consumers of "
michael@0 6555 "nsStyleBorder, the IsPercentageAwareChild method, "
michael@0 6556 "the nsAbsoluteContainingBlock::FrameDependsOnContainer "
michael@0 6557 "method, the "
michael@0 6558 "nsLineLayout::IsPercentageAwareReplacedElement method "
michael@0 6559 "and probably some other places");
michael@0 6560 if (eCSSUnit_Enumerated == value.GetUnit()) {
michael@0 6561 NS_ASSERTION(value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
michael@0 6562 value.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
michael@0 6563 value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
michael@0 6564 "Unexpected enum value");
michael@0 6565 border->SetBorderWidth(side,
michael@0 6566 (mPresContext->GetBorderWidthTable())[value.GetIntValue()]);
michael@0 6567 }
michael@0 6568 // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
michael@0 6569 else if (SetCoord(value, coord, nsStyleCoord(),
michael@0 6570 SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
michael@0 6571 aContext, mPresContext, canStoreInRuleTree)) {
michael@0 6572 NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
michael@0 6573 // clamp negative calc() to 0.
michael@0 6574 border->SetBorderWidth(side, std::max(coord.GetCoordValue(), 0));
michael@0 6575 }
michael@0 6576 else if (eCSSUnit_Inherit == value.GetUnit()) {
michael@0 6577 canStoreInRuleTree = false;
michael@0 6578 border->SetBorderWidth(side,
michael@0 6579 parentBorder->GetComputedBorder().Side(side));
michael@0 6580 }
michael@0 6581 else if (eCSSUnit_Initial == value.GetUnit() ||
michael@0 6582 eCSSUnit_Unset == value.GetUnit()) {
michael@0 6583 border->SetBorderWidth(side,
michael@0 6584 (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
michael@0 6585 }
michael@0 6586 else {
michael@0 6587 NS_ASSERTION(eCSSUnit_Null == value.GetUnit(),
michael@0 6588 "missing case handling border width");
michael@0 6589 }
michael@0 6590 }
michael@0 6591 }
michael@0 6592
michael@0 6593 // border-style, border-*-style: enum, inherit
michael@0 6594 nsCSSRect ourBorderStyle;
michael@0 6595 ourBorderStyle.mTop = *aRuleData->ValueForBorderTopStyle();
michael@0 6596 ourBorderStyle.mRight = *aRuleData->ValueForBorderRightStyleValue();
michael@0 6597 ourBorderStyle.mBottom = *aRuleData->ValueForBorderBottomStyle();
michael@0 6598 ourBorderStyle.mLeft = *aRuleData->ValueForBorderLeftStyleValue();
michael@0 6599 AdjustLogicalBoxProp(aContext,
michael@0 6600 *aRuleData->ValueForBorderLeftStyleLTRSource(),
michael@0 6601 *aRuleData->ValueForBorderLeftStyleRTLSource(),
michael@0 6602 *aRuleData->ValueForBorderStartStyleValue(),
michael@0 6603 *aRuleData->ValueForBorderEndStyleValue(),
michael@0 6604 NS_SIDE_LEFT, ourBorderStyle, canStoreInRuleTree);
michael@0 6605 AdjustLogicalBoxProp(aContext,
michael@0 6606 *aRuleData->ValueForBorderRightStyleLTRSource(),
michael@0 6607 *aRuleData->ValueForBorderRightStyleRTLSource(),
michael@0 6608 *aRuleData->ValueForBorderEndStyleValue(),
michael@0 6609 *aRuleData->ValueForBorderStartStyleValue(),
michael@0 6610 NS_SIDE_RIGHT, ourBorderStyle, canStoreInRuleTree);
michael@0 6611 { // scope for compilers with broken |for| loop scoping
michael@0 6612 NS_FOR_CSS_SIDES(side) {
michael@0 6613 const nsCSSValue &value = ourBorderStyle.*(nsCSSRect::sides[side]);
michael@0 6614 nsCSSUnit unit = value.GetUnit();
michael@0 6615 NS_ABORT_IF_FALSE(eCSSUnit_None != unit,
michael@0 6616 "'none' should be handled as enumerated value");
michael@0 6617 if (eCSSUnit_Enumerated == unit) {
michael@0 6618 border->SetBorderStyle(side, value.GetIntValue());
michael@0 6619 }
michael@0 6620 else if (eCSSUnit_Initial == unit ||
michael@0 6621 eCSSUnit_Unset == unit) {
michael@0 6622 border->SetBorderStyle(side, NS_STYLE_BORDER_STYLE_NONE);
michael@0 6623 }
michael@0 6624 else if (eCSSUnit_Inherit == unit) {
michael@0 6625 canStoreInRuleTree = false;
michael@0 6626 border->SetBorderStyle(side, parentBorder->GetBorderStyle(side));
michael@0 6627 }
michael@0 6628 }
michael@0 6629 }
michael@0 6630
michael@0 6631 // -moz-border-*-colors: color, string, enum, none, inherit/initial
michael@0 6632 nscolor borderColor;
michael@0 6633 nscolor unused = NS_RGB(0,0,0);
michael@0 6634
michael@0 6635 static const nsCSSProperty borderColorsProps[] = {
michael@0 6636 eCSSProperty_border_top_colors,
michael@0 6637 eCSSProperty_border_right_colors,
michael@0 6638 eCSSProperty_border_bottom_colors,
michael@0 6639 eCSSProperty_border_left_colors
michael@0 6640 };
michael@0 6641
michael@0 6642 NS_FOR_CSS_SIDES(side) {
michael@0 6643 const nsCSSValue& value = *aRuleData->ValueFor(borderColorsProps[side]);
michael@0 6644 switch (value.GetUnit()) {
michael@0 6645 case eCSSUnit_Null:
michael@0 6646 break;
michael@0 6647
michael@0 6648 case eCSSUnit_Initial:
michael@0 6649 case eCSSUnit_Unset:
michael@0 6650 case eCSSUnit_None:
michael@0 6651 border->ClearBorderColors(side);
michael@0 6652 break;
michael@0 6653
michael@0 6654 case eCSSUnit_Inherit: {
michael@0 6655 canStoreInRuleTree = false;
michael@0 6656 border->ClearBorderColors(side);
michael@0 6657 if (parentContext) {
michael@0 6658 nsBorderColors *parentColors;
michael@0 6659 parentBorder->GetCompositeColors(side, &parentColors);
michael@0 6660 if (parentColors) {
michael@0 6661 border->EnsureBorderColors();
michael@0 6662 border->mBorderColors[side] = parentColors->Clone();
michael@0 6663 }
michael@0 6664 }
michael@0 6665 break;
michael@0 6666 }
michael@0 6667
michael@0 6668 case eCSSUnit_List:
michael@0 6669 case eCSSUnit_ListDep: {
michael@0 6670 // Some composite border color information has been specified for this
michael@0 6671 // border side.
michael@0 6672 border->EnsureBorderColors();
michael@0 6673 border->ClearBorderColors(side);
michael@0 6674 const nsCSSValueList* list = value.GetListValue();
michael@0 6675 while (list) {
michael@0 6676 if (SetColor(list->mValue, unused, mPresContext,
michael@0 6677 aContext, borderColor, canStoreInRuleTree))
michael@0 6678 border->AppendBorderColor(side, borderColor);
michael@0 6679 else {
michael@0 6680 NS_NOTREACHED("unexpected item in -moz-border-*-colors list");
michael@0 6681 }
michael@0 6682 list = list->mNext;
michael@0 6683 }
michael@0 6684 break;
michael@0 6685 }
michael@0 6686
michael@0 6687 default:
michael@0 6688 NS_ABORT_IF_FALSE(false, "unrecognized border color unit");
michael@0 6689 }
michael@0 6690 }
michael@0 6691
michael@0 6692 // border-color, border-*-color: color, string, enum, inherit
michael@0 6693 bool foreground;
michael@0 6694 nsCSSRect ourBorderColor;
michael@0 6695 ourBorderColor.mTop = *aRuleData->ValueForBorderTopColor();
michael@0 6696 ourBorderColor.mRight = *aRuleData->ValueForBorderRightColorValue();
michael@0 6697 ourBorderColor.mBottom = *aRuleData->ValueForBorderBottomColor();
michael@0 6698 ourBorderColor.mLeft = *aRuleData->ValueForBorderLeftColorValue();
michael@0 6699 AdjustLogicalBoxProp(aContext,
michael@0 6700 *aRuleData->ValueForBorderLeftColorLTRSource(),
michael@0 6701 *aRuleData->ValueForBorderLeftColorRTLSource(),
michael@0 6702 *aRuleData->ValueForBorderStartColorValue(),
michael@0 6703 *aRuleData->ValueForBorderEndColorValue(),
michael@0 6704 NS_SIDE_LEFT, ourBorderColor, canStoreInRuleTree);
michael@0 6705 AdjustLogicalBoxProp(aContext,
michael@0 6706 *aRuleData->ValueForBorderRightColorLTRSource(),
michael@0 6707 *aRuleData->ValueForBorderRightColorRTLSource(),
michael@0 6708 *aRuleData->ValueForBorderEndColorValue(),
michael@0 6709 *aRuleData->ValueForBorderStartColorValue(),
michael@0 6710 NS_SIDE_RIGHT, ourBorderColor, canStoreInRuleTree);
michael@0 6711 { // scope for compilers with broken |for| loop scoping
michael@0 6712 NS_FOR_CSS_SIDES(side) {
michael@0 6713 const nsCSSValue &value = ourBorderColor.*(nsCSSRect::sides[side]);
michael@0 6714 if (eCSSUnit_Inherit == value.GetUnit()) {
michael@0 6715 canStoreInRuleTree = false;
michael@0 6716 if (parentContext) {
michael@0 6717 parentBorder->GetBorderColor(side, borderColor, foreground);
michael@0 6718 if (foreground) {
michael@0 6719 // We want to inherit the color from the parent, not use the
michael@0 6720 // color on the element where this chunk of style data will be
michael@0 6721 // used. We can ensure that the data for the parent are fully
michael@0 6722 // computed (unlike for the element where this will be used, for
michael@0 6723 // which the color could be specified on a more specific rule).
michael@0 6724 border->SetBorderColor(side, parentContext->StyleColor()->mColor);
michael@0 6725 } else
michael@0 6726 border->SetBorderColor(side, borderColor);
michael@0 6727 } else {
michael@0 6728 // We're the root
michael@0 6729 border->SetBorderToForeground(side);
michael@0 6730 }
michael@0 6731 }
michael@0 6732 else if (SetColor(value, unused, mPresContext, aContext, borderColor,
michael@0 6733 canStoreInRuleTree)) {
michael@0 6734 border->SetBorderColor(side, borderColor);
michael@0 6735 }
michael@0 6736 else if (eCSSUnit_Enumerated == value.GetUnit()) {
michael@0 6737 switch (value.GetIntValue()) {
michael@0 6738 case NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR:
michael@0 6739 border->SetBorderToForeground(side);
michael@0 6740 break;
michael@0 6741 default:
michael@0 6742 NS_NOTREACHED("Unexpected enumerated color");
michael@0 6743 break;
michael@0 6744 }
michael@0 6745 }
michael@0 6746 else if (eCSSUnit_Initial == value.GetUnit() ||
michael@0 6747 eCSSUnit_Unset == value.GetUnit()) {
michael@0 6748 border->SetBorderToForeground(side);
michael@0 6749 }
michael@0 6750 }
michael@0 6751 }
michael@0 6752
michael@0 6753 // border-radius: length, percent, inherit
michael@0 6754 {
michael@0 6755 const nsCSSProperty* subprops =
michael@0 6756 nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_radius);
michael@0 6757 NS_FOR_CSS_FULL_CORNERS(corner) {
michael@0 6758 int cx = NS_FULL_TO_HALF_CORNER(corner, false);
michael@0 6759 int cy = NS_FULL_TO_HALF_CORNER(corner, true);
michael@0 6760 const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
michael@0 6761 nsStyleCoord parentX = parentBorder->mBorderRadius.Get(cx);
michael@0 6762 nsStyleCoord parentY = parentBorder->mBorderRadius.Get(cy);
michael@0 6763 nsStyleCoord coordX, coordY;
michael@0 6764
michael@0 6765 if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
michael@0 6766 SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
michael@0 6767 SETCOORD_STORE_CALC | SETCOORD_UNSET_INITIAL,
michael@0 6768 aContext, mPresContext, canStoreInRuleTree)) {
michael@0 6769 border->mBorderRadius.Set(cx, coordX);
michael@0 6770 border->mBorderRadius.Set(cy, coordY);
michael@0 6771 }
michael@0 6772 }
michael@0 6773 }
michael@0 6774
michael@0 6775 // float-edge: enum, inherit, initial
michael@0 6776 SetDiscrete(*aRuleData->ValueForFloatEdge(),
michael@0 6777 border->mFloatEdge, canStoreInRuleTree,
michael@0 6778 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 6779 parentBorder->mFloatEdge,
michael@0 6780 NS_STYLE_FLOAT_EDGE_CONTENT, 0, 0, 0, 0);
michael@0 6781
michael@0 6782 // border-image-source
michael@0 6783 const nsCSSValue* borderImageSource = aRuleData->ValueForBorderImageSource();
michael@0 6784 if (borderImageSource->GetUnit() == eCSSUnit_Inherit) {
michael@0 6785 canStoreInRuleTree = false;
michael@0 6786 border->mBorderImageSource = parentBorder->mBorderImageSource;
michael@0 6787 } else {
michael@0 6788 SetStyleImage(aContext,
michael@0 6789 *borderImageSource,
michael@0 6790 border->mBorderImageSource,
michael@0 6791 canStoreInRuleTree);
michael@0 6792 }
michael@0 6793
michael@0 6794 nsCSSValue borderImageSliceValue;
michael@0 6795 nsCSSValue borderImageSliceFill;
michael@0 6796 SetBorderImageSlice(*aRuleData->ValueForBorderImageSlice(),
michael@0 6797 borderImageSliceValue, borderImageSliceFill);
michael@0 6798
michael@0 6799 // border-image-slice: fill
michael@0 6800 SetDiscrete(borderImageSliceFill,
michael@0 6801 border->mBorderImageFill,
michael@0 6802 canStoreInRuleTree,
michael@0 6803 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 6804 parentBorder->mBorderImageFill,
michael@0 6805 NS_STYLE_BORDER_IMAGE_SLICE_NOFILL, 0, 0, 0, 0);
michael@0 6806
michael@0 6807 nsCSSRect borderImageSlice;
michael@0 6808 SetBorderImageRect(borderImageSliceValue, borderImageSlice);
michael@0 6809
michael@0 6810 nsCSSRect borderImageWidth;
michael@0 6811 SetBorderImageRect(*aRuleData->ValueForBorderImageWidth(),
michael@0 6812 borderImageWidth);
michael@0 6813
michael@0 6814 nsCSSRect borderImageOutset;
michael@0 6815 SetBorderImageRect(*aRuleData->ValueForBorderImageOutset(),
michael@0 6816 borderImageOutset);
michael@0 6817
michael@0 6818 NS_FOR_CSS_SIDES (side) {
michael@0 6819 // border-image-slice
michael@0 6820 if (SetCoord(borderImageSlice.*(nsCSSRect::sides[side]), coord,
michael@0 6821 parentBorder->mBorderImageSlice.Get(side),
michael@0 6822 SETCOORD_FACTOR | SETCOORD_PERCENT |
michael@0 6823 SETCOORD_INHERIT | SETCOORD_INITIAL_HUNDRED_PCT |
michael@0 6824 SETCOORD_UNSET_INITIAL,
michael@0 6825 aContext, mPresContext, canStoreInRuleTree)) {
michael@0 6826 border->mBorderImageSlice.Set(side, coord);
michael@0 6827 }
michael@0 6828
michael@0 6829 // border-image-width
michael@0 6830 // 'auto' here means "same as slice"
michael@0 6831 if (SetCoord(borderImageWidth.*(nsCSSRect::sides[side]), coord,
michael@0 6832 parentBorder->mBorderImageWidth.Get(side),
michael@0 6833 SETCOORD_LPAH | SETCOORD_FACTOR | SETCOORD_INITIAL_FACTOR_ONE |
michael@0 6834 SETCOORD_UNSET_INITIAL,
michael@0 6835 aContext, mPresContext, canStoreInRuleTree)) {
michael@0 6836 border->mBorderImageWidth.Set(side, coord);
michael@0 6837 }
michael@0 6838
michael@0 6839 // border-image-outset
michael@0 6840 if (SetCoord(borderImageOutset.*(nsCSSRect::sides[side]), coord,
michael@0 6841 parentBorder->mBorderImageOutset.Get(side),
michael@0 6842 SETCOORD_LENGTH | SETCOORD_FACTOR |
michael@0 6843 SETCOORD_INHERIT | SETCOORD_INITIAL_FACTOR_ZERO |
michael@0 6844 SETCOORD_UNSET_INITIAL,
michael@0 6845 aContext, mPresContext, canStoreInRuleTree)) {
michael@0 6846 border->mBorderImageOutset.Set(side, coord);
michael@0 6847 }
michael@0 6848 }
michael@0 6849
michael@0 6850 // border-image-repeat
michael@0 6851 nsCSSValuePair borderImageRepeat;
michael@0 6852 SetBorderImagePair(*aRuleData->ValueForBorderImageRepeat(),
michael@0 6853 borderImageRepeat);
michael@0 6854
michael@0 6855 SetDiscrete(borderImageRepeat.mXValue,
michael@0 6856 border->mBorderImageRepeatH,
michael@0 6857 canStoreInRuleTree,
michael@0 6858 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 6859 parentBorder->mBorderImageRepeatH,
michael@0 6860 NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, 0, 0, 0, 0);
michael@0 6861
michael@0 6862 SetDiscrete(borderImageRepeat.mYValue,
michael@0 6863 border->mBorderImageRepeatV,
michael@0 6864 canStoreInRuleTree,
michael@0 6865 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 6866 parentBorder->mBorderImageRepeatV,
michael@0 6867 NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, 0, 0, 0, 0);
michael@0 6868
michael@0 6869 border->TrackImage(aContext->PresContext());
michael@0 6870
michael@0 6871 COMPUTE_END_RESET(Border, border)
michael@0 6872 }
michael@0 6873
michael@0 6874 const void*
michael@0 6875 nsRuleNode::ComputePaddingData(void* aStartStruct,
michael@0 6876 const nsRuleData* aRuleData,
michael@0 6877 nsStyleContext* aContext,
michael@0 6878 nsRuleNode* aHighestNode,
michael@0 6879 const RuleDetail aRuleDetail,
michael@0 6880 const bool aCanStoreInRuleTree)
michael@0 6881 {
michael@0 6882 COMPUTE_START_RESET(Padding, (), padding, parentPadding)
michael@0 6883
michael@0 6884 // padding: length, percent, inherit
michael@0 6885 nsStyleCoord coord;
michael@0 6886 nsCSSRect ourPadding;
michael@0 6887 ourPadding.mTop = *aRuleData->ValueForPaddingTop();
michael@0 6888 ourPadding.mRight = *aRuleData->ValueForPaddingRightValue();
michael@0 6889 ourPadding.mBottom = *aRuleData->ValueForPaddingBottom();
michael@0 6890 ourPadding.mLeft = *aRuleData->ValueForPaddingLeftValue();
michael@0 6891 AdjustLogicalBoxProp(aContext,
michael@0 6892 *aRuleData->ValueForPaddingLeftLTRSource(),
michael@0 6893 *aRuleData->ValueForPaddingLeftRTLSource(),
michael@0 6894 *aRuleData->ValueForPaddingStartValue(),
michael@0 6895 *aRuleData->ValueForPaddingEndValue(),
michael@0 6896 NS_SIDE_LEFT, ourPadding, canStoreInRuleTree);
michael@0 6897 AdjustLogicalBoxProp(aContext,
michael@0 6898 *aRuleData->ValueForPaddingRightLTRSource(),
michael@0 6899 *aRuleData->ValueForPaddingRightRTLSource(),
michael@0 6900 *aRuleData->ValueForPaddingEndValue(),
michael@0 6901 *aRuleData->ValueForPaddingStartValue(),
michael@0 6902 NS_SIDE_RIGHT, ourPadding, canStoreInRuleTree);
michael@0 6903 NS_FOR_CSS_SIDES(side) {
michael@0 6904 nsStyleCoord parentCoord = parentPadding->mPadding.Get(side);
michael@0 6905 if (SetCoord(ourPadding.*(nsCSSRect::sides[side]),
michael@0 6906 coord, parentCoord,
michael@0 6907 SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
michael@0 6908 SETCOORD_UNSET_INITIAL,
michael@0 6909 aContext, mPresContext, canStoreInRuleTree)) {
michael@0 6910 padding->mPadding.Set(side, coord);
michael@0 6911 }
michael@0 6912 }
michael@0 6913
michael@0 6914 padding->RecalcData();
michael@0 6915 COMPUTE_END_RESET(Padding, padding)
michael@0 6916 }
michael@0 6917
michael@0 6918 const void*
michael@0 6919 nsRuleNode::ComputeOutlineData(void* aStartStruct,
michael@0 6920 const nsRuleData* aRuleData,
michael@0 6921 nsStyleContext* aContext,
michael@0 6922 nsRuleNode* aHighestNode,
michael@0 6923 const RuleDetail aRuleDetail,
michael@0 6924 const bool aCanStoreInRuleTree)
michael@0 6925 {
michael@0 6926 COMPUTE_START_RESET(Outline, (mPresContext), outline, parentOutline)
michael@0 6927
michael@0 6928 // outline-width: length, enum, inherit
michael@0 6929 const nsCSSValue* outlineWidthValue = aRuleData->ValueForOutlineWidth();
michael@0 6930 if (eCSSUnit_Initial == outlineWidthValue->GetUnit() ||
michael@0 6931 eCSSUnit_Unset == outlineWidthValue->GetUnit()) {
michael@0 6932 outline->mOutlineWidth =
michael@0 6933 nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
michael@0 6934 }
michael@0 6935 else {
michael@0 6936 SetCoord(*outlineWidthValue, outline->mOutlineWidth,
michael@0 6937 parentOutline->mOutlineWidth,
michael@0 6938 SETCOORD_LEH | SETCOORD_CALC_LENGTH_ONLY, aContext,
michael@0 6939 mPresContext, canStoreInRuleTree);
michael@0 6940 }
michael@0 6941
michael@0 6942 // outline-offset: length, inherit
michael@0 6943 nsStyleCoord tempCoord;
michael@0 6944 const nsCSSValue* outlineOffsetValue = aRuleData->ValueForOutlineOffset();
michael@0 6945 if (SetCoord(*outlineOffsetValue, tempCoord,
michael@0 6946 nsStyleCoord(parentOutline->mOutlineOffset,
michael@0 6947 nsStyleCoord::CoordConstructor),
michael@0 6948 SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY |
michael@0 6949 SETCOORD_UNSET_INITIAL,
michael@0 6950 aContext, mPresContext, canStoreInRuleTree)) {
michael@0 6951 outline->mOutlineOffset = tempCoord.GetCoordValue();
michael@0 6952 } else {
michael@0 6953 NS_ASSERTION(outlineOffsetValue->GetUnit() == eCSSUnit_Null,
michael@0 6954 "unexpected unit");
michael@0 6955 }
michael@0 6956
michael@0 6957 // outline-color: color, string, enum, inherit
michael@0 6958 nscolor outlineColor;
michael@0 6959 nscolor unused = NS_RGB(0,0,0);
michael@0 6960 const nsCSSValue* outlineColorValue = aRuleData->ValueForOutlineColor();
michael@0 6961 if (eCSSUnit_Inherit == outlineColorValue->GetUnit()) {
michael@0 6962 canStoreInRuleTree = false;
michael@0 6963 if (parentContext) {
michael@0 6964 if (parentOutline->GetOutlineColor(outlineColor))
michael@0 6965 outline->SetOutlineColor(outlineColor);
michael@0 6966 else {
michael@0 6967 // We want to inherit the color from the parent, not use the
michael@0 6968 // color on the element where this chunk of style data will be
michael@0 6969 // used. We can ensure that the data for the parent are fully
michael@0 6970 // computed (unlike for the element where this will be used, for
michael@0 6971 // which the color could be specified on a more specific rule).
michael@0 6972 outline->SetOutlineColor(parentContext->StyleColor()->mColor);
michael@0 6973 }
michael@0 6974 } else {
michael@0 6975 outline->SetOutlineInitialColor();
michael@0 6976 }
michael@0 6977 }
michael@0 6978 else if (SetColor(*outlineColorValue, unused, mPresContext,
michael@0 6979 aContext, outlineColor, canStoreInRuleTree))
michael@0 6980 outline->SetOutlineColor(outlineColor);
michael@0 6981 else if (eCSSUnit_Enumerated == outlineColorValue->GetUnit() ||
michael@0 6982 eCSSUnit_Initial == outlineColorValue->GetUnit() ||
michael@0 6983 eCSSUnit_Unset == outlineColorValue->GetUnit()) {
michael@0 6984 outline->SetOutlineInitialColor();
michael@0 6985 }
michael@0 6986
michael@0 6987 // -moz-outline-radius: length, percent, inherit
michael@0 6988 {
michael@0 6989 const nsCSSProperty* subprops =
michael@0 6990 nsCSSProps::SubpropertyEntryFor(eCSSProperty__moz_outline_radius);
michael@0 6991 NS_FOR_CSS_FULL_CORNERS(corner) {
michael@0 6992 int cx = NS_FULL_TO_HALF_CORNER(corner, false);
michael@0 6993 int cy = NS_FULL_TO_HALF_CORNER(corner, true);
michael@0 6994 const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
michael@0 6995 nsStyleCoord parentX = parentOutline->mOutlineRadius.Get(cx);
michael@0 6996 nsStyleCoord parentY = parentOutline->mOutlineRadius.Get(cy);
michael@0 6997 nsStyleCoord coordX, coordY;
michael@0 6998
michael@0 6999 if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
michael@0 7000 SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
michael@0 7001 SETCOORD_STORE_CALC | SETCOORD_UNSET_INITIAL,
michael@0 7002 aContext, mPresContext, canStoreInRuleTree)) {
michael@0 7003 outline->mOutlineRadius.Set(cx, coordX);
michael@0 7004 outline->mOutlineRadius.Set(cy, coordY);
michael@0 7005 }
michael@0 7006 }
michael@0 7007 }
michael@0 7008
michael@0 7009 // outline-style: enum, inherit, initial
michael@0 7010 // cannot use SetDiscrete because of SetOutlineStyle
michael@0 7011 const nsCSSValue* outlineStyleValue = aRuleData->ValueForOutlineStyle();
michael@0 7012 nsCSSUnit unit = outlineStyleValue->GetUnit();
michael@0 7013 NS_ABORT_IF_FALSE(eCSSUnit_None != unit && eCSSUnit_Auto != unit,
michael@0 7014 "'none' and 'auto' should be handled as enumerated values");
michael@0 7015 if (eCSSUnit_Enumerated == unit) {
michael@0 7016 outline->SetOutlineStyle(outlineStyleValue->GetIntValue());
michael@0 7017 } else if (eCSSUnit_Initial == unit ||
michael@0 7018 eCSSUnit_Unset == unit) {
michael@0 7019 outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_NONE);
michael@0 7020 } else if (eCSSUnit_Inherit == unit) {
michael@0 7021 canStoreInRuleTree = false;
michael@0 7022 outline->SetOutlineStyle(parentOutline->GetOutlineStyle());
michael@0 7023 }
michael@0 7024
michael@0 7025 outline->RecalcData(mPresContext);
michael@0 7026 COMPUTE_END_RESET(Outline, outline)
michael@0 7027 }
michael@0 7028
michael@0 7029 const void*
michael@0 7030 nsRuleNode::ComputeListData(void* aStartStruct,
michael@0 7031 const nsRuleData* aRuleData,
michael@0 7032 nsStyleContext* aContext,
michael@0 7033 nsRuleNode* aHighestNode,
michael@0 7034 const RuleDetail aRuleDetail,
michael@0 7035 const bool aCanStoreInRuleTree)
michael@0 7036 {
michael@0 7037 COMPUTE_START_INHERITED(List, (), list, parentList)
michael@0 7038
michael@0 7039 // list-style-type: enum, inherit, initial
michael@0 7040 SetDiscrete(*aRuleData->ValueForListStyleType(),
michael@0 7041 list->mListStyleType, canStoreInRuleTree,
michael@0 7042 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 7043 parentList->mListStyleType,
michael@0 7044 NS_STYLE_LIST_STYLE_DISC, 0, 0, 0, 0);
michael@0 7045
michael@0 7046 // list-style-image: url, none, inherit
michael@0 7047 const nsCSSValue* imageValue = aRuleData->ValueForListStyleImage();
michael@0 7048 if (eCSSUnit_Image == imageValue->GetUnit()) {
michael@0 7049 NS_SET_IMAGE_REQUEST_WITH_DOC(list->SetListStyleImage,
michael@0 7050 aContext,
michael@0 7051 imageValue->GetImageValue)
michael@0 7052 }
michael@0 7053 else if (eCSSUnit_None == imageValue->GetUnit() ||
michael@0 7054 eCSSUnit_Initial == imageValue->GetUnit()) {
michael@0 7055 list->SetListStyleImage(nullptr);
michael@0 7056 }
michael@0 7057 else if (eCSSUnit_Inherit == imageValue->GetUnit() ||
michael@0 7058 eCSSUnit_Unset == imageValue->GetUnit()) {
michael@0 7059 canStoreInRuleTree = false;
michael@0 7060 NS_SET_IMAGE_REQUEST(list->SetListStyleImage,
michael@0 7061 aContext,
michael@0 7062 parentList->GetListStyleImage())
michael@0 7063 }
michael@0 7064
michael@0 7065 // list-style-position: enum, inherit, initial
michael@0 7066 SetDiscrete(*aRuleData->ValueForListStylePosition(),
michael@0 7067 list->mListStylePosition, canStoreInRuleTree,
michael@0 7068 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 7069 parentList->mListStylePosition,
michael@0 7070 NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, 0, 0, 0, 0);
michael@0 7071
michael@0 7072 // image region property: length, auto, inherit
michael@0 7073 const nsCSSValue* imageRegionValue = aRuleData->ValueForImageRegion();
michael@0 7074 switch (imageRegionValue->GetUnit()) {
michael@0 7075 case eCSSUnit_Inherit:
michael@0 7076 case eCSSUnit_Unset:
michael@0 7077 canStoreInRuleTree = false;
michael@0 7078 list->mImageRegion = parentList->mImageRegion;
michael@0 7079 break;
michael@0 7080
michael@0 7081 case eCSSUnit_Initial:
michael@0 7082 case eCSSUnit_Auto:
michael@0 7083 list->mImageRegion.SetRect(0,0,0,0);
michael@0 7084 break;
michael@0 7085
michael@0 7086 case eCSSUnit_Null:
michael@0 7087 break;
michael@0 7088
michael@0 7089 case eCSSUnit_Rect: {
michael@0 7090 const nsCSSRect& rgnRect = imageRegionValue->GetRectValue();
michael@0 7091
michael@0 7092 if (rgnRect.mTop.GetUnit() == eCSSUnit_Auto)
michael@0 7093 list->mImageRegion.y = 0;
michael@0 7094 else if (rgnRect.mTop.IsLengthUnit())
michael@0 7095 list->mImageRegion.y =
michael@0 7096 CalcLength(rgnRect.mTop, aContext, mPresContext, canStoreInRuleTree);
michael@0 7097
michael@0 7098 if (rgnRect.mBottom.GetUnit() == eCSSUnit_Auto)
michael@0 7099 list->mImageRegion.height = 0;
michael@0 7100 else if (rgnRect.mBottom.IsLengthUnit())
michael@0 7101 list->mImageRegion.height =
michael@0 7102 CalcLength(rgnRect.mBottom, aContext, mPresContext,
michael@0 7103 canStoreInRuleTree) - list->mImageRegion.y;
michael@0 7104
michael@0 7105 if (rgnRect.mLeft.GetUnit() == eCSSUnit_Auto)
michael@0 7106 list->mImageRegion.x = 0;
michael@0 7107 else if (rgnRect.mLeft.IsLengthUnit())
michael@0 7108 list->mImageRegion.x =
michael@0 7109 CalcLength(rgnRect.mLeft, aContext, mPresContext, canStoreInRuleTree);
michael@0 7110
michael@0 7111 if (rgnRect.mRight.GetUnit() == eCSSUnit_Auto)
michael@0 7112 list->mImageRegion.width = 0;
michael@0 7113 else if (rgnRect.mRight.IsLengthUnit())
michael@0 7114 list->mImageRegion.width =
michael@0 7115 CalcLength(rgnRect.mRight, aContext, mPresContext,
michael@0 7116 canStoreInRuleTree) - list->mImageRegion.x;
michael@0 7117 break;
michael@0 7118 }
michael@0 7119
michael@0 7120 default:
michael@0 7121 NS_ABORT_IF_FALSE(false, "unrecognized image-region unit");
michael@0 7122 }
michael@0 7123
michael@0 7124 COMPUTE_END_INHERITED(List, list)
michael@0 7125 }
michael@0 7126
michael@0 7127 static void
michael@0 7128 SetGridTrackBreadth(const nsCSSValue& aValue,
michael@0 7129 nsStyleCoord& aResult,
michael@0 7130 nsStyleContext* aStyleContext,
michael@0 7131 nsPresContext* aPresContext,
michael@0 7132 bool& aCanStoreInRuleTree)
michael@0 7133 {
michael@0 7134 nsCSSUnit unit = aValue.GetUnit();
michael@0 7135 if (unit == eCSSUnit_FlexFraction) {
michael@0 7136 aResult.SetFlexFractionValue(aValue.GetFloatValue());
michael@0 7137 } else {
michael@0 7138 MOZ_ASSERT(unit != eCSSUnit_Inherit && unit != eCSSUnit_Unset,
michael@0 7139 "Unexpected value that would use dummyParentCoord");
michael@0 7140 const nsStyleCoord dummyParentCoord;
michael@0 7141 SetCoord(aValue, aResult, dummyParentCoord,
michael@0 7142 SETCOORD_LPE | SETCOORD_STORE_CALC,
michael@0 7143 aStyleContext, aPresContext, aCanStoreInRuleTree);
michael@0 7144 }
michael@0 7145 }
michael@0 7146
michael@0 7147 static void
michael@0 7148 SetGridTrackSize(const nsCSSValue& aValue,
michael@0 7149 nsStyleCoord& aResultMin,
michael@0 7150 nsStyleCoord& aResultMax,
michael@0 7151 nsStyleContext* aStyleContext,
michael@0 7152 nsPresContext* aPresContext,
michael@0 7153 bool& aCanStoreInRuleTree)
michael@0 7154 {
michael@0 7155 if (aValue.GetUnit() == eCSSUnit_Function) {
michael@0 7156 // A minmax() function.
michael@0 7157 nsCSSValue::Array* func = aValue.GetArrayValue();
michael@0 7158 NS_ASSERTION(func->Item(0).GetKeywordValue() == eCSSKeyword_minmax,
michael@0 7159 "Expected minmax(), got another function name");
michael@0 7160 SetGridTrackBreadth(func->Item(1), aResultMin,
michael@0 7161 aStyleContext, aPresContext, aCanStoreInRuleTree);
michael@0 7162 SetGridTrackBreadth(func->Item(2), aResultMax,
michael@0 7163 aStyleContext, aPresContext, aCanStoreInRuleTree);
michael@0 7164 } else if (aValue.GetUnit() == eCSSUnit_Auto) {
michael@0 7165 // 'auto' computes to 'minmax(min-content, max-content)'
michael@0 7166 aResultMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
michael@0 7167 eStyleUnit_Enumerated);
michael@0 7168 aResultMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
michael@0 7169 eStyleUnit_Enumerated);
michael@0 7170 } else {
michael@0 7171 // A single <track-breadth>,
michael@0 7172 // specifies identical min and max sizing functions.
michael@0 7173 SetGridTrackBreadth(aValue, aResultMin,
michael@0 7174 aStyleContext, aPresContext, aCanStoreInRuleTree);
michael@0 7175 aResultMax = aResultMin;
michael@0 7176 }
michael@0 7177 }
michael@0 7178
michael@0 7179 static void
michael@0 7180 SetGridAutoColumnsRows(const nsCSSValue& aValue,
michael@0 7181 nsStyleCoord& aResultMin,
michael@0 7182 nsStyleCoord& aResultMax,
michael@0 7183 const nsStyleCoord& aParentValueMin,
michael@0 7184 const nsStyleCoord& aParentValueMax,
michael@0 7185 nsStyleContext* aStyleContext,
michael@0 7186 nsPresContext* aPresContext,
michael@0 7187 bool& aCanStoreInRuleTree)
michael@0 7188
michael@0 7189 {
michael@0 7190 switch (aValue.GetUnit()) {
michael@0 7191 case eCSSUnit_Null:
michael@0 7192 break;
michael@0 7193
michael@0 7194 case eCSSUnit_Inherit:
michael@0 7195 aCanStoreInRuleTree = false;
michael@0 7196 aResultMin = aParentValueMin;
michael@0 7197 aResultMax = aParentValueMax;
michael@0 7198 break;
michael@0 7199
michael@0 7200 case eCSSUnit_Initial:
michael@0 7201 case eCSSUnit_Unset:
michael@0 7202 // The initial value is 'auto',
michael@0 7203 // which computes to 'minmax(min-content, max-content)'.
michael@0 7204 // (Explicitly-specified 'auto' values are handled in SetGridTrackSize.)
michael@0 7205 aResultMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
michael@0 7206 eStyleUnit_Enumerated);
michael@0 7207 aResultMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
michael@0 7208 eStyleUnit_Enumerated);
michael@0 7209 break;
michael@0 7210
michael@0 7211 default:
michael@0 7212 SetGridTrackSize(aValue, aResultMin, aResultMax,
michael@0 7213 aStyleContext, aPresContext, aCanStoreInRuleTree);
michael@0 7214 }
michael@0 7215 }
michael@0 7216
michael@0 7217 static void
michael@0 7218 AppendGridLineNames(const nsCSSValue& aValue,
michael@0 7219 nsStyleGridTemplate& aResult)
michael@0 7220 {
michael@0 7221 // Compute a <line-names> value
michael@0 7222 nsTArray<nsString>* nameList = aResult.mLineNameLists.AppendElement();
michael@0 7223 // Null unit means empty list, nothing more to do.
michael@0 7224 if (aValue.GetUnit() != eCSSUnit_Null) {
michael@0 7225 const nsCSSValueList* item = aValue.GetListValue();
michael@0 7226 do {
michael@0 7227 nsString* name = nameList->AppendElement();
michael@0 7228 item->mValue.GetStringValue(*name);
michael@0 7229 item = item->mNext;
michael@0 7230 } while (item);
michael@0 7231 }
michael@0 7232 }
michael@0 7233
michael@0 7234 static void
michael@0 7235 SetGridTrackList(const nsCSSValue& aValue,
michael@0 7236 nsStyleGridTemplate& aResult,
michael@0 7237 const nsStyleGridTemplate& aParentValue,
michael@0 7238 nsStyleContext* aStyleContext,
michael@0 7239 nsPresContext* aPresContext,
michael@0 7240 bool& aCanStoreInRuleTree)
michael@0 7241
michael@0 7242 {
michael@0 7243 switch (aValue.GetUnit()) {
michael@0 7244 case eCSSUnit_Null:
michael@0 7245 break;
michael@0 7246
michael@0 7247 case eCSSUnit_Inherit:
michael@0 7248 aCanStoreInRuleTree = false;
michael@0 7249 aResult.mIsSubgrid = aParentValue.mIsSubgrid;
michael@0 7250 aResult.mLineNameLists = aParentValue.mLineNameLists;
michael@0 7251 aResult.mMinTrackSizingFunctions = aParentValue.mMinTrackSizingFunctions;
michael@0 7252 aResult.mMaxTrackSizingFunctions = aParentValue.mMaxTrackSizingFunctions;
michael@0 7253 break;
michael@0 7254
michael@0 7255 case eCSSUnit_Initial:
michael@0 7256 case eCSSUnit_Unset:
michael@0 7257 case eCSSUnit_None:
michael@0 7258 aResult.mIsSubgrid = false;
michael@0 7259 aResult.mLineNameLists.Clear();
michael@0 7260 aResult.mMinTrackSizingFunctions.Clear();
michael@0 7261 aResult.mMaxTrackSizingFunctions.Clear();
michael@0 7262 break;
michael@0 7263
michael@0 7264 default:
michael@0 7265 aResult.mLineNameLists.Clear();
michael@0 7266 aResult.mMinTrackSizingFunctions.Clear();
michael@0 7267 aResult.mMaxTrackSizingFunctions.Clear();
michael@0 7268 const nsCSSValueList* item = aValue.GetListValue();
michael@0 7269 if (item->mValue.GetUnit() == eCSSUnit_Enumerated &&
michael@0 7270 item->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) {
michael@0 7271 // subgrid <line-name-list>?
michael@0 7272 aResult.mIsSubgrid = true;
michael@0 7273 item = item->mNext;
michael@0 7274 while (item) {
michael@0 7275 AppendGridLineNames(item->mValue, aResult);
michael@0 7276 item = item->mNext;
michael@0 7277 }
michael@0 7278 } else {
michael@0 7279 // <track-list>
michael@0 7280 // The list is expected to have odd number of items, at least 3
michael@0 7281 // starting with a <line-names> (sub list of identifiers),
michael@0 7282 // and alternating between that and <track-size>.
michael@0 7283 aResult.mIsSubgrid = false;
michael@0 7284 for (;;) {
michael@0 7285 AppendGridLineNames(item->mValue, aResult);
michael@0 7286 item = item->mNext;
michael@0 7287
michael@0 7288 if (!item) {
michael@0 7289 break;
michael@0 7290 }
michael@0 7291
michael@0 7292 nsStyleCoord& min = *aResult.mMinTrackSizingFunctions.AppendElement();
michael@0 7293 nsStyleCoord& max = *aResult.mMaxTrackSizingFunctions.AppendElement();
michael@0 7294 SetGridTrackSize(item->mValue, min, max,
michael@0 7295 aStyleContext, aPresContext, aCanStoreInRuleTree);
michael@0 7296
michael@0 7297 item = item->mNext;
michael@0 7298 MOZ_ASSERT(item, "Expected a eCSSUnit_List of odd length");
michael@0 7299 }
michael@0 7300 MOZ_ASSERT(!aResult.mMinTrackSizingFunctions.IsEmpty() &&
michael@0 7301 aResult.mMinTrackSizingFunctions.Length() ==
michael@0 7302 aResult.mMaxTrackSizingFunctions.Length() &&
michael@0 7303 aResult.mMinTrackSizingFunctions.Length() + 1 ==
michael@0 7304 aResult.mLineNameLists.Length(),
michael@0 7305 "Inconstistent array lengths for nsStyleGridTemplate");
michael@0 7306 }
michael@0 7307 }
michael@0 7308 }
michael@0 7309
michael@0 7310 static void
michael@0 7311 SetGridTemplateAreas(const nsCSSValue& aValue,
michael@0 7312 nsRefPtr<css::GridTemplateAreasValue>* aResult,
michael@0 7313 css::GridTemplateAreasValue* aParentValue,
michael@0 7314 bool& aCanStoreInRuleTree)
michael@0 7315 {
michael@0 7316 switch (aValue.GetUnit()) {
michael@0 7317 case eCSSUnit_Null:
michael@0 7318 break;
michael@0 7319
michael@0 7320 case eCSSUnit_Inherit:
michael@0 7321 aCanStoreInRuleTree = false;
michael@0 7322 *aResult = aParentValue;
michael@0 7323 break;
michael@0 7324
michael@0 7325 case eCSSUnit_Initial:
michael@0 7326 case eCSSUnit_Unset:
michael@0 7327 case eCSSUnit_None:
michael@0 7328 *aResult = nullptr;
michael@0 7329 break;
michael@0 7330
michael@0 7331 default:
michael@0 7332 *aResult = aValue.GetGridTemplateAreas();
michael@0 7333 }
michael@0 7334 }
michael@0 7335
michael@0 7336 static void
michael@0 7337 SetGridLine(const nsCSSValue& aValue,
michael@0 7338 nsStyleGridLine& aResult,
michael@0 7339 const nsStyleGridLine& aParentValue,
michael@0 7340 bool& aCanStoreInRuleTree)
michael@0 7341
michael@0 7342 {
michael@0 7343 switch (aValue.GetUnit()) {
michael@0 7344 case eCSSUnit_Null:
michael@0 7345 break;
michael@0 7346
michael@0 7347 case eCSSUnit_Inherit:
michael@0 7348 aCanStoreInRuleTree = false;
michael@0 7349 aResult = aParentValue;
michael@0 7350 break;
michael@0 7351
michael@0 7352 case eCSSUnit_Initial:
michael@0 7353 case eCSSUnit_Unset:
michael@0 7354 case eCSSUnit_Auto:
michael@0 7355 aResult.SetAuto();
michael@0 7356 break;
michael@0 7357
michael@0 7358 default:
michael@0 7359 aResult.SetAuto(); // Reset any existing value.
michael@0 7360 const nsCSSValueList* item = aValue.GetListValue();
michael@0 7361 do {
michael@0 7362 if (item->mValue.GetUnit() == eCSSUnit_Enumerated) {
michael@0 7363 aResult.mHasSpan = true;
michael@0 7364 } else if (item->mValue.GetUnit() == eCSSUnit_Integer) {
michael@0 7365 aResult.mInteger = item->mValue.GetIntValue();
michael@0 7366 } else if (item->mValue.GetUnit() == eCSSUnit_Ident) {
michael@0 7367 item->mValue.GetStringValue(aResult.mLineName);
michael@0 7368 } else {
michael@0 7369 NS_ASSERTION(false, "Unexpected unit");
michael@0 7370 }
michael@0 7371 item = item->mNext;
michael@0 7372 } while (item);
michael@0 7373 MOZ_ASSERT(!aResult.IsAuto(),
michael@0 7374 "should have set something away from default value");
michael@0 7375 }
michael@0 7376 }
michael@0 7377
michael@0 7378 const void*
michael@0 7379 nsRuleNode::ComputePositionData(void* aStartStruct,
michael@0 7380 const nsRuleData* aRuleData,
michael@0 7381 nsStyleContext* aContext,
michael@0 7382 nsRuleNode* aHighestNode,
michael@0 7383 const RuleDetail aRuleDetail,
michael@0 7384 const bool aCanStoreInRuleTree)
michael@0 7385 {
michael@0 7386 COMPUTE_START_RESET(Position, (), pos, parentPos)
michael@0 7387
michael@0 7388 // box offsets: length, percent, calc, auto, inherit
michael@0 7389 static const nsCSSProperty offsetProps[] = {
michael@0 7390 eCSSProperty_top,
michael@0 7391 eCSSProperty_right,
michael@0 7392 eCSSProperty_bottom,
michael@0 7393 eCSSProperty_left
michael@0 7394 };
michael@0 7395 nsStyleCoord coord;
michael@0 7396 NS_FOR_CSS_SIDES(side) {
michael@0 7397 nsStyleCoord parentCoord = parentPos->mOffset.Get(side);
michael@0 7398 if (SetCoord(*aRuleData->ValueFor(offsetProps[side]),
michael@0 7399 coord, parentCoord,
michael@0 7400 SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
michael@0 7401 SETCOORD_UNSET_INITIAL,
michael@0 7402 aContext, mPresContext, canStoreInRuleTree)) {
michael@0 7403 pos->mOffset.Set(side, coord);
michael@0 7404 }
michael@0 7405 }
michael@0 7406
michael@0 7407 SetCoord(*aRuleData->ValueForWidth(), pos->mWidth, parentPos->mWidth,
michael@0 7408 SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
michael@0 7409 SETCOORD_UNSET_INITIAL,
michael@0 7410 aContext, mPresContext, canStoreInRuleTree);
michael@0 7411 SetCoord(*aRuleData->ValueForMinWidth(), pos->mMinWidth, parentPos->mMinWidth,
michael@0 7412 SETCOORD_LPEH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
michael@0 7413 SETCOORD_UNSET_INITIAL,
michael@0 7414 aContext, mPresContext, canStoreInRuleTree);
michael@0 7415 SetCoord(*aRuleData->ValueForMaxWidth(), pos->mMaxWidth, parentPos->mMaxWidth,
michael@0 7416 SETCOORD_LPOEH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC |
michael@0 7417 SETCOORD_UNSET_INITIAL,
michael@0 7418 aContext, mPresContext, canStoreInRuleTree);
michael@0 7419
michael@0 7420 SetCoord(*aRuleData->ValueForHeight(), pos->mHeight, parentPos->mHeight,
michael@0 7421 SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
michael@0 7422 SETCOORD_UNSET_INITIAL,
michael@0 7423 aContext, mPresContext, canStoreInRuleTree);
michael@0 7424 SetCoord(*aRuleData->ValueForMinHeight(), pos->mMinHeight, parentPos->mMinHeight,
michael@0 7425 SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
michael@0 7426 SETCOORD_UNSET_INITIAL,
michael@0 7427 aContext, mPresContext, canStoreInRuleTree);
michael@0 7428 SetCoord(*aRuleData->ValueForMaxHeight(), pos->mMaxHeight, parentPos->mMaxHeight,
michael@0 7429 SETCOORD_LPOH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC |
michael@0 7430 SETCOORD_UNSET_INITIAL,
michael@0 7431 aContext, mPresContext, canStoreInRuleTree);
michael@0 7432
michael@0 7433 // box-sizing: enum, inherit, initial
michael@0 7434 SetDiscrete(*aRuleData->ValueForBoxSizing(),
michael@0 7435 pos->mBoxSizing, canStoreInRuleTree,
michael@0 7436 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 7437 parentPos->mBoxSizing,
michael@0 7438 NS_STYLE_BOX_SIZING_CONTENT, 0, 0, 0, 0);
michael@0 7439
michael@0 7440 // align-content: enum, inherit, initial
michael@0 7441 SetDiscrete(*aRuleData->ValueForAlignContent(),
michael@0 7442 pos->mAlignContent, canStoreInRuleTree,
michael@0 7443 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 7444 parentPos->mAlignContent,
michael@0 7445 NS_STYLE_ALIGN_CONTENT_STRETCH, 0, 0, 0, 0);
michael@0 7446
michael@0 7447 // align-items: enum, inherit, initial
michael@0 7448 SetDiscrete(*aRuleData->ValueForAlignItems(),
michael@0 7449 pos->mAlignItems, canStoreInRuleTree,
michael@0 7450 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 7451 parentPos->mAlignItems,
michael@0 7452 NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE, 0, 0, 0, 0);
michael@0 7453
michael@0 7454 // align-self: enum, inherit, initial
michael@0 7455 // NOTE: align-self's initial value is the special keyword "auto", which is
michael@0 7456 // supposed to compute to our parent's computed value of "align-items". So
michael@0 7457 // technically, "auto" itself is never a valid computed value for align-self,
michael@0 7458 // since it always computes to something else. Despite that, we do actually
michael@0 7459 // store "auto" in nsStylePosition::mAlignSelf, as NS_STYLE_ALIGN_SELF_AUTO
michael@0 7460 // (and then resolve it as-necessary). We do this because "auto" is the
michael@0 7461 // initial value for this property, so if we were to actually resolve it in
michael@0 7462 // nsStylePosition, we'd never be able to share any nsStylePosition structs
michael@0 7463 // in the rule tree, since their mAlignSelf values would depend on the parent
michael@0 7464 // style, by default.
michael@0 7465 if (aRuleData->ValueForAlignSelf()->GetUnit() == eCSSUnit_Inherit) {
michael@0 7466 // Special handling for "align-self: inherit", in case we're inheriting
michael@0 7467 // "align-self: auto", in which case we need to resolve the parent's "auto"
michael@0 7468 // and inherit that resolved value.
michael@0 7469 uint8_t inheritedAlignSelf = parentPos->mAlignSelf;
michael@0 7470 if (inheritedAlignSelf == NS_STYLE_ALIGN_SELF_AUTO) {
michael@0 7471 if (!parentContext) {
michael@0 7472 // We're the root node. Nothing to inherit from --> just use default
michael@0 7473 // value.
michael@0 7474 inheritedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
michael@0 7475 } else {
michael@0 7476 // Our parent's "auto" value should resolve to our grandparent's value
michael@0 7477 // for "align-items". So, that's what we're supposed to inherit.
michael@0 7478 nsStyleContext* grandparentContext = parentContext->GetParent();
michael@0 7479 if (!grandparentContext) {
michael@0 7480 // No grandparent --> our parent is the root node, so its
michael@0 7481 // "align-self: auto" computes to the default "align-items" value:
michael@0 7482 inheritedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
michael@0 7483 } else {
michael@0 7484 // Normal case -- we have a grandparent.
michael@0 7485 // Its "align-items" value is what we should end up inheriting.
michael@0 7486 const nsStylePosition* grandparentPos =
michael@0 7487 grandparentContext->StylePosition();
michael@0 7488 inheritedAlignSelf = grandparentPos->mAlignItems;
michael@0 7489 }
michael@0 7490 }
michael@0 7491 }
michael@0 7492
michael@0 7493 pos->mAlignSelf = inheritedAlignSelf;
michael@0 7494 canStoreInRuleTree = false;
michael@0 7495 } else {
michael@0 7496 SetDiscrete(*aRuleData->ValueForAlignSelf(),
michael@0 7497 pos->mAlignSelf, canStoreInRuleTree,
michael@0 7498 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 7499 parentPos->mAlignSelf, // (unused -- we handled inherit above)
michael@0 7500 NS_STYLE_ALIGN_SELF_AUTO, // initial == auto
michael@0 7501 0, 0, 0, 0);
michael@0 7502 }
michael@0 7503
michael@0 7504 // flex-basis: auto, length, percent, enum, calc, inherit, initial
michael@0 7505 // (Note: The flags here should match those used for 'width' property above.)
michael@0 7506 SetCoord(*aRuleData->ValueForFlexBasis(), pos->mFlexBasis, parentPos->mFlexBasis,
michael@0 7507 SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
michael@0 7508 SETCOORD_UNSET_INITIAL,
michael@0 7509 aContext, mPresContext, canStoreInRuleTree);
michael@0 7510
michael@0 7511 // flex-direction: enum, inherit, initial
michael@0 7512 SetDiscrete(*aRuleData->ValueForFlexDirection(),
michael@0 7513 pos->mFlexDirection, canStoreInRuleTree,
michael@0 7514 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 7515 parentPos->mFlexDirection,
michael@0 7516 NS_STYLE_FLEX_DIRECTION_ROW, 0, 0, 0, 0);
michael@0 7517
michael@0 7518 // flex-grow: float, inherit, initial
michael@0 7519 SetFactor(*aRuleData->ValueForFlexGrow(),
michael@0 7520 pos->mFlexGrow, canStoreInRuleTree,
michael@0 7521 parentPos->mFlexGrow, 0.0f,
michael@0 7522 SETFCT_UNSET_INITIAL);
michael@0 7523
michael@0 7524 // flex-shrink: float, inherit, initial
michael@0 7525 SetFactor(*aRuleData->ValueForFlexShrink(),
michael@0 7526 pos->mFlexShrink, canStoreInRuleTree,
michael@0 7527 parentPos->mFlexShrink, 1.0f,
michael@0 7528 SETFCT_UNSET_INITIAL);
michael@0 7529
michael@0 7530 // flex-wrap: enum, inherit, initial
michael@0 7531 SetDiscrete(*aRuleData->ValueForFlexWrap(),
michael@0 7532 pos->mFlexWrap, canStoreInRuleTree,
michael@0 7533 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 7534 parentPos->mFlexWrap,
michael@0 7535 NS_STYLE_FLEX_WRAP_NOWRAP, 0, 0, 0, 0);
michael@0 7536
michael@0 7537 // order: integer, inherit, initial
michael@0 7538 SetDiscrete(*aRuleData->ValueForOrder(),
michael@0 7539 pos->mOrder, canStoreInRuleTree,
michael@0 7540 SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
michael@0 7541 parentPos->mOrder,
michael@0 7542 NS_STYLE_ORDER_INITIAL, 0, 0, 0, 0);
michael@0 7543
michael@0 7544 // justify-content: enum, inherit, initial
michael@0 7545 SetDiscrete(*aRuleData->ValueForJustifyContent(),
michael@0 7546 pos->mJustifyContent, canStoreInRuleTree,
michael@0 7547 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 7548 parentPos->mJustifyContent,
michael@0 7549 NS_STYLE_JUSTIFY_CONTENT_FLEX_START, 0, 0, 0, 0);
michael@0 7550
michael@0 7551 // grid-auto-flow
michael@0 7552 const nsCSSValue& gridAutoFlow = *aRuleData->ValueForGridAutoFlow();
michael@0 7553 switch (gridAutoFlow.GetUnit()) {
michael@0 7554 case eCSSUnit_Null:
michael@0 7555 break;
michael@0 7556 case eCSSUnit_Inherit:
michael@0 7557 canStoreInRuleTree = false;
michael@0 7558 pos->mGridAutoFlow = parentPos->mGridAutoFlow;
michael@0 7559 break;
michael@0 7560 case eCSSUnit_Initial:
michael@0 7561 case eCSSUnit_Unset:
michael@0 7562 pos->mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_NONE;
michael@0 7563 break;
michael@0 7564 default:
michael@0 7565 NS_ASSERTION(gridAutoFlow.GetUnit() == eCSSUnit_Enumerated,
michael@0 7566 "Unexpected unit");
michael@0 7567 pos->mGridAutoFlow = gridAutoFlow.GetIntValue();
michael@0 7568 }
michael@0 7569
michael@0 7570 // grid-auto-columns
michael@0 7571 SetGridAutoColumnsRows(*aRuleData->ValueForGridAutoColumns(),
michael@0 7572 pos->mGridAutoColumnsMin,
michael@0 7573 pos->mGridAutoColumnsMax,
michael@0 7574 parentPos->mGridAutoColumnsMin,
michael@0 7575 parentPos->mGridAutoColumnsMax,
michael@0 7576 aContext, mPresContext, canStoreInRuleTree);
michael@0 7577
michael@0 7578 // grid-auto-rows
michael@0 7579 SetGridAutoColumnsRows(*aRuleData->ValueForGridAutoRows(),
michael@0 7580 pos->mGridAutoRowsMin,
michael@0 7581 pos->mGridAutoRowsMax,
michael@0 7582 parentPos->mGridAutoRowsMin,
michael@0 7583 parentPos->mGridAutoRowsMax,
michael@0 7584 aContext, mPresContext, canStoreInRuleTree);
michael@0 7585
michael@0 7586 // grid-template-columns
michael@0 7587 SetGridTrackList(*aRuleData->ValueForGridTemplateColumns(),
michael@0 7588 pos->mGridTemplateColumns, parentPos->mGridTemplateColumns,
michael@0 7589 aContext, mPresContext, canStoreInRuleTree);
michael@0 7590
michael@0 7591 // grid-template-rows
michael@0 7592 SetGridTrackList(*aRuleData->ValueForGridTemplateRows(),
michael@0 7593 pos->mGridTemplateRows, parentPos->mGridTemplateRows,
michael@0 7594 aContext, mPresContext, canStoreInRuleTree);
michael@0 7595
michael@0 7596 // grid-tempate-areas
michael@0 7597 SetGridTemplateAreas(*aRuleData->ValueForGridTemplateAreas(),
michael@0 7598 &pos->mGridTemplateAreas,
michael@0 7599 parentPos->mGridTemplateAreas,
michael@0 7600 canStoreInRuleTree);
michael@0 7601
michael@0 7602 // grid-auto-position
michael@0 7603 const nsCSSValue& gridAutoPosition = *aRuleData->ValueForGridAutoPosition();
michael@0 7604 switch (gridAutoPosition.GetUnit()) {
michael@0 7605 case eCSSUnit_Null:
michael@0 7606 break;
michael@0 7607 case eCSSUnit_Inherit:
michael@0 7608 canStoreInRuleTree = false;
michael@0 7609 pos->mGridAutoPositionColumn = parentPos->mGridAutoPositionColumn;
michael@0 7610 pos->mGridAutoPositionRow = parentPos->mGridAutoPositionRow;
michael@0 7611 break;
michael@0 7612 case eCSSUnit_Initial:
michael@0 7613 case eCSSUnit_Unset:
michael@0 7614 // '1 / 1'
michael@0 7615 pos->mGridAutoPositionColumn.SetToInteger(1);
michael@0 7616 pos->mGridAutoPositionRow.SetToInteger(1);
michael@0 7617 break;
michael@0 7618 default:
michael@0 7619 SetGridLine(gridAutoPosition.GetPairValue().mXValue,
michael@0 7620 pos->mGridAutoPositionColumn,
michael@0 7621 parentPos->mGridAutoPositionColumn,
michael@0 7622 canStoreInRuleTree);
michael@0 7623 SetGridLine(gridAutoPosition.GetPairValue().mYValue,
michael@0 7624 pos->mGridAutoPositionRow,
michael@0 7625 parentPos->mGridAutoPositionRow,
michael@0 7626 canStoreInRuleTree);
michael@0 7627 }
michael@0 7628
michael@0 7629 // grid-column-start
michael@0 7630 SetGridLine(*aRuleData->ValueForGridColumnStart(),
michael@0 7631 pos->mGridColumnStart,
michael@0 7632 parentPos->mGridColumnStart,
michael@0 7633 canStoreInRuleTree);
michael@0 7634
michael@0 7635 // grid-column-end
michael@0 7636 SetGridLine(*aRuleData->ValueForGridColumnEnd(),
michael@0 7637 pos->mGridColumnEnd,
michael@0 7638 parentPos->mGridColumnEnd,
michael@0 7639 canStoreInRuleTree);
michael@0 7640
michael@0 7641 // grid-row-start
michael@0 7642 SetGridLine(*aRuleData->ValueForGridRowStart(),
michael@0 7643 pos->mGridRowStart,
michael@0 7644 parentPos->mGridRowStart,
michael@0 7645 canStoreInRuleTree);
michael@0 7646
michael@0 7647 // grid-row-end
michael@0 7648 SetGridLine(*aRuleData->ValueForGridRowEnd(),
michael@0 7649 pos->mGridRowEnd,
michael@0 7650 parentPos->mGridRowEnd,
michael@0 7651 canStoreInRuleTree);
michael@0 7652
michael@0 7653 // z-index
michael@0 7654 const nsCSSValue* zIndexValue = aRuleData->ValueForZIndex();
michael@0 7655 if (! SetCoord(*zIndexValue, pos->mZIndex, parentPos->mZIndex,
michael@0 7656 SETCOORD_IA | SETCOORD_INITIAL_AUTO | SETCOORD_UNSET_INITIAL,
michael@0 7657 aContext, nullptr, canStoreInRuleTree)) {
michael@0 7658 if (eCSSUnit_Inherit == zIndexValue->GetUnit()) {
michael@0 7659 // handle inherit, because it's ok to inherit 'auto' here
michael@0 7660 canStoreInRuleTree = false;
michael@0 7661 pos->mZIndex = parentPos->mZIndex;
michael@0 7662 }
michael@0 7663 }
michael@0 7664
michael@0 7665 COMPUTE_END_RESET(Position, pos)
michael@0 7666 }
michael@0 7667
michael@0 7668 const void*
michael@0 7669 nsRuleNode::ComputeTableData(void* aStartStruct,
michael@0 7670 const nsRuleData* aRuleData,
michael@0 7671 nsStyleContext* aContext,
michael@0 7672 nsRuleNode* aHighestNode,
michael@0 7673 const RuleDetail aRuleDetail,
michael@0 7674 const bool aCanStoreInRuleTree)
michael@0 7675 {
michael@0 7676 COMPUTE_START_RESET(Table, (), table, parentTable)
michael@0 7677
michael@0 7678 // table-layout: enum, inherit, initial
michael@0 7679 SetDiscrete(*aRuleData->ValueForTableLayout(),
michael@0 7680 table->mLayoutStrategy, canStoreInRuleTree,
michael@0 7681 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 7682 parentTable->mLayoutStrategy,
michael@0 7683 NS_STYLE_TABLE_LAYOUT_AUTO, 0, 0, 0, 0);
michael@0 7684
michael@0 7685 // span: pixels (not a real CSS prop)
michael@0 7686 const nsCSSValue* spanValue = aRuleData->ValueForSpan();
michael@0 7687 if (eCSSUnit_Enumerated == spanValue->GetUnit() ||
michael@0 7688 eCSSUnit_Integer == spanValue->GetUnit())
michael@0 7689 table->mSpan = spanValue->GetIntValue();
michael@0 7690
michael@0 7691 COMPUTE_END_RESET(Table, table)
michael@0 7692 }
michael@0 7693
michael@0 7694 const void*
michael@0 7695 nsRuleNode::ComputeTableBorderData(void* aStartStruct,
michael@0 7696 const nsRuleData* aRuleData,
michael@0 7697 nsStyleContext* aContext,
michael@0 7698 nsRuleNode* aHighestNode,
michael@0 7699 const RuleDetail aRuleDetail,
michael@0 7700 const bool aCanStoreInRuleTree)
michael@0 7701 {
michael@0 7702 COMPUTE_START_INHERITED(TableBorder, (mPresContext), table, parentTable)
michael@0 7703
michael@0 7704 // border-collapse: enum, inherit, initial
michael@0 7705 SetDiscrete(*aRuleData->ValueForBorderCollapse(), table->mBorderCollapse,
michael@0 7706 canStoreInRuleTree,
michael@0 7707 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 7708 parentTable->mBorderCollapse,
michael@0 7709 NS_STYLE_BORDER_SEPARATE, 0, 0, 0, 0);
michael@0 7710
michael@0 7711 const nsCSSValue* borderSpacingValue = aRuleData->ValueForBorderSpacing();
michael@0 7712 if (borderSpacingValue->GetUnit() != eCSSUnit_Null) {
michael@0 7713 // border-spacing-x/y: length, inherit
michael@0 7714 nsStyleCoord parentX(parentTable->mBorderSpacingX,
michael@0 7715 nsStyleCoord::CoordConstructor);
michael@0 7716 nsStyleCoord parentY(parentTable->mBorderSpacingY,
michael@0 7717 nsStyleCoord::CoordConstructor);
michael@0 7718 nsStyleCoord coordX, coordY;
michael@0 7719
michael@0 7720 #ifdef DEBUG
michael@0 7721 bool result =
michael@0 7722 #endif
michael@0 7723 SetPairCoords(*borderSpacingValue,
michael@0 7724 coordX, coordY, parentX, parentY,
michael@0 7725 SETCOORD_LH | SETCOORD_INITIAL_ZERO |
michael@0 7726 SETCOORD_CALC_LENGTH_ONLY |
michael@0 7727 SETCOORD_CALC_CLAMP_NONNEGATIVE | SETCOORD_UNSET_INHERIT,
michael@0 7728 aContext, mPresContext, canStoreInRuleTree);
michael@0 7729 NS_ASSERTION(result, "malformed table border value");
michael@0 7730 table->mBorderSpacingX = coordX.GetCoordValue();
michael@0 7731 table->mBorderSpacingY = coordY.GetCoordValue();
michael@0 7732 }
michael@0 7733
michael@0 7734 // caption-side: enum, inherit, initial
michael@0 7735 SetDiscrete(*aRuleData->ValueForCaptionSide(),
michael@0 7736 table->mCaptionSide, canStoreInRuleTree,
michael@0 7737 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 7738 parentTable->mCaptionSide,
michael@0 7739 NS_STYLE_CAPTION_SIDE_TOP, 0, 0, 0, 0);
michael@0 7740
michael@0 7741 // empty-cells: enum, inherit, initial
michael@0 7742 SetDiscrete(*aRuleData->ValueForEmptyCells(),
michael@0 7743 table->mEmptyCells, canStoreInRuleTree,
michael@0 7744 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 7745 parentTable->mEmptyCells,
michael@0 7746 (mPresContext->CompatibilityMode() == eCompatibility_NavQuirks)
michael@0 7747 ? NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND
michael@0 7748 : NS_STYLE_TABLE_EMPTY_CELLS_SHOW,
michael@0 7749 0, 0, 0, 0);
michael@0 7750
michael@0 7751 COMPUTE_END_INHERITED(TableBorder, table)
michael@0 7752 }
michael@0 7753
michael@0 7754 const void*
michael@0 7755 nsRuleNode::ComputeContentData(void* aStartStruct,
michael@0 7756 const nsRuleData* aRuleData,
michael@0 7757 nsStyleContext* aContext,
michael@0 7758 nsRuleNode* aHighestNode,
michael@0 7759 const RuleDetail aRuleDetail,
michael@0 7760 const bool aCanStoreInRuleTree)
michael@0 7761 {
michael@0 7762 uint32_t count;
michael@0 7763 nsAutoString buffer;
michael@0 7764
michael@0 7765 COMPUTE_START_RESET(Content, (), content, parentContent)
michael@0 7766
michael@0 7767 // content: [string, url, counter, attr, enum]+, normal, none, inherit
michael@0 7768 const nsCSSValue* contentValue = aRuleData->ValueForContent();
michael@0 7769 switch (contentValue->GetUnit()) {
michael@0 7770 case eCSSUnit_Null:
michael@0 7771 break;
michael@0 7772
michael@0 7773 case eCSSUnit_Normal:
michael@0 7774 case eCSSUnit_None:
michael@0 7775 case eCSSUnit_Initial:
michael@0 7776 case eCSSUnit_Unset:
michael@0 7777 // "normal", "none", "initial" and "unset" all mean no content
michael@0 7778 content->AllocateContents(0);
michael@0 7779 break;
michael@0 7780
michael@0 7781 case eCSSUnit_Inherit:
michael@0 7782 canStoreInRuleTree = false;
michael@0 7783 count = parentContent->ContentCount();
michael@0 7784 if (NS_SUCCEEDED(content->AllocateContents(count))) {
michael@0 7785 while (0 < count--) {
michael@0 7786 content->ContentAt(count) = parentContent->ContentAt(count);
michael@0 7787 }
michael@0 7788 }
michael@0 7789 break;
michael@0 7790
michael@0 7791 case eCSSUnit_Enumerated: {
michael@0 7792 NS_ABORT_IF_FALSE(contentValue->GetIntValue() ==
michael@0 7793 NS_STYLE_CONTENT_ALT_CONTENT,
michael@0 7794 "unrecognized solitary content keyword");
michael@0 7795 content->AllocateContents(1);
michael@0 7796 nsStyleContentData& data = content->ContentAt(0);
michael@0 7797 data.mType = eStyleContentType_AltContent;
michael@0 7798 data.mContent.mString = nullptr;
michael@0 7799 break;
michael@0 7800 }
michael@0 7801
michael@0 7802 case eCSSUnit_List:
michael@0 7803 case eCSSUnit_ListDep: {
michael@0 7804 const nsCSSValueList* contentValueList = contentValue->GetListValue();
michael@0 7805 count = 0;
michael@0 7806 while (contentValueList) {
michael@0 7807 count++;
michael@0 7808 contentValueList = contentValueList->mNext;
michael@0 7809 }
michael@0 7810 if (NS_SUCCEEDED(content->AllocateContents(count))) {
michael@0 7811 const nsAutoString nullStr;
michael@0 7812 count = 0;
michael@0 7813 contentValueList = contentValue->GetListValue();
michael@0 7814 while (contentValueList) {
michael@0 7815 const nsCSSValue& value = contentValueList->mValue;
michael@0 7816 nsCSSUnit unit = value.GetUnit();
michael@0 7817 nsStyleContentType type;
michael@0 7818 nsStyleContentData &data = content->ContentAt(count++);
michael@0 7819 switch (unit) {
michael@0 7820 case eCSSUnit_String: type = eStyleContentType_String; break;
michael@0 7821 case eCSSUnit_Image: type = eStyleContentType_Image; break;
michael@0 7822 case eCSSUnit_Attr: type = eStyleContentType_Attr; break;
michael@0 7823 case eCSSUnit_Counter: type = eStyleContentType_Counter; break;
michael@0 7824 case eCSSUnit_Counters: type = eStyleContentType_Counters; break;
michael@0 7825 case eCSSUnit_Enumerated:
michael@0 7826 switch (value.GetIntValue()) {
michael@0 7827 case NS_STYLE_CONTENT_OPEN_QUOTE:
michael@0 7828 type = eStyleContentType_OpenQuote; break;
michael@0 7829 case NS_STYLE_CONTENT_CLOSE_QUOTE:
michael@0 7830 type = eStyleContentType_CloseQuote; break;
michael@0 7831 case NS_STYLE_CONTENT_NO_OPEN_QUOTE:
michael@0 7832 type = eStyleContentType_NoOpenQuote; break;
michael@0 7833 case NS_STYLE_CONTENT_NO_CLOSE_QUOTE:
michael@0 7834 type = eStyleContentType_NoCloseQuote; break;
michael@0 7835 default:
michael@0 7836 NS_ERROR("bad content value");
michael@0 7837 type = eStyleContentType_Uninitialized;
michael@0 7838 }
michael@0 7839 break;
michael@0 7840 default:
michael@0 7841 NS_ERROR("bad content type");
michael@0 7842 type = eStyleContentType_Uninitialized;
michael@0 7843 }
michael@0 7844 data.mType = type;
michael@0 7845 if (type == eStyleContentType_Image) {
michael@0 7846 NS_SET_IMAGE_REQUEST_WITH_DOC(data.SetImage,
michael@0 7847 aContext,
michael@0 7848 value.GetImageValue);
michael@0 7849 }
michael@0 7850 else if (type <= eStyleContentType_Attr) {
michael@0 7851 value.GetStringValue(buffer);
michael@0 7852 data.mContent.mString = NS_strdup(buffer.get());
michael@0 7853 }
michael@0 7854 else if (type <= eStyleContentType_Counters) {
michael@0 7855 data.mContent.mCounters = value.GetArrayValue();
michael@0 7856 data.mContent.mCounters->AddRef();
michael@0 7857 }
michael@0 7858 else {
michael@0 7859 data.mContent.mString = nullptr;
michael@0 7860 }
michael@0 7861 contentValueList = contentValueList->mNext;
michael@0 7862 }
michael@0 7863 }
michael@0 7864 break;
michael@0 7865 }
michael@0 7866
michael@0 7867 default:
michael@0 7868 NS_ABORT_IF_FALSE(false,
michael@0 7869 nsPrintfCString("unrecognized content unit %d",
michael@0 7870 contentValue->GetUnit()).get());
michael@0 7871 }
michael@0 7872
michael@0 7873 // counter-increment: [string [int]]+, none, inherit
michael@0 7874 const nsCSSValue* counterIncrementValue =
michael@0 7875 aRuleData->ValueForCounterIncrement();
michael@0 7876 switch (counterIncrementValue->GetUnit()) {
michael@0 7877 case eCSSUnit_Null:
michael@0 7878 break;
michael@0 7879
michael@0 7880 case eCSSUnit_None:
michael@0 7881 case eCSSUnit_Initial:
michael@0 7882 case eCSSUnit_Unset:
michael@0 7883 content->AllocateCounterIncrements(0);
michael@0 7884 break;
michael@0 7885
michael@0 7886 case eCSSUnit_Inherit:
michael@0 7887 canStoreInRuleTree = false;
michael@0 7888 count = parentContent->CounterIncrementCount();
michael@0 7889 if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
michael@0 7890 while (0 < count--) {
michael@0 7891 const nsStyleCounterData *data =
michael@0 7892 parentContent->GetCounterIncrementAt(count);
michael@0 7893 content->SetCounterIncrementAt(count, data->mCounter, data->mValue);
michael@0 7894 }
michael@0 7895 }
michael@0 7896 break;
michael@0 7897
michael@0 7898 case eCSSUnit_PairList:
michael@0 7899 case eCSSUnit_PairListDep: {
michael@0 7900 const nsCSSValuePairList* ourIncrement =
michael@0 7901 counterIncrementValue->GetPairListValue();
michael@0 7902 NS_ABORT_IF_FALSE(ourIncrement->mXValue.GetUnit() == eCSSUnit_Ident,
michael@0 7903 "unexpected value unit");
michael@0 7904 count = ListLength(ourIncrement);
michael@0 7905 if (NS_FAILED(content->AllocateCounterIncrements(count))) {
michael@0 7906 break;
michael@0 7907 }
michael@0 7908
michael@0 7909 count = 0;
michael@0 7910 for (const nsCSSValuePairList* p = ourIncrement; p; p = p->mNext, count++) {
michael@0 7911 int32_t increment;
michael@0 7912 if (p->mYValue.GetUnit() == eCSSUnit_Integer) {
michael@0 7913 increment = p->mYValue.GetIntValue();
michael@0 7914 } else {
michael@0 7915 increment = 1;
michael@0 7916 }
michael@0 7917 p->mXValue.GetStringValue(buffer);
michael@0 7918 content->SetCounterIncrementAt(count, buffer, increment);
michael@0 7919 }
michael@0 7920 break;
michael@0 7921 }
michael@0 7922
michael@0 7923 default:
michael@0 7924 NS_ABORT_IF_FALSE(false, "unexpected value unit");
michael@0 7925 }
michael@0 7926
michael@0 7927 // counter-reset: [string [int]]+, none, inherit
michael@0 7928 const nsCSSValue* counterResetValue = aRuleData->ValueForCounterReset();
michael@0 7929 switch (counterResetValue->GetUnit()) {
michael@0 7930 case eCSSUnit_Null:
michael@0 7931 break;
michael@0 7932
michael@0 7933 case eCSSUnit_None:
michael@0 7934 case eCSSUnit_Initial:
michael@0 7935 case eCSSUnit_Unset:
michael@0 7936 content->AllocateCounterResets(0);
michael@0 7937 break;
michael@0 7938
michael@0 7939 case eCSSUnit_Inherit:
michael@0 7940 canStoreInRuleTree = false;
michael@0 7941 count = parentContent->CounterResetCount();
michael@0 7942 if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
michael@0 7943 while (0 < count--) {
michael@0 7944 const nsStyleCounterData *data =
michael@0 7945 parentContent->GetCounterResetAt(count);
michael@0 7946 content->SetCounterResetAt(count, data->mCounter, data->mValue);
michael@0 7947 }
michael@0 7948 }
michael@0 7949 break;
michael@0 7950
michael@0 7951 case eCSSUnit_PairList:
michael@0 7952 case eCSSUnit_PairListDep: {
michael@0 7953 const nsCSSValuePairList* ourReset =
michael@0 7954 counterResetValue->GetPairListValue();
michael@0 7955 NS_ABORT_IF_FALSE(ourReset->mXValue.GetUnit() == eCSSUnit_Ident,
michael@0 7956 "unexpected value unit");
michael@0 7957 count = ListLength(ourReset);
michael@0 7958 if (NS_FAILED(content->AllocateCounterResets(count))) {
michael@0 7959 break;
michael@0 7960 }
michael@0 7961
michael@0 7962 count = 0;
michael@0 7963 for (const nsCSSValuePairList* p = ourReset; p; p = p->mNext, count++) {
michael@0 7964 int32_t reset;
michael@0 7965 if (p->mYValue.GetUnit() == eCSSUnit_Integer) {
michael@0 7966 reset = p->mYValue.GetIntValue();
michael@0 7967 } else {
michael@0 7968 reset = 0;
michael@0 7969 }
michael@0 7970 p->mXValue.GetStringValue(buffer);
michael@0 7971 content->SetCounterResetAt(count, buffer, reset);
michael@0 7972 }
michael@0 7973 break;
michael@0 7974 }
michael@0 7975
michael@0 7976 default:
michael@0 7977 NS_ABORT_IF_FALSE(false, "unexpected value unit");
michael@0 7978 }
michael@0 7979
michael@0 7980 // marker-offset: length, auto, inherit
michael@0 7981 SetCoord(*aRuleData->ValueForMarkerOffset(), content->mMarkerOffset, parentContent->mMarkerOffset,
michael@0 7982 SETCOORD_LH | SETCOORD_AUTO | SETCOORD_INITIAL_AUTO |
michael@0 7983 SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INITIAL,
michael@0 7984 aContext, mPresContext, canStoreInRuleTree);
michael@0 7985
michael@0 7986 // If we ended up with an image, track it.
michael@0 7987 for (uint32_t i = 0; i < content->ContentCount(); ++i) {
michael@0 7988 if ((content->ContentAt(i).mType == eStyleContentType_Image) &&
michael@0 7989 content->ContentAt(i).mContent.mImage) {
michael@0 7990 content->ContentAt(i).TrackImage(aContext->PresContext());
michael@0 7991 }
michael@0 7992 }
michael@0 7993
michael@0 7994 COMPUTE_END_RESET(Content, content)
michael@0 7995 }
michael@0 7996
michael@0 7997 const void*
michael@0 7998 nsRuleNode::ComputeQuotesData(void* aStartStruct,
michael@0 7999 const nsRuleData* aRuleData,
michael@0 8000 nsStyleContext* aContext,
michael@0 8001 nsRuleNode* aHighestNode,
michael@0 8002 const RuleDetail aRuleDetail,
michael@0 8003 const bool aCanStoreInRuleTree)
michael@0 8004 {
michael@0 8005 COMPUTE_START_INHERITED(Quotes, (), quotes, parentQuotes)
michael@0 8006
michael@0 8007 // quotes: inherit, initial, none, [string string]+
michael@0 8008 const nsCSSValue* quotesValue = aRuleData->ValueForQuotes();
michael@0 8009 switch (quotesValue->GetUnit()) {
michael@0 8010 case eCSSUnit_Null:
michael@0 8011 break;
michael@0 8012 case eCSSUnit_Inherit:
michael@0 8013 case eCSSUnit_Unset:
michael@0 8014 canStoreInRuleTree = false;
michael@0 8015 quotes->CopyFrom(*parentQuotes);
michael@0 8016 break;
michael@0 8017 case eCSSUnit_Initial:
michael@0 8018 quotes->SetInitial();
michael@0 8019 break;
michael@0 8020 case eCSSUnit_None:
michael@0 8021 quotes->AllocateQuotes(0);
michael@0 8022 break;
michael@0 8023 case eCSSUnit_PairList:
michael@0 8024 case eCSSUnit_PairListDep: {
michael@0 8025 const nsCSSValuePairList* ourQuotes
michael@0 8026 = quotesValue->GetPairListValue();
michael@0 8027 nsAutoString buffer;
michael@0 8028 nsAutoString closeBuffer;
michael@0 8029 uint32_t count = ListLength(ourQuotes);
michael@0 8030 if (NS_FAILED(quotes->AllocateQuotes(count))) {
michael@0 8031 break;
michael@0 8032 }
michael@0 8033 count = 0;
michael@0 8034 while (ourQuotes) {
michael@0 8035 NS_ABORT_IF_FALSE(ourQuotes->mXValue.GetUnit() == eCSSUnit_String &&
michael@0 8036 ourQuotes->mYValue.GetUnit() == eCSSUnit_String,
michael@0 8037 "improper list contents for quotes");
michael@0 8038 ourQuotes->mXValue.GetStringValue(buffer);
michael@0 8039 ourQuotes->mYValue.GetStringValue(closeBuffer);
michael@0 8040 quotes->SetQuotesAt(count++, buffer, closeBuffer);
michael@0 8041 ourQuotes = ourQuotes->mNext;
michael@0 8042 }
michael@0 8043 break;
michael@0 8044 }
michael@0 8045 default:
michael@0 8046 NS_ABORT_IF_FALSE(false, "unexpected value unit");
michael@0 8047 }
michael@0 8048
michael@0 8049 COMPUTE_END_INHERITED(Quotes, quotes)
michael@0 8050 }
michael@0 8051
michael@0 8052 const void*
michael@0 8053 nsRuleNode::ComputeXULData(void* aStartStruct,
michael@0 8054 const nsRuleData* aRuleData,
michael@0 8055 nsStyleContext* aContext,
michael@0 8056 nsRuleNode* aHighestNode,
michael@0 8057 const RuleDetail aRuleDetail,
michael@0 8058 const bool aCanStoreInRuleTree)
michael@0 8059 {
michael@0 8060 COMPUTE_START_RESET(XUL, (), xul, parentXUL)
michael@0 8061
michael@0 8062 // box-align: enum, inherit, initial
michael@0 8063 SetDiscrete(*aRuleData->ValueForBoxAlign(),
michael@0 8064 xul->mBoxAlign, canStoreInRuleTree,
michael@0 8065 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 8066 parentXUL->mBoxAlign,
michael@0 8067 NS_STYLE_BOX_ALIGN_STRETCH, 0, 0, 0, 0);
michael@0 8068
michael@0 8069 // box-direction: enum, inherit, initial
michael@0 8070 SetDiscrete(*aRuleData->ValueForBoxDirection(),
michael@0 8071 xul->mBoxDirection, canStoreInRuleTree,
michael@0 8072 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 8073 parentXUL->mBoxDirection,
michael@0 8074 NS_STYLE_BOX_DIRECTION_NORMAL, 0, 0, 0, 0);
michael@0 8075
michael@0 8076 // box-flex: factor, inherit
michael@0 8077 SetFactor(*aRuleData->ValueForBoxFlex(),
michael@0 8078 xul->mBoxFlex, canStoreInRuleTree,
michael@0 8079 parentXUL->mBoxFlex, 0.0f,
michael@0 8080 SETFCT_UNSET_INITIAL);
michael@0 8081
michael@0 8082 // box-orient: enum, inherit, initial
michael@0 8083 SetDiscrete(*aRuleData->ValueForBoxOrient(),
michael@0 8084 xul->mBoxOrient, canStoreInRuleTree,
michael@0 8085 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 8086 parentXUL->mBoxOrient,
michael@0 8087 NS_STYLE_BOX_ORIENT_HORIZONTAL, 0, 0, 0, 0);
michael@0 8088
michael@0 8089 // box-pack: enum, inherit, initial
michael@0 8090 SetDiscrete(*aRuleData->ValueForBoxPack(),
michael@0 8091 xul->mBoxPack, canStoreInRuleTree,
michael@0 8092 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 8093 parentXUL->mBoxPack,
michael@0 8094 NS_STYLE_BOX_PACK_START, 0, 0, 0, 0);
michael@0 8095
michael@0 8096 // box-ordinal-group: integer, inherit, initial
michael@0 8097 SetDiscrete(*aRuleData->ValueForBoxOrdinalGroup(),
michael@0 8098 xul->mBoxOrdinal, canStoreInRuleTree,
michael@0 8099 SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
michael@0 8100 parentXUL->mBoxOrdinal, 1,
michael@0 8101 0, 0, 0, 0);
michael@0 8102
michael@0 8103 const nsCSSValue* stackSizingValue = aRuleData->ValueForStackSizing();
michael@0 8104 if (eCSSUnit_Inherit == stackSizingValue->GetUnit()) {
michael@0 8105 canStoreInRuleTree = false;
michael@0 8106 xul->mStretchStack = parentXUL->mStretchStack;
michael@0 8107 } else if (eCSSUnit_Initial == stackSizingValue->GetUnit() ||
michael@0 8108 eCSSUnit_Unset == stackSizingValue->GetUnit()) {
michael@0 8109 xul->mStretchStack = true;
michael@0 8110 } else if (eCSSUnit_Enumerated == stackSizingValue->GetUnit()) {
michael@0 8111 xul->mStretchStack = stackSizingValue->GetIntValue() ==
michael@0 8112 NS_STYLE_STACK_SIZING_STRETCH_TO_FIT;
michael@0 8113 }
michael@0 8114
michael@0 8115 COMPUTE_END_RESET(XUL, xul)
michael@0 8116 }
michael@0 8117
michael@0 8118 const void*
michael@0 8119 nsRuleNode::ComputeColumnData(void* aStartStruct,
michael@0 8120 const nsRuleData* aRuleData,
michael@0 8121 nsStyleContext* aContext,
michael@0 8122 nsRuleNode* aHighestNode,
michael@0 8123 const RuleDetail aRuleDetail,
michael@0 8124 const bool aCanStoreInRuleTree)
michael@0 8125 {
michael@0 8126 COMPUTE_START_RESET(Column, (mPresContext), column, parent)
michael@0 8127
michael@0 8128 // column-width: length, auto, inherit
michael@0 8129 SetCoord(*aRuleData->ValueForColumnWidth(),
michael@0 8130 column->mColumnWidth, parent->mColumnWidth,
michael@0 8131 SETCOORD_LAH | SETCOORD_INITIAL_AUTO |
michael@0 8132 SETCOORD_CALC_LENGTH_ONLY | SETCOORD_CALC_CLAMP_NONNEGATIVE |
michael@0 8133 SETCOORD_UNSET_INITIAL,
michael@0 8134 aContext, mPresContext, canStoreInRuleTree);
michael@0 8135
michael@0 8136 // column-gap: length, inherit, normal
michael@0 8137 SetCoord(*aRuleData->ValueForColumnGap(),
michael@0 8138 column->mColumnGap, parent->mColumnGap,
michael@0 8139 SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
michael@0 8140 SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INITIAL,
michael@0 8141 aContext, mPresContext, canStoreInRuleTree);
michael@0 8142 // clamp negative calc() to 0
michael@0 8143 if (column->mColumnGap.GetUnit() == eStyleUnit_Coord) {
michael@0 8144 column->mColumnGap.SetCoordValue(
michael@0 8145 std::max(column->mColumnGap.GetCoordValue(), 0));
michael@0 8146 }
michael@0 8147
michael@0 8148 // column-count: auto, integer, inherit
michael@0 8149 const nsCSSValue* columnCountValue = aRuleData->ValueForColumnCount();
michael@0 8150 if (eCSSUnit_Auto == columnCountValue->GetUnit() ||
michael@0 8151 eCSSUnit_Initial == columnCountValue->GetUnit() ||
michael@0 8152 eCSSUnit_Unset == columnCountValue->GetUnit()) {
michael@0 8153 column->mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
michael@0 8154 } else if (eCSSUnit_Integer == columnCountValue->GetUnit()) {
michael@0 8155 column->mColumnCount = columnCountValue->GetIntValue();
michael@0 8156 // Max kMaxColumnCount columns - wallpaper for bug 345583.
michael@0 8157 column->mColumnCount = std::min(column->mColumnCount,
michael@0 8158 nsStyleColumn::kMaxColumnCount);
michael@0 8159 } else if (eCSSUnit_Inherit == columnCountValue->GetUnit()) {
michael@0 8160 canStoreInRuleTree = false;
michael@0 8161 column->mColumnCount = parent->mColumnCount;
michael@0 8162 }
michael@0 8163
michael@0 8164 // column-rule-width: length, enum, inherit
michael@0 8165 const nsCSSValue& widthValue = *aRuleData->ValueForColumnRuleWidth();
michael@0 8166 if (eCSSUnit_Initial == widthValue.GetUnit() ||
michael@0 8167 eCSSUnit_Unset == widthValue.GetUnit()) {
michael@0 8168 column->SetColumnRuleWidth(
michael@0 8169 (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
michael@0 8170 }
michael@0 8171 else if (eCSSUnit_Enumerated == widthValue.GetUnit()) {
michael@0 8172 NS_ASSERTION(widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
michael@0 8173 widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
michael@0 8174 widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
michael@0 8175 "Unexpected enum value");
michael@0 8176 column->SetColumnRuleWidth(
michael@0 8177 (mPresContext->GetBorderWidthTable())[widthValue.GetIntValue()]);
michael@0 8178 }
michael@0 8179 else if (eCSSUnit_Inherit == widthValue.GetUnit()) {
michael@0 8180 column->SetColumnRuleWidth(parent->GetComputedColumnRuleWidth());
michael@0 8181 canStoreInRuleTree = false;
michael@0 8182 }
michael@0 8183 else if (widthValue.IsLengthUnit() || widthValue.IsCalcUnit()) {
michael@0 8184 nscoord len =
michael@0 8185 CalcLength(widthValue, aContext, mPresContext, canStoreInRuleTree);
michael@0 8186 if (len < 0) {
michael@0 8187 // FIXME: This is untested (by test_value_storage.html) for
michael@0 8188 // column-rule-width since it gets covered up by the border
michael@0 8189 // rounding code.
michael@0 8190 NS_ASSERTION(widthValue.IsCalcUnit(),
michael@0 8191 "parser should have rejected negative length");
michael@0 8192 len = 0;
michael@0 8193 }
michael@0 8194 column->SetColumnRuleWidth(len);
michael@0 8195 }
michael@0 8196
michael@0 8197 // column-rule-style: enum, inherit
michael@0 8198 const nsCSSValue& styleValue = *aRuleData->ValueForColumnRuleStyle();
michael@0 8199 NS_ABORT_IF_FALSE(eCSSUnit_None != styleValue.GetUnit(),
michael@0 8200 "'none' should be handled as enumerated value");
michael@0 8201 if (eCSSUnit_Enumerated == styleValue.GetUnit()) {
michael@0 8202 column->mColumnRuleStyle = styleValue.GetIntValue();
michael@0 8203 }
michael@0 8204 else if (eCSSUnit_Initial == styleValue.GetUnit() ||
michael@0 8205 eCSSUnit_Unset == styleValue.GetUnit()) {
michael@0 8206 column->mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
michael@0 8207 }
michael@0 8208 else if (eCSSUnit_Inherit == styleValue.GetUnit()) {
michael@0 8209 canStoreInRuleTree = false;
michael@0 8210 column->mColumnRuleStyle = parent->mColumnRuleStyle;
michael@0 8211 }
michael@0 8212
michael@0 8213 // column-rule-color: color, inherit
michael@0 8214 const nsCSSValue& colorValue = *aRuleData->ValueForColumnRuleColor();
michael@0 8215 if (eCSSUnit_Inherit == colorValue.GetUnit()) {
michael@0 8216 canStoreInRuleTree = false;
michael@0 8217 column->mColumnRuleColorIsForeground = false;
michael@0 8218 if (parent->mColumnRuleColorIsForeground) {
michael@0 8219 if (parentContext) {
michael@0 8220 column->mColumnRuleColor = parentContext->StyleColor()->mColor;
michael@0 8221 } else {
michael@0 8222 nsStyleColor defaultColumnRuleColor(mPresContext);
michael@0 8223 column->mColumnRuleColor = defaultColumnRuleColor.mColor;
michael@0 8224 }
michael@0 8225 } else {
michael@0 8226 column->mColumnRuleColor = parent->mColumnRuleColor;
michael@0 8227 }
michael@0 8228 }
michael@0 8229 else if (eCSSUnit_Initial == colorValue.GetUnit() ||
michael@0 8230 eCSSUnit_Unset == colorValue.GetUnit() ||
michael@0 8231 eCSSUnit_Enumerated == colorValue.GetUnit()) {
michael@0 8232 column->mColumnRuleColorIsForeground = true;
michael@0 8233 }
michael@0 8234 else if (SetColor(colorValue, 0, mPresContext, aContext,
michael@0 8235 column->mColumnRuleColor, canStoreInRuleTree)) {
michael@0 8236 column->mColumnRuleColorIsForeground = false;
michael@0 8237 }
michael@0 8238
michael@0 8239 // column-fill: enum
michael@0 8240 SetDiscrete(*aRuleData->ValueForColumnFill(),
michael@0 8241 column->mColumnFill, canStoreInRuleTree,
michael@0 8242 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 8243 parent->mColumnFill,
michael@0 8244 NS_STYLE_COLUMN_FILL_BALANCE,
michael@0 8245 0, 0, 0, 0);
michael@0 8246
michael@0 8247 COMPUTE_END_RESET(Column, column)
michael@0 8248 }
michael@0 8249
michael@0 8250 static void
michael@0 8251 SetSVGPaint(const nsCSSValue& aValue, const nsStyleSVGPaint& parentPaint,
michael@0 8252 nsPresContext* aPresContext, nsStyleContext *aContext,
michael@0 8253 nsStyleSVGPaint& aResult, nsStyleSVGPaintType aInitialPaintType,
michael@0 8254 bool& aCanStoreInRuleTree)
michael@0 8255 {
michael@0 8256 nscolor color;
michael@0 8257
michael@0 8258 if (aValue.GetUnit() == eCSSUnit_Inherit ||
michael@0 8259 aValue.GetUnit() == eCSSUnit_Unset) {
michael@0 8260 aResult = parentPaint;
michael@0 8261 aCanStoreInRuleTree = false;
michael@0 8262 } else if (aValue.GetUnit() == eCSSUnit_None) {
michael@0 8263 aResult.SetType(eStyleSVGPaintType_None);
michael@0 8264 } else if (aValue.GetUnit() == eCSSUnit_Initial) {
michael@0 8265 aResult.SetType(aInitialPaintType);
michael@0 8266 aResult.mPaint.mColor = NS_RGB(0, 0, 0);
michael@0 8267 aResult.mFallbackColor = NS_RGB(0, 0, 0);
michael@0 8268 } else if (SetColor(aValue, NS_RGB(0, 0, 0), aPresContext, aContext,
michael@0 8269 color, aCanStoreInRuleTree)) {
michael@0 8270 aResult.SetType(eStyleSVGPaintType_Color);
michael@0 8271 aResult.mPaint.mColor = color;
michael@0 8272 } else if (aValue.GetUnit() == eCSSUnit_Pair) {
michael@0 8273 const nsCSSValuePair& pair = aValue.GetPairValue();
michael@0 8274
michael@0 8275 if (pair.mXValue.GetUnit() == eCSSUnit_URL) {
michael@0 8276 aResult.SetType(eStyleSVGPaintType_Server);
michael@0 8277 aResult.mPaint.mPaintServer = pair.mXValue.GetURLValue();
michael@0 8278 NS_IF_ADDREF(aResult.mPaint.mPaintServer);
michael@0 8279 } else if (pair.mXValue.GetUnit() == eCSSUnit_Enumerated) {
michael@0 8280
michael@0 8281 switch (pair.mXValue.GetIntValue()) {
michael@0 8282 case NS_COLOR_CONTEXT_FILL:
michael@0 8283 aResult.SetType(eStyleSVGPaintType_ContextFill);
michael@0 8284 break;
michael@0 8285 case NS_COLOR_CONTEXT_STROKE:
michael@0 8286 aResult.SetType(eStyleSVGPaintType_ContextStroke);
michael@0 8287 break;
michael@0 8288 default:
michael@0 8289 NS_NOTREACHED("unknown keyword as paint server value");
michael@0 8290 }
michael@0 8291
michael@0 8292 } else {
michael@0 8293 NS_NOTREACHED("malformed paint server value");
michael@0 8294 }
michael@0 8295
michael@0 8296 if (pair.mYValue.GetUnit() == eCSSUnit_None) {
michael@0 8297 aResult.mFallbackColor = NS_RGBA(0, 0, 0, 0);
michael@0 8298 } else {
michael@0 8299 NS_ABORT_IF_FALSE(pair.mYValue.GetUnit() != eCSSUnit_Inherit,
michael@0 8300 "cannot inherit fallback colour");
michael@0 8301 SetColor(pair.mYValue, NS_RGB(0, 0, 0), aPresContext, aContext,
michael@0 8302 aResult.mFallbackColor, aCanStoreInRuleTree);
michael@0 8303 }
michael@0 8304 } else {
michael@0 8305 NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Null,
michael@0 8306 "malformed paint server value");
michael@0 8307 }
michael@0 8308 }
michael@0 8309
michael@0 8310 static void
michael@0 8311 SetSVGOpacity(const nsCSSValue& aValue,
michael@0 8312 float& aOpacityField, nsStyleSVGOpacitySource& aOpacityTypeField,
michael@0 8313 bool& aCanStoreInRuleTree,
michael@0 8314 float aParentOpacity, nsStyleSVGOpacitySource aParentOpacityType)
michael@0 8315 {
michael@0 8316 if (eCSSUnit_Enumerated == aValue.GetUnit()) {
michael@0 8317 switch (aValue.GetIntValue()) {
michael@0 8318 case NS_STYLE_CONTEXT_FILL_OPACITY:
michael@0 8319 aOpacityTypeField = eStyleSVGOpacitySource_ContextFillOpacity;
michael@0 8320 break;
michael@0 8321 case NS_STYLE_CONTEXT_STROKE_OPACITY:
michael@0 8322 aOpacityTypeField = eStyleSVGOpacitySource_ContextStrokeOpacity;
michael@0 8323 break;
michael@0 8324 default:
michael@0 8325 NS_NOTREACHED("SetSVGOpacity: Unknown keyword");
michael@0 8326 }
michael@0 8327 // Fall back on fully opaque
michael@0 8328 aOpacityField = 1.0f;
michael@0 8329 } else if (eCSSUnit_Inherit == aValue.GetUnit() ||
michael@0 8330 eCSSUnit_Unset == aValue.GetUnit()) {
michael@0 8331 aCanStoreInRuleTree = false;
michael@0 8332 aOpacityField = aParentOpacity;
michael@0 8333 aOpacityTypeField = aParentOpacityType;
michael@0 8334 } else if (eCSSUnit_Null != aValue.GetUnit()) {
michael@0 8335 SetFactor(aValue, aOpacityField, aCanStoreInRuleTree,
michael@0 8336 aParentOpacity, 1.0f, SETFCT_OPACITY);
michael@0 8337 aOpacityTypeField = eStyleSVGOpacitySource_Normal;
michael@0 8338 }
michael@0 8339 }
michael@0 8340
michael@0 8341 const void*
michael@0 8342 nsRuleNode::ComputeSVGData(void* aStartStruct,
michael@0 8343 const nsRuleData* aRuleData,
michael@0 8344 nsStyleContext* aContext,
michael@0 8345 nsRuleNode* aHighestNode,
michael@0 8346 const RuleDetail aRuleDetail,
michael@0 8347 const bool aCanStoreInRuleTree)
michael@0 8348 {
michael@0 8349 COMPUTE_START_INHERITED(SVG, (), svg, parentSVG)
michael@0 8350
michael@0 8351 // clip-rule: enum, inherit, initial
michael@0 8352 SetDiscrete(*aRuleData->ValueForClipRule(),
michael@0 8353 svg->mClipRule, canStoreInRuleTree,
michael@0 8354 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 8355 parentSVG->mClipRule,
michael@0 8356 NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
michael@0 8357
michael@0 8358 // color-interpolation: enum, inherit, initial
michael@0 8359 SetDiscrete(*aRuleData->ValueForColorInterpolation(),
michael@0 8360 svg->mColorInterpolation, canStoreInRuleTree,
michael@0 8361 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 8362 parentSVG->mColorInterpolation,
michael@0 8363 NS_STYLE_COLOR_INTERPOLATION_SRGB, 0, 0, 0, 0);
michael@0 8364
michael@0 8365 // color-interpolation-filters: enum, inherit, initial
michael@0 8366 SetDiscrete(*aRuleData->ValueForColorInterpolationFilters(),
michael@0 8367 svg->mColorInterpolationFilters, canStoreInRuleTree,
michael@0 8368 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 8369 parentSVG->mColorInterpolationFilters,
michael@0 8370 NS_STYLE_COLOR_INTERPOLATION_LINEARRGB, 0, 0, 0, 0);
michael@0 8371
michael@0 8372 // fill:
michael@0 8373 SetSVGPaint(*aRuleData->ValueForFill(),
michael@0 8374 parentSVG->mFill, mPresContext, aContext,
michael@0 8375 svg->mFill, eStyleSVGPaintType_Color, canStoreInRuleTree);
michael@0 8376
michael@0 8377 // fill-opacity: factor, inherit, initial,
michael@0 8378 // context-fill-opacity, context-stroke-opacity
michael@0 8379 nsStyleSVGOpacitySource contextFillOpacity = svg->mFillOpacitySource;
michael@0 8380 SetSVGOpacity(*aRuleData->ValueForFillOpacity(),
michael@0 8381 svg->mFillOpacity, contextFillOpacity, canStoreInRuleTree,
michael@0 8382 parentSVG->mFillOpacity, parentSVG->mFillOpacitySource);
michael@0 8383 svg->mFillOpacitySource = contextFillOpacity;
michael@0 8384
michael@0 8385 // fill-rule: enum, inherit, initial
michael@0 8386 SetDiscrete(*aRuleData->ValueForFillRule(),
michael@0 8387 svg->mFillRule, canStoreInRuleTree,
michael@0 8388 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 8389 parentSVG->mFillRule,
michael@0 8390 NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
michael@0 8391
michael@0 8392 // image-rendering: enum, inherit
michael@0 8393 SetDiscrete(*aRuleData->ValueForImageRendering(),
michael@0 8394 svg->mImageRendering, canStoreInRuleTree,
michael@0 8395 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 8396 parentSVG->mImageRendering,
michael@0 8397 NS_STYLE_IMAGE_RENDERING_AUTO, 0, 0, 0, 0);
michael@0 8398
michael@0 8399 // marker-end: url, none, inherit
michael@0 8400 const nsCSSValue* markerEndValue = aRuleData->ValueForMarkerEnd();
michael@0 8401 if (eCSSUnit_URL == markerEndValue->GetUnit()) {
michael@0 8402 svg->mMarkerEnd = markerEndValue->GetURLValue();
michael@0 8403 } else if (eCSSUnit_None == markerEndValue->GetUnit() ||
michael@0 8404 eCSSUnit_Initial == markerEndValue->GetUnit()) {
michael@0 8405 svg->mMarkerEnd = nullptr;
michael@0 8406 } else if (eCSSUnit_Inherit == markerEndValue->GetUnit() ||
michael@0 8407 eCSSUnit_Unset == markerEndValue->GetUnit()) {
michael@0 8408 canStoreInRuleTree = false;
michael@0 8409 svg->mMarkerEnd = parentSVG->mMarkerEnd;
michael@0 8410 }
michael@0 8411
michael@0 8412 // marker-mid: url, none, inherit
michael@0 8413 const nsCSSValue* markerMidValue = aRuleData->ValueForMarkerMid();
michael@0 8414 if (eCSSUnit_URL == markerMidValue->GetUnit()) {
michael@0 8415 svg->mMarkerMid = markerMidValue->GetURLValue();
michael@0 8416 } else if (eCSSUnit_None == markerMidValue->GetUnit() ||
michael@0 8417 eCSSUnit_Initial == markerMidValue->GetUnit()) {
michael@0 8418 svg->mMarkerMid = nullptr;
michael@0 8419 } else if (eCSSUnit_Inherit == markerMidValue->GetUnit() ||
michael@0 8420 eCSSUnit_Unset == markerMidValue->GetUnit()) {
michael@0 8421 canStoreInRuleTree = false;
michael@0 8422 svg->mMarkerMid = parentSVG->mMarkerMid;
michael@0 8423 }
michael@0 8424
michael@0 8425 // marker-start: url, none, inherit
michael@0 8426 const nsCSSValue* markerStartValue = aRuleData->ValueForMarkerStart();
michael@0 8427 if (eCSSUnit_URL == markerStartValue->GetUnit()) {
michael@0 8428 svg->mMarkerStart = markerStartValue->GetURLValue();
michael@0 8429 } else if (eCSSUnit_None == markerStartValue->GetUnit() ||
michael@0 8430 eCSSUnit_Initial == markerStartValue->GetUnit()) {
michael@0 8431 svg->mMarkerStart = nullptr;
michael@0 8432 } else if (eCSSUnit_Inherit == markerStartValue->GetUnit() ||
michael@0 8433 eCSSUnit_Unset == markerStartValue->GetUnit()) {
michael@0 8434 canStoreInRuleTree = false;
michael@0 8435 svg->mMarkerStart = parentSVG->mMarkerStart;
michael@0 8436 }
michael@0 8437
michael@0 8438 // paint-order: enum (bit field), inherit, initial
michael@0 8439 const nsCSSValue* paintOrderValue = aRuleData->ValueForPaintOrder();
michael@0 8440 switch (paintOrderValue->GetUnit()) {
michael@0 8441 case eCSSUnit_Null:
michael@0 8442 break;
michael@0 8443
michael@0 8444 case eCSSUnit_Enumerated:
michael@0 8445 static_assert
michael@0 8446 (NS_STYLE_PAINT_ORDER_BITWIDTH * NS_STYLE_PAINT_ORDER_LAST_VALUE <= 8,
michael@0 8447 "SVGStyleStruct::mPaintOrder not big enough");
michael@0 8448 svg->mPaintOrder = static_cast<uint8_t>(paintOrderValue->GetIntValue());
michael@0 8449 break;
michael@0 8450
michael@0 8451 case eCSSUnit_Inherit:
michael@0 8452 case eCSSUnit_Unset:
michael@0 8453 canStoreInRuleTree = false;
michael@0 8454 svg->mPaintOrder = parentSVG->mPaintOrder;
michael@0 8455 break;
michael@0 8456
michael@0 8457 case eCSSUnit_Initial:
michael@0 8458 svg->mPaintOrder = NS_STYLE_PAINT_ORDER_NORMAL;
michael@0 8459 break;
michael@0 8460
michael@0 8461 default:
michael@0 8462 NS_NOTREACHED("unexpected unit");
michael@0 8463 }
michael@0 8464
michael@0 8465 // shape-rendering: enum, inherit
michael@0 8466 SetDiscrete(*aRuleData->ValueForShapeRendering(),
michael@0 8467 svg->mShapeRendering, canStoreInRuleTree,
michael@0 8468 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 8469 parentSVG->mShapeRendering,
michael@0 8470 NS_STYLE_SHAPE_RENDERING_AUTO, 0, 0, 0, 0);
michael@0 8471
michael@0 8472 // stroke:
michael@0 8473 SetSVGPaint(*aRuleData->ValueForStroke(),
michael@0 8474 parentSVG->mStroke, mPresContext, aContext,
michael@0 8475 svg->mStroke, eStyleSVGPaintType_None, canStoreInRuleTree);
michael@0 8476
michael@0 8477 // stroke-dasharray: <dasharray>, none, inherit, context-value
michael@0 8478 const nsCSSValue* strokeDasharrayValue = aRuleData->ValueForStrokeDasharray();
michael@0 8479 switch (strokeDasharrayValue->GetUnit()) {
michael@0 8480 case eCSSUnit_Null:
michael@0 8481 break;
michael@0 8482
michael@0 8483 case eCSSUnit_Inherit:
michael@0 8484 case eCSSUnit_Unset:
michael@0 8485 canStoreInRuleTree = false;
michael@0 8486 svg->mStrokeDasharrayFromObject = parentSVG->mStrokeDasharrayFromObject;
michael@0 8487 // only do the copy if weren't already set up by the copy constructor
michael@0 8488 // FIXME Bug 389408: This is broken when aStartStruct is non-null!
michael@0 8489 if (!svg->mStrokeDasharray) {
michael@0 8490 svg->mStrokeDasharrayLength = parentSVG->mStrokeDasharrayLength;
michael@0 8491 if (svg->mStrokeDasharrayLength) {
michael@0 8492 svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
michael@0 8493 if (svg->mStrokeDasharray)
michael@0 8494 memcpy(svg->mStrokeDasharray,
michael@0 8495 parentSVG->mStrokeDasharray,
michael@0 8496 svg->mStrokeDasharrayLength * sizeof(nsStyleCoord));
michael@0 8497 else
michael@0 8498 svg->mStrokeDasharrayLength = 0;
michael@0 8499 }
michael@0 8500 }
michael@0 8501 break;
michael@0 8502
michael@0 8503 case eCSSUnit_Enumerated:
michael@0 8504 NS_ABORT_IF_FALSE(strokeDasharrayValue->GetIntValue() ==
michael@0 8505 NS_STYLE_STROKE_PROP_CONTEXT_VALUE,
michael@0 8506 "Unknown keyword for stroke-dasharray");
michael@0 8507 svg->mStrokeDasharrayFromObject = true;
michael@0 8508 delete [] svg->mStrokeDasharray;
michael@0 8509 svg->mStrokeDasharray = nullptr;
michael@0 8510 svg->mStrokeDasharrayLength = 0;
michael@0 8511 break;
michael@0 8512
michael@0 8513 case eCSSUnit_Initial:
michael@0 8514 case eCSSUnit_None:
michael@0 8515 svg->mStrokeDasharrayFromObject = false;
michael@0 8516 delete [] svg->mStrokeDasharray;
michael@0 8517 svg->mStrokeDasharray = nullptr;
michael@0 8518 svg->mStrokeDasharrayLength = 0;
michael@0 8519 break;
michael@0 8520
michael@0 8521 case eCSSUnit_List:
michael@0 8522 case eCSSUnit_ListDep: {
michael@0 8523 svg->mStrokeDasharrayFromObject = false;
michael@0 8524 delete [] svg->mStrokeDasharray;
michael@0 8525 svg->mStrokeDasharray = nullptr;
michael@0 8526 svg->mStrokeDasharrayLength = 0;
michael@0 8527
michael@0 8528 // count number of values
michael@0 8529 const nsCSSValueList *value = strokeDasharrayValue->GetListValue();
michael@0 8530 svg->mStrokeDasharrayLength = ListLength(value);
michael@0 8531
michael@0 8532 NS_ASSERTION(svg->mStrokeDasharrayLength != 0, "no dasharray items");
michael@0 8533
michael@0 8534 svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
michael@0 8535
michael@0 8536 if (svg->mStrokeDasharray) {
michael@0 8537 uint32_t i = 0;
michael@0 8538 while (nullptr != value) {
michael@0 8539 SetCoord(value->mValue,
michael@0 8540 svg->mStrokeDasharray[i++], nsStyleCoord(),
michael@0 8541 SETCOORD_LP | SETCOORD_FACTOR,
michael@0 8542 aContext, mPresContext, canStoreInRuleTree);
michael@0 8543 value = value->mNext;
michael@0 8544 }
michael@0 8545 } else {
michael@0 8546 svg->mStrokeDasharrayLength = 0;
michael@0 8547 }
michael@0 8548 break;
michael@0 8549 }
michael@0 8550
michael@0 8551 default:
michael@0 8552 NS_ABORT_IF_FALSE(false, "unrecognized dasharray unit");
michael@0 8553 }
michael@0 8554
michael@0 8555 // stroke-dashoffset: <dashoffset>, inherit
michael@0 8556 const nsCSSValue *strokeDashoffsetValue =
michael@0 8557 aRuleData->ValueForStrokeDashoffset();
michael@0 8558 svg->mStrokeDashoffsetFromObject =
michael@0 8559 strokeDashoffsetValue->GetUnit() == eCSSUnit_Enumerated &&
michael@0 8560 strokeDashoffsetValue->GetIntValue() == NS_STYLE_STROKE_PROP_CONTEXT_VALUE;
michael@0 8561 if (svg->mStrokeDashoffsetFromObject) {
michael@0 8562 svg->mStrokeDashoffset.SetCoordValue(0);
michael@0 8563 } else {
michael@0 8564 SetCoord(*aRuleData->ValueForStrokeDashoffset(),
michael@0 8565 svg->mStrokeDashoffset, parentSVG->mStrokeDashoffset,
michael@0 8566 SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_INITIAL_ZERO |
michael@0 8567 SETCOORD_UNSET_INHERIT,
michael@0 8568 aContext, mPresContext, canStoreInRuleTree);
michael@0 8569 }
michael@0 8570
michael@0 8571 // stroke-linecap: enum, inherit, initial
michael@0 8572 SetDiscrete(*aRuleData->ValueForStrokeLinecap(),
michael@0 8573 svg->mStrokeLinecap, canStoreInRuleTree,
michael@0 8574 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 8575 parentSVG->mStrokeLinecap,
michael@0 8576 NS_STYLE_STROKE_LINECAP_BUTT, 0, 0, 0, 0);
michael@0 8577
michael@0 8578 // stroke-linejoin: enum, inherit, initial
michael@0 8579 SetDiscrete(*aRuleData->ValueForStrokeLinejoin(),
michael@0 8580 svg->mStrokeLinejoin, canStoreInRuleTree,
michael@0 8581 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 8582 parentSVG->mStrokeLinejoin,
michael@0 8583 NS_STYLE_STROKE_LINEJOIN_MITER, 0, 0, 0, 0);
michael@0 8584
michael@0 8585 // stroke-miterlimit: <miterlimit>, inherit
michael@0 8586 SetFactor(*aRuleData->ValueForStrokeMiterlimit(),
michael@0 8587 svg->mStrokeMiterlimit,
michael@0 8588 canStoreInRuleTree,
michael@0 8589 parentSVG->mStrokeMiterlimit, 4.0f,
michael@0 8590 SETFCT_UNSET_INHERIT);
michael@0 8591
michael@0 8592 // stroke-opacity:
michael@0 8593 nsStyleSVGOpacitySource contextStrokeOpacity = svg->mStrokeOpacitySource;
michael@0 8594 SetSVGOpacity(*aRuleData->ValueForStrokeOpacity(),
michael@0 8595 svg->mStrokeOpacity, contextStrokeOpacity, canStoreInRuleTree,
michael@0 8596 parentSVG->mStrokeOpacity, parentSVG->mStrokeOpacitySource);
michael@0 8597 svg->mStrokeOpacitySource = contextStrokeOpacity;
michael@0 8598
michael@0 8599 // stroke-width:
michael@0 8600 const nsCSSValue* strokeWidthValue = aRuleData->ValueForStrokeWidth();
michael@0 8601 switch (strokeWidthValue->GetUnit()) {
michael@0 8602 case eCSSUnit_Enumerated:
michael@0 8603 NS_ABORT_IF_FALSE(strokeWidthValue->GetIntValue() ==
michael@0 8604 NS_STYLE_STROKE_PROP_CONTEXT_VALUE,
michael@0 8605 "Unrecognized keyword for stroke-width");
michael@0 8606 svg->mStrokeWidthFromObject = true;
michael@0 8607 svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
michael@0 8608 break;
michael@0 8609
michael@0 8610 case eCSSUnit_Initial:
michael@0 8611 svg->mStrokeWidthFromObject = false;
michael@0 8612 svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
michael@0 8613 break;
michael@0 8614
michael@0 8615 default:
michael@0 8616 svg->mStrokeWidthFromObject = false;
michael@0 8617 SetCoord(*strokeWidthValue,
michael@0 8618 svg->mStrokeWidth, parentSVG->mStrokeWidth,
michael@0 8619 SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_UNSET_INHERIT,
michael@0 8620 aContext, mPresContext, canStoreInRuleTree);
michael@0 8621 }
michael@0 8622
michael@0 8623 // text-anchor: enum, inherit, initial
michael@0 8624 SetDiscrete(*aRuleData->ValueForTextAnchor(),
michael@0 8625 svg->mTextAnchor, canStoreInRuleTree,
michael@0 8626 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 8627 parentSVG->mTextAnchor,
michael@0 8628 NS_STYLE_TEXT_ANCHOR_START, 0, 0, 0, 0);
michael@0 8629
michael@0 8630 // text-rendering: enum, inherit, initial
michael@0 8631 SetDiscrete(*aRuleData->ValueForTextRendering(),
michael@0 8632 svg->mTextRendering, canStoreInRuleTree,
michael@0 8633 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
michael@0 8634 parentSVG->mTextRendering,
michael@0 8635 NS_STYLE_TEXT_RENDERING_AUTO, 0, 0, 0, 0);
michael@0 8636
michael@0 8637 COMPUTE_END_INHERITED(SVG, svg)
michael@0 8638 }
michael@0 8639
michael@0 8640 // Returns true if the nsStyleFilter was successfully set using the nsCSSValue.
michael@0 8641 bool
michael@0 8642 nsRuleNode::SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter,
michael@0 8643 const nsCSSValue& aValue,
michael@0 8644 nsStyleContext* aStyleContext,
michael@0 8645 nsPresContext* aPresContext,
michael@0 8646 bool& aCanStoreInRuleTree)
michael@0 8647 {
michael@0 8648 nsCSSUnit unit = aValue.GetUnit();
michael@0 8649 if (unit == eCSSUnit_URL) {
michael@0 8650 nsIURI* url = aValue.GetURLValue();
michael@0 8651 if (!url)
michael@0 8652 return false;
michael@0 8653 aStyleFilter->SetURL(url);
michael@0 8654 return true;
michael@0 8655 }
michael@0 8656
michael@0 8657 NS_ABORT_IF_FALSE(unit == eCSSUnit_Function, "expected a filter function");
michael@0 8658
michael@0 8659 nsCSSValue::Array* filterFunction = aValue.GetArrayValue();
michael@0 8660 nsCSSKeyword functionName =
michael@0 8661 (nsCSSKeyword)filterFunction->Item(0).GetIntValue();
michael@0 8662
michael@0 8663 int32_t type;
michael@0 8664 DebugOnly<bool> foundKeyword =
michael@0 8665 nsCSSProps::FindKeyword(functionName,
michael@0 8666 nsCSSProps::kFilterFunctionKTable,
michael@0 8667 type);
michael@0 8668 NS_ABORT_IF_FALSE(foundKeyword, "unknown filter type");
michael@0 8669 if (type == NS_STYLE_FILTER_DROP_SHADOW) {
michael@0 8670 nsRefPtr<nsCSSShadowArray> shadowArray = GetShadowData(
michael@0 8671 filterFunction->Item(1).GetListValue(),
michael@0 8672 aStyleContext,
michael@0 8673 false,
michael@0 8674 aCanStoreInRuleTree);
michael@0 8675 aStyleFilter->SetDropShadow(shadowArray);
michael@0 8676 return true;
michael@0 8677 }
michael@0 8678
michael@0 8679 int32_t mask = SETCOORD_PERCENT | SETCOORD_FACTOR;
michael@0 8680 if (type == NS_STYLE_FILTER_BLUR) {
michael@0 8681 mask = SETCOORD_LENGTH | SETCOORD_STORE_CALC;
michael@0 8682 } else if (type == NS_STYLE_FILTER_HUE_ROTATE) {
michael@0 8683 mask = SETCOORD_ANGLE;
michael@0 8684 }
michael@0 8685
michael@0 8686 NS_ABORT_IF_FALSE(filterFunction->Count() == 2,
michael@0 8687 "all filter functions should have "
michael@0 8688 "exactly one argument");
michael@0 8689
michael@0 8690 nsCSSValue& arg = filterFunction->Item(1);
michael@0 8691 nsStyleCoord filterParameter;
michael@0 8692 DebugOnly<bool> didSetCoord = SetCoord(arg, filterParameter,
michael@0 8693 nsStyleCoord(), mask,
michael@0 8694 aStyleContext, aPresContext,
michael@0 8695 aCanStoreInRuleTree);
michael@0 8696 aStyleFilter->SetFilterParameter(filterParameter, type);
michael@0 8697 NS_ABORT_IF_FALSE(didSetCoord, "unexpected unit");
michael@0 8698 return true;
michael@0 8699 }
michael@0 8700
michael@0 8701 const void*
michael@0 8702 nsRuleNode::ComputeSVGResetData(void* aStartStruct,
michael@0 8703 const nsRuleData* aRuleData,
michael@0 8704 nsStyleContext* aContext,
michael@0 8705 nsRuleNode* aHighestNode,
michael@0 8706 const RuleDetail aRuleDetail,
michael@0 8707 const bool aCanStoreInRuleTree)
michael@0 8708 {
michael@0 8709 COMPUTE_START_RESET(SVGReset, (), svgReset, parentSVGReset)
michael@0 8710
michael@0 8711 // stop-color:
michael@0 8712 const nsCSSValue* stopColorValue = aRuleData->ValueForStopColor();
michael@0 8713 if (eCSSUnit_Initial == stopColorValue->GetUnit() ||
michael@0 8714 eCSSUnit_Unset == stopColorValue->GetUnit()) {
michael@0 8715 svgReset->mStopColor = NS_RGB(0, 0, 0);
michael@0 8716 } else {
michael@0 8717 SetColor(*stopColorValue, parentSVGReset->mStopColor,
michael@0 8718 mPresContext, aContext, svgReset->mStopColor, canStoreInRuleTree);
michael@0 8719 }
michael@0 8720
michael@0 8721 // flood-color:
michael@0 8722 const nsCSSValue* floodColorValue = aRuleData->ValueForFloodColor();
michael@0 8723 if (eCSSUnit_Initial == floodColorValue->GetUnit() ||
michael@0 8724 eCSSUnit_Unset == floodColorValue->GetUnit()) {
michael@0 8725 svgReset->mFloodColor = NS_RGB(0, 0, 0);
michael@0 8726 } else {
michael@0 8727 SetColor(*floodColorValue, parentSVGReset->mFloodColor,
michael@0 8728 mPresContext, aContext, svgReset->mFloodColor, canStoreInRuleTree);
michael@0 8729 }
michael@0 8730
michael@0 8731 // lighting-color:
michael@0 8732 const nsCSSValue* lightingColorValue = aRuleData->ValueForLightingColor();
michael@0 8733 if (eCSSUnit_Initial == lightingColorValue->GetUnit() ||
michael@0 8734 eCSSUnit_Unset == lightingColorValue->GetUnit()) {
michael@0 8735 svgReset->mLightingColor = NS_RGB(255, 255, 255);
michael@0 8736 } else {
michael@0 8737 SetColor(*lightingColorValue, parentSVGReset->mLightingColor,
michael@0 8738 mPresContext, aContext, svgReset->mLightingColor,
michael@0 8739 canStoreInRuleTree);
michael@0 8740 }
michael@0 8741
michael@0 8742 // clip-path: url, none, inherit
michael@0 8743 const nsCSSValue* clipPathValue = aRuleData->ValueForClipPath();
michael@0 8744 if (eCSSUnit_URL == clipPathValue->GetUnit()) {
michael@0 8745 svgReset->mClipPath = clipPathValue->GetURLValue();
michael@0 8746 } else if (eCSSUnit_None == clipPathValue->GetUnit() ||
michael@0 8747 eCSSUnit_Initial == clipPathValue->GetUnit() ||
michael@0 8748 eCSSUnit_Unset == clipPathValue->GetUnit()) {
michael@0 8749 svgReset->mClipPath = nullptr;
michael@0 8750 } else if (eCSSUnit_Inherit == clipPathValue->GetUnit()) {
michael@0 8751 canStoreInRuleTree = false;
michael@0 8752 svgReset->mClipPath = parentSVGReset->mClipPath;
michael@0 8753 }
michael@0 8754
michael@0 8755 // stop-opacity:
michael@0 8756 SetFactor(*aRuleData->ValueForStopOpacity(),
michael@0 8757 svgReset->mStopOpacity, canStoreInRuleTree,
michael@0 8758 parentSVGReset->mStopOpacity, 1.0f,
michael@0 8759 SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
michael@0 8760
michael@0 8761 // flood-opacity:
michael@0 8762 SetFactor(*aRuleData->ValueForFloodOpacity(),
michael@0 8763 svgReset->mFloodOpacity, canStoreInRuleTree,
michael@0 8764 parentSVGReset->mFloodOpacity, 1.0f,
michael@0 8765 SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
michael@0 8766
michael@0 8767 // dominant-baseline: enum, inherit, initial
michael@0 8768 SetDiscrete(*aRuleData->ValueForDominantBaseline(),
michael@0 8769 svgReset->mDominantBaseline,
michael@0 8770 canStoreInRuleTree,
michael@0 8771 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 8772 parentSVGReset->mDominantBaseline,
michael@0 8773 NS_STYLE_DOMINANT_BASELINE_AUTO, 0, 0, 0, 0);
michael@0 8774
michael@0 8775 // vector-effect: enum, inherit, initial
michael@0 8776 SetDiscrete(*aRuleData->ValueForVectorEffect(),
michael@0 8777 svgReset->mVectorEffect,
michael@0 8778 canStoreInRuleTree,
michael@0 8779 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 8780 parentSVGReset->mVectorEffect,
michael@0 8781 NS_STYLE_VECTOR_EFFECT_NONE, 0, 0, 0, 0);
michael@0 8782
michael@0 8783 // filter: url, none, inherit
michael@0 8784 const nsCSSValue* filterValue = aRuleData->ValueForFilter();
michael@0 8785 switch (filterValue->GetUnit()) {
michael@0 8786 case eCSSUnit_Null:
michael@0 8787 break;
michael@0 8788 case eCSSUnit_None:
michael@0 8789 case eCSSUnit_Initial:
michael@0 8790 case eCSSUnit_Unset:
michael@0 8791 svgReset->mFilters.Clear();
michael@0 8792 break;
michael@0 8793 case eCSSUnit_Inherit:
michael@0 8794 canStoreInRuleTree = false;
michael@0 8795 svgReset->mFilters = parentSVGReset->mFilters;
michael@0 8796 break;
michael@0 8797 case eCSSUnit_List:
michael@0 8798 case eCSSUnit_ListDep: {
michael@0 8799 svgReset->mFilters.Clear();
michael@0 8800 const nsCSSValueList* cur = filterValue->GetListValue();
michael@0 8801 while (cur) {
michael@0 8802 nsStyleFilter styleFilter;
michael@0 8803 if (!SetStyleFilterToCSSValue(&styleFilter, cur->mValue, aContext,
michael@0 8804 mPresContext, canStoreInRuleTree)) {
michael@0 8805 svgReset->mFilters.Clear();
michael@0 8806 break;
michael@0 8807 }
michael@0 8808 NS_ABORT_IF_FALSE(styleFilter.GetType() != NS_STYLE_FILTER_NONE,
michael@0 8809 "filter should be set");
michael@0 8810 svgReset->mFilters.AppendElement(styleFilter);
michael@0 8811 cur = cur->mNext;
michael@0 8812 }
michael@0 8813 break;
michael@0 8814 }
michael@0 8815 default:
michael@0 8816 NS_NOTREACHED("unexpected unit");
michael@0 8817 }
michael@0 8818
michael@0 8819 // mask: url, none, inherit
michael@0 8820 const nsCSSValue* maskValue = aRuleData->ValueForMask();
michael@0 8821 if (eCSSUnit_URL == maskValue->GetUnit()) {
michael@0 8822 svgReset->mMask = maskValue->GetURLValue();
michael@0 8823 } else if (eCSSUnit_None == maskValue->GetUnit() ||
michael@0 8824 eCSSUnit_Initial == maskValue->GetUnit() ||
michael@0 8825 eCSSUnit_Unset == maskValue->GetUnit()) {
michael@0 8826 svgReset->mMask = nullptr;
michael@0 8827 } else if (eCSSUnit_Inherit == maskValue->GetUnit()) {
michael@0 8828 canStoreInRuleTree = false;
michael@0 8829 svgReset->mMask = parentSVGReset->mMask;
michael@0 8830 }
michael@0 8831
michael@0 8832 // mask-type: enum, inherit, initial
michael@0 8833 SetDiscrete(*aRuleData->ValueForMaskType(),
michael@0 8834 svgReset->mMaskType,
michael@0 8835 canStoreInRuleTree,
michael@0 8836 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
michael@0 8837 parentSVGReset->mMaskType,
michael@0 8838 NS_STYLE_MASK_TYPE_LUMINANCE, 0, 0, 0, 0);
michael@0 8839
michael@0 8840 COMPUTE_END_RESET(SVGReset, svgReset)
michael@0 8841 }
michael@0 8842
michael@0 8843 const void*
michael@0 8844 nsRuleNode::ComputeVariablesData(void* aStartStruct,
michael@0 8845 const nsRuleData* aRuleData,
michael@0 8846 nsStyleContext* aContext,
michael@0 8847 nsRuleNode* aHighestNode,
michael@0 8848 const RuleDetail aRuleDetail,
michael@0 8849 const bool aCanStoreInRuleTree)
michael@0 8850 {
michael@0 8851 COMPUTE_START_INHERITED(Variables, (), variables, parentVariables)
michael@0 8852
michael@0 8853 MOZ_ASSERT(aRuleData->mVariables,
michael@0 8854 "shouldn't be in ComputeVariablesData if there were no variable "
michael@0 8855 "declarations specified");
michael@0 8856
michael@0 8857 CSSVariableResolver resolver(&variables->mVariables);
michael@0 8858 resolver.Resolve(&parentVariables->mVariables,
michael@0 8859 aRuleData->mVariables);
michael@0 8860 canStoreInRuleTree = false;
michael@0 8861
michael@0 8862 COMPUTE_END_INHERITED(Variables, variables)
michael@0 8863 }
michael@0 8864
michael@0 8865 const void*
michael@0 8866 nsRuleNode::GetStyleData(nsStyleStructID aSID,
michael@0 8867 nsStyleContext* aContext,
michael@0 8868 bool aComputeData)
michael@0 8869 {
michael@0 8870 NS_ASSERTION(IsUsedDirectly(),
michael@0 8871 "if we ever call this on rule nodes that aren't used "
michael@0 8872 "directly, we should adjust handling of mDependentBits "
michael@0 8873 "in some way.");
michael@0 8874
michael@0 8875 const void *data;
michael@0 8876 data = mStyleData.GetStyleData(aSID);
michael@0 8877 if (MOZ_LIKELY(data != nullptr))
michael@0 8878 return data; // We have a fully specified struct. Just return it.
michael@0 8879
michael@0 8880 if (MOZ_UNLIKELY(!aComputeData))
michael@0 8881 return nullptr;
michael@0 8882
michael@0 8883 // Nothing is cached. We'll have to delve further and examine our rules.
michael@0 8884 data = WalkRuleTree(aSID, aContext);
michael@0 8885
michael@0 8886 NS_ABORT_IF_FALSE(data, "should have aborted on out-of-memory");
michael@0 8887 return data;
michael@0 8888 }
michael@0 8889
michael@0 8890 // See comments above in GetStyleData for an explanation of what the
michael@0 8891 // code below does.
michael@0 8892 #define STYLE_STRUCT(name_, checkdata_cb_) \
michael@0 8893 const nsStyle##name_* \
michael@0 8894 nsRuleNode::GetStyle##name_(nsStyleContext* aContext, bool aComputeData) \
michael@0 8895 { \
michael@0 8896 NS_ASSERTION(IsUsedDirectly(), \
michael@0 8897 "if we ever call this on rule nodes that aren't used " \
michael@0 8898 "directly, we should adjust handling of mDependentBits " \
michael@0 8899 "in some way."); \
michael@0 8900 \
michael@0 8901 const nsStyle##name_ *data; \
michael@0 8902 data = mStyleData.GetStyle##name_(); \
michael@0 8903 if (MOZ_LIKELY(data != nullptr)) \
michael@0 8904 return data; \
michael@0 8905 \
michael@0 8906 if (MOZ_UNLIKELY(!aComputeData)) \
michael@0 8907 return nullptr; \
michael@0 8908 \
michael@0 8909 data = static_cast<const nsStyle##name_ *> \
michael@0 8910 (WalkRuleTree(eStyleStruct_##name_, aContext)); \
michael@0 8911 \
michael@0 8912 NS_ABORT_IF_FALSE(data, "should have aborted on out-of-memory"); \
michael@0 8913 return data; \
michael@0 8914 }
michael@0 8915 #include "nsStyleStructList.h"
michael@0 8916 #undef STYLE_STRUCT
michael@0 8917
michael@0 8918 void
michael@0 8919 nsRuleNode::Mark()
michael@0 8920 {
michael@0 8921 for (nsRuleNode *node = this;
michael@0 8922 node && !(node->mDependentBits & NS_RULE_NODE_GC_MARK);
michael@0 8923 node = node->mParent)
michael@0 8924 node->mDependentBits |= NS_RULE_NODE_GC_MARK;
michael@0 8925 }
michael@0 8926
michael@0 8927 static PLDHashOperator
michael@0 8928 SweepRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
michael@0 8929 uint32_t number, void *arg)
michael@0 8930 {
michael@0 8931 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
michael@0 8932 if (entry->mRuleNode->Sweep())
michael@0 8933 return PL_DHASH_REMOVE; // implies NEXT, unless |ed with STOP
michael@0 8934 return PL_DHASH_NEXT;
michael@0 8935 }
michael@0 8936
michael@0 8937 bool
michael@0 8938 nsRuleNode::Sweep()
michael@0 8939 {
michael@0 8940 // If we're not marked, then we have to delete ourself.
michael@0 8941 // However, we never allow the root node to GC itself, because nsStyleSet
michael@0 8942 // wants to hold onto the root node and not worry about re-creating a
michael@0 8943 // rule walker if the root node is deleted.
michael@0 8944 if (!(mDependentBits & NS_RULE_NODE_GC_MARK) &&
michael@0 8945 // Skip this only if we're the *current* root and not an old one.
michael@0 8946 !(IsRoot() && mPresContext->StyleSet()->GetRuleTree() == this)) {
michael@0 8947 Destroy();
michael@0 8948 return true;
michael@0 8949 }
michael@0 8950
michael@0 8951 // Clear our mark, for the next time around.
michael@0 8952 mDependentBits &= ~NS_RULE_NODE_GC_MARK;
michael@0 8953
michael@0 8954 // Call sweep on the children, since some may not be marked, and
michael@0 8955 // remove any deleted children from the child lists.
michael@0 8956 if (HaveChildren()) {
michael@0 8957 uint32_t childrenDestroyed;
michael@0 8958 if (ChildrenAreHashed()) {
michael@0 8959 PLDHashTable *children = ChildrenHash();
michael@0 8960 uint32_t oldChildCount = children->entryCount;
michael@0 8961 PL_DHashTableEnumerate(children, SweepRuleNodeChildren, nullptr);
michael@0 8962 childrenDestroyed = children->entryCount - oldChildCount;
michael@0 8963 } else {
michael@0 8964 childrenDestroyed = 0;
michael@0 8965 for (nsRuleNode **children = ChildrenListPtr(); *children; ) {
michael@0 8966 nsRuleNode *next = (*children)->mNextSibling;
michael@0 8967 if ((*children)->Sweep()) {
michael@0 8968 // This rule node was destroyed, so implicitly advance by
michael@0 8969 // making *children point to the next entry.
michael@0 8970 *children = next;
michael@0 8971 ++childrenDestroyed;
michael@0 8972 } else {
michael@0 8973 // Advance.
michael@0 8974 children = &(*children)->mNextSibling;
michael@0 8975 }
michael@0 8976 }
michael@0 8977 }
michael@0 8978 mRefCnt -= childrenDestroyed;
michael@0 8979 NS_POSTCONDITION(IsRoot() || mRefCnt > 0,
michael@0 8980 "We didn't get swept, so we'd better have style contexts "
michael@0 8981 "pointing to us or to one of our descendants, which means "
michael@0 8982 "we'd better have a nonzero mRefCnt here!");
michael@0 8983 }
michael@0 8984 return false;
michael@0 8985 }
michael@0 8986
michael@0 8987 /* static */ bool
michael@0 8988 nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext,
michael@0 8989 uint32_t ruleTypeMask,
michael@0 8990 bool aAuthorColorsAllowed)
michael@0 8991 {
michael@0 8992 uint32_t inheritBits = 0;
michael@0 8993 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND)
michael@0 8994 inheritBits |= NS_STYLE_INHERIT_BIT(Background);
michael@0 8995
michael@0 8996 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER)
michael@0 8997 inheritBits |= NS_STYLE_INHERIT_BIT(Border);
michael@0 8998
michael@0 8999 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING)
michael@0 9000 inheritBits |= NS_STYLE_INHERIT_BIT(Padding);
michael@0 9001
michael@0 9002 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW)
michael@0 9003 inheritBits |= NS_STYLE_INHERIT_BIT(Text);
michael@0 9004
michael@0 9005 // properties in the SIDS, whether or not we care about them
michael@0 9006 size_t nprops = 0,
michael@0 9007 backgroundOffset, borderOffset, paddingOffset, textShadowOffset;
michael@0 9008
michael@0 9009 // We put the reset properties the start of the nsCSSValue array....
michael@0 9010
michael@0 9011 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
michael@0 9012 backgroundOffset = nprops;
michael@0 9013 nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Background);
michael@0 9014 }
michael@0 9015
michael@0 9016 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
michael@0 9017 borderOffset = nprops;
michael@0 9018 nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Border);
michael@0 9019 }
michael@0 9020
michael@0 9021 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
michael@0 9022 paddingOffset = nprops;
michael@0 9023 nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Padding);
michael@0 9024 }
michael@0 9025
michael@0 9026 // ...and the inherited properties at the end of the array.
michael@0 9027 size_t inheritedOffset = nprops;
michael@0 9028
michael@0 9029 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
michael@0 9030 textShadowOffset = nprops;
michael@0 9031 nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Text);
michael@0 9032 }
michael@0 9033
michael@0 9034 void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
michael@0 9035 AutoCSSValueArray dataArray(dataStorage, nprops);
michael@0 9036
michael@0 9037 /* We're relying on the use of |aStyleContext| not mutating it! */
michael@0 9038 nsRuleData ruleData(inheritBits, dataArray.get(),
michael@0 9039 aStyleContext->PresContext(), aStyleContext);
michael@0 9040
michael@0 9041 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
michael@0 9042 ruleData.mValueOffsets[eStyleStruct_Background] = backgroundOffset;
michael@0 9043 }
michael@0 9044
michael@0 9045 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
michael@0 9046 ruleData.mValueOffsets[eStyleStruct_Border] = borderOffset;
michael@0 9047 }
michael@0 9048
michael@0 9049 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
michael@0 9050 ruleData.mValueOffsets[eStyleStruct_Padding] = paddingOffset;
michael@0 9051 }
michael@0 9052
michael@0 9053 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
michael@0 9054 ruleData.mValueOffsets[eStyleStruct_Text] = textShadowOffset;
michael@0 9055 }
michael@0 9056
michael@0 9057 static const nsCSSProperty backgroundValues[] = {
michael@0 9058 eCSSProperty_background_color,
michael@0 9059 eCSSProperty_background_image,
michael@0 9060 };
michael@0 9061
michael@0 9062 static const nsCSSProperty borderValues[] = {
michael@0 9063 eCSSProperty_border_top_color,
michael@0 9064 eCSSProperty_border_top_style,
michael@0 9065 eCSSProperty_border_top_width,
michael@0 9066 eCSSProperty_border_right_color_value,
michael@0 9067 eCSSProperty_border_right_style_value,
michael@0 9068 eCSSProperty_border_right_width_value,
michael@0 9069 eCSSProperty_border_bottom_color,
michael@0 9070 eCSSProperty_border_bottom_style,
michael@0 9071 eCSSProperty_border_bottom_width,
michael@0 9072 eCSSProperty_border_left_color_value,
michael@0 9073 eCSSProperty_border_left_style_value,
michael@0 9074 eCSSProperty_border_left_width_value,
michael@0 9075 eCSSProperty_border_start_color_value,
michael@0 9076 eCSSProperty_border_start_style_value,
michael@0 9077 eCSSProperty_border_start_width_value,
michael@0 9078 eCSSProperty_border_end_color_value,
michael@0 9079 eCSSProperty_border_end_style_value,
michael@0 9080 eCSSProperty_border_end_width_value,
michael@0 9081 eCSSProperty_border_top_left_radius,
michael@0 9082 eCSSProperty_border_top_right_radius,
michael@0 9083 eCSSProperty_border_bottom_right_radius,
michael@0 9084 eCSSProperty_border_bottom_left_radius,
michael@0 9085 };
michael@0 9086
michael@0 9087 static const nsCSSProperty paddingValues[] = {
michael@0 9088 eCSSProperty_padding_top,
michael@0 9089 eCSSProperty_padding_right_value,
michael@0 9090 eCSSProperty_padding_bottom,
michael@0 9091 eCSSProperty_padding_left_value,
michael@0 9092 eCSSProperty_padding_start_value,
michael@0 9093 eCSSProperty_padding_end_value,
michael@0 9094 };
michael@0 9095
michael@0 9096 static const nsCSSProperty textShadowValues[] = {
michael@0 9097 eCSSProperty_text_shadow
michael@0 9098 };
michael@0 9099
michael@0 9100 // Number of properties we care about
michael@0 9101 size_t nValues = 0;
michael@0 9102
michael@0 9103 nsCSSValue* values[MOZ_ARRAY_LENGTH(backgroundValues) +
michael@0 9104 MOZ_ARRAY_LENGTH(borderValues) +
michael@0 9105 MOZ_ARRAY_LENGTH(paddingValues) +
michael@0 9106 MOZ_ARRAY_LENGTH(textShadowValues)];
michael@0 9107
michael@0 9108 nsCSSProperty properties[MOZ_ARRAY_LENGTH(backgroundValues) +
michael@0 9109 MOZ_ARRAY_LENGTH(borderValues) +
michael@0 9110 MOZ_ARRAY_LENGTH(paddingValues) +
michael@0 9111 MOZ_ARRAY_LENGTH(textShadowValues)];
michael@0 9112
michael@0 9113 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
michael@0 9114 for (uint32_t i = 0, i_end = ArrayLength(backgroundValues);
michael@0 9115 i < i_end; ++i) {
michael@0 9116 properties[nValues] = backgroundValues[i];
michael@0 9117 values[nValues++] = ruleData.ValueFor(backgroundValues[i]);
michael@0 9118 }
michael@0 9119 }
michael@0 9120
michael@0 9121 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
michael@0 9122 for (uint32_t i = 0, i_end = ArrayLength(borderValues);
michael@0 9123 i < i_end; ++i) {
michael@0 9124 properties[nValues] = borderValues[i];
michael@0 9125 values[nValues++] = ruleData.ValueFor(borderValues[i]);
michael@0 9126 }
michael@0 9127 }
michael@0 9128
michael@0 9129 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
michael@0 9130 for (uint32_t i = 0, i_end = ArrayLength(paddingValues);
michael@0 9131 i < i_end; ++i) {
michael@0 9132 properties[nValues] = paddingValues[i];
michael@0 9133 values[nValues++] = ruleData.ValueFor(paddingValues[i]);
michael@0 9134 }
michael@0 9135 }
michael@0 9136
michael@0 9137 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
michael@0 9138 for (uint32_t i = 0, i_end = ArrayLength(textShadowValues);
michael@0 9139 i < i_end; ++i) {
michael@0 9140 properties[nValues] = textShadowValues[i];
michael@0 9141 values[nValues++] = ruleData.ValueFor(textShadowValues[i]);
michael@0 9142 }
michael@0 9143 }
michael@0 9144
michael@0 9145 nsStyleContext* styleContext = aStyleContext;
michael@0 9146
michael@0 9147 // We need to be careful not to count styles covered up by user-important or
michael@0 9148 // UA-important declarations. But we do want to catch explicit inherit
michael@0 9149 // styling in those and check our parent style context to see whether we have
michael@0 9150 // user styling for those properties. Note that we don't care here about
michael@0 9151 // inheritance due to lack of a specified value, since all the properties we
michael@0 9152 // care about are reset properties.
michael@0 9153 bool haveExplicitUAInherit;
michael@0 9154 do {
michael@0 9155 haveExplicitUAInherit = false;
michael@0 9156 for (nsRuleNode* ruleNode = styleContext->RuleNode(); ruleNode;
michael@0 9157 ruleNode = ruleNode->GetParent()) {
michael@0 9158 nsIStyleRule *rule = ruleNode->GetRule();
michael@0 9159 if (rule) {
michael@0 9160 ruleData.mLevel = ruleNode->GetLevel();
michael@0 9161 ruleData.mIsImportantRule = ruleNode->IsImportantRule();
michael@0 9162
michael@0 9163 rule->MapRuleInfoInto(&ruleData);
michael@0 9164
michael@0 9165 if (ruleData.mLevel == nsStyleSet::eAgentSheet ||
michael@0 9166 ruleData.mLevel == nsStyleSet::eUserSheet) {
michael@0 9167 // This is a rule whose effect we want to ignore, so if any of
michael@0 9168 // the properties we care about were set, set them to the dummy
michael@0 9169 // value that they'll never otherwise get.
michael@0 9170 for (uint32_t i = 0; i < nValues; ++i) {
michael@0 9171 nsCSSUnit unit = values[i]->GetUnit();
michael@0 9172 if (unit != eCSSUnit_Null &&
michael@0 9173 unit != eCSSUnit_Dummy &&
michael@0 9174 unit != eCSSUnit_DummyInherit) {
michael@0 9175 if (unit == eCSSUnit_Inherit ||
michael@0 9176 (i >= inheritedOffset && unit == eCSSUnit_Unset)) {
michael@0 9177 haveExplicitUAInherit = true;
michael@0 9178 values[i]->SetDummyInheritValue();
michael@0 9179 } else {
michael@0 9180 values[i]->SetDummyValue();
michael@0 9181 }
michael@0 9182 }
michael@0 9183 }
michael@0 9184 } else {
michael@0 9185 // If any of the values we care about was set by the above rule,
michael@0 9186 // we have author style.
michael@0 9187 for (uint32_t i = 0; i < nValues; ++i) {
michael@0 9188 if (values[i]->GetUnit() != eCSSUnit_Null &&
michael@0 9189 values[i]->GetUnit() != eCSSUnit_Dummy && // see above
michael@0 9190 values[i]->GetUnit() != eCSSUnit_DummyInherit) {
michael@0 9191 // If author colors are not allowed, only claim to have
michael@0 9192 // author-specified rules if we're looking at a non-color
michael@0 9193 // property or if we're looking at the background color and it's
michael@0 9194 // set to transparent. Anything else should get set to a dummy
michael@0 9195 // value instead.
michael@0 9196 if (aAuthorColorsAllowed ||
michael@0 9197 !nsCSSProps::PropHasFlags(properties[i],
michael@0 9198 CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED) ||
michael@0 9199 (properties[i] == eCSSProperty_background_color &&
michael@0 9200 !values[i]->IsNonTransparentColor())) {
michael@0 9201 return true;
michael@0 9202 }
michael@0 9203
michael@0 9204 values[i]->SetDummyValue();
michael@0 9205 }
michael@0 9206 }
michael@0 9207 }
michael@0 9208 }
michael@0 9209 }
michael@0 9210
michael@0 9211 if (haveExplicitUAInherit) {
michael@0 9212 // reset all the eCSSUnit_Null values to eCSSUnit_Dummy (since they're
michael@0 9213 // not styled by the author, or by anyone else), and then reset all the
michael@0 9214 // eCSSUnit_DummyInherit values to eCSSUnit_Null (so we will be able to
michael@0 9215 // detect them being styled by the author) and move up to our parent
michael@0 9216 // style context.
michael@0 9217 for (uint32_t i = 0; i < nValues; ++i)
michael@0 9218 if (values[i]->GetUnit() == eCSSUnit_Null)
michael@0 9219 values[i]->SetDummyValue();
michael@0 9220 for (uint32_t i = 0; i < nValues; ++i)
michael@0 9221 if (values[i]->GetUnit() == eCSSUnit_DummyInherit)
michael@0 9222 values[i]->Reset();
michael@0 9223 styleContext = styleContext->GetParent();
michael@0 9224 }
michael@0 9225 } while (haveExplicitUAInherit && styleContext);
michael@0 9226
michael@0 9227 return false;
michael@0 9228 }
michael@0 9229
michael@0 9230 /* static */
michael@0 9231 bool
michael@0 9232 nsRuleNode::ComputeColor(const nsCSSValue& aValue, nsPresContext* aPresContext,
michael@0 9233 nsStyleContext* aStyleContext, nscolor& aResult)
michael@0 9234 {
michael@0 9235 MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Inherit,
michael@0 9236 "aValue shouldn't have eCSSUnit_Inherit");
michael@0 9237 MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Initial,
michael@0 9238 "aValue shouldn't have eCSSUnit_Initial");
michael@0 9239 MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Unset,
michael@0 9240 "aValue shouldn't have eCSSUnit_Unset");
michael@0 9241
michael@0 9242 bool canStoreInRuleTree;
michael@0 9243 bool ok = SetColor(aValue, NS_RGB(0, 0, 0), aPresContext, aStyleContext,
michael@0 9244 aResult, canStoreInRuleTree);
michael@0 9245 MOZ_ASSERT(ok || !(aPresContext && aStyleContext));
michael@0 9246 return ok;
michael@0 9247 }

mercurial