Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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 | } |