1 /* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * * Redistributions of source code must retain the above copyright 5 * notice, this list of conditions and the following disclaimer. 6 * * Redistributions in binary form must reproduce the above 7 * copyright notice, this list of conditions and the following disclaimer 8 * in the documentation and/or other materials provided with the 9 * distribution. 10 * * Neither the name of Google Inc. nor the names of its 11 * contributors may be used to endorse or promote products derived from 12 * this software without specific prior written permission. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "core/css/resolver/StyleBuilderConverter.h" 29 30 #include "core/css/CSSFontFeatureValue.h" 31 #include "core/css/CSSFunctionValue.h" 32 #include "core/css/CSSGridLineNamesValue.h" 33 #include "core/css/CSSPrimitiveValueMappings.h" 34 #include "core/css/CSSReflectValue.h" 35 #include "core/css/CSSShadowValue.h" 36 #include "core/css/Pair.h" 37 #include "core/css/Rect.h" 38 #include "core/svg/SVGURIReference.h" 39 40 namespace blink { 41 42 namespace { 43 44 static GridLength convertGridTrackBreadth(const StyleResolverState& state, CSSPrimitiveValue* primitiveValue) 45 { 46 if (primitiveValue->getValueID() == CSSValueMinContent) 47 return Length(MinContent); 48 49 if (primitiveValue->getValueID() == CSSValueMaxContent) 50 return Length(MaxContent); 51 52 // Fractional unit. 53 if (primitiveValue->isFlex()) 54 return GridLength(primitiveValue->getDoubleValue()); 55 56 return primitiveValue->convertToLength<FixedConversion | PercentConversion | AutoConversion>(state.cssToLengthConversionData()); 57 } 58 59 } // namespace 60 61 PassRefPtr<StyleReflection> StyleBuilderConverter::convertBoxReflect(StyleResolverState& state, CSSValue* value) 62 { 63 if (value->isPrimitiveValue()) { 64 ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone); 65 return RenderStyle::initialBoxReflect(); 66 } 67 68 CSSReflectValue* reflectValue = toCSSReflectValue(value); 69 RefPtr<StyleReflection> reflection = StyleReflection::create(); 70 reflection->setDirection(*reflectValue->direction()); 71 if (reflectValue->offset()) 72 reflection->setOffset(reflectValue->offset()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData())); 73 NinePieceImage mask; 74 mask.setMaskDefaults(); 75 state.styleMap().mapNinePieceImage(state.style(), CSSPropertyWebkitBoxReflect, reflectValue->mask(), mask); 76 reflection->setMask(mask); 77 78 return reflection.release(); 79 } 80 81 Color StyleBuilderConverter::convertColor(StyleResolverState& state, CSSValue* value, bool forVisitedLink) 82 { 83 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 84 return state.document().textLinkColors().colorFromPrimitiveValue(primitiveValue, state.style()->color(), forVisitedLink); 85 } 86 87 AtomicString StyleBuilderConverter::convertFragmentIdentifier(StyleResolverState& state, CSSValue* value) 88 { 89 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 90 if (primitiveValue->isURI()) 91 return SVGURIReference::fragmentIdentifierFromIRIString(primitiveValue->getStringValue(), state.element()->treeScope()); 92 return nullAtom; 93 } 94 95 LengthBox StyleBuilderConverter::convertClip(StyleResolverState& state, CSSValue* value) 96 { 97 Rect* rect = toCSSPrimitiveValue(value)->getRectValue(); 98 99 return LengthBox(convertLengthOrAuto(state, rect->top()), 100 convertLengthOrAuto(state, rect->right()), 101 convertLengthOrAuto(state, rect->bottom()), 102 convertLengthOrAuto(state, rect->left())); 103 } 104 105 PassRefPtr<FontFeatureSettings> StyleBuilderConverter::convertFontFeatureSettings(StyleResolverState& state, CSSValue* value) 106 { 107 if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->getValueID() == CSSValueNormal) 108 return FontBuilder::initialFeatureSettings(); 109 110 CSSValueList* list = toCSSValueList(value); 111 RefPtr<FontFeatureSettings> settings = FontFeatureSettings::create(); 112 int len = list->length(); 113 for (int i = 0; i < len; ++i) { 114 CSSFontFeatureValue* feature = toCSSFontFeatureValue(list->item(i)); 115 settings->append(FontFeature(feature->tag(), feature->value())); 116 } 117 return settings; 118 } 119 120 class RedirectSetHasViewportUnits { 121 public: 122 RedirectSetHasViewportUnits(RenderStyle* from, RenderStyle* to) 123 : m_from(from), m_to(to), m_hadViewportUnits(from->hasViewportUnits()) 124 { 125 from->setHasViewportUnits(false); 126 } 127 ~RedirectSetHasViewportUnits() 128 { 129 m_to->setHasViewportUnits(m_from->hasViewportUnits()); 130 m_from->setHasViewportUnits(m_hadViewportUnits); 131 } 132 private: 133 RenderStyle* m_from; 134 RenderStyle* m_to; 135 bool m_hadViewportUnits; 136 }; 137 138 static float computeFontSize(StyleResolverState& state, CSSPrimitiveValue* primitiveValue, const FontDescription::Size& parentSize) 139 { 140 RedirectSetHasViewportUnits redirect(state.parentStyle(), state.style()); 141 142 CSSToLengthConversionData conversionData(state.parentStyle(), state.rootElementStyle(), state.document().renderView(), 1.0f, true); 143 if (primitiveValue->isLength()) 144 return primitiveValue->computeLength<float>(conversionData); 145 if (primitiveValue->isCalculatedPercentageWithLength()) 146 return primitiveValue->cssCalcValue()->toCalcValue(conversionData)->evaluate(parentSize.value); 147 148 ASSERT_NOT_REACHED(); 149 return 0; 150 } 151 152 FontDescription::Size StyleBuilderConverter::convertFontSize(StyleResolverState& state, CSSValue* value) 153 { 154 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 155 156 FontDescription::Size parentSize(0, 0.0f, false); 157 158 // FIXME: Find out when parentStyle could be 0? 159 if (state.parentStyle()) 160 parentSize = state.parentFontDescription().size(); 161 162 if (CSSValueID valueID = primitiveValue->getValueID()) { 163 switch (valueID) { 164 case CSSValueXxSmall: 165 case CSSValueXSmall: 166 case CSSValueSmall: 167 case CSSValueMedium: 168 case CSSValueLarge: 169 case CSSValueXLarge: 170 case CSSValueXxLarge: 171 case CSSValueWebkitXxxLarge: 172 return FontDescription::Size(FontSize::keywordSize(valueID), 0.0f, false); 173 case CSSValueLarger: 174 return FontDescription::largerSize(parentSize); 175 case CSSValueSmaller: 176 return FontDescription::smallerSize(parentSize); 177 default: 178 ASSERT_NOT_REACHED(); 179 return FontBuilder::initialSize(); 180 } 181 } 182 183 bool parentIsAbsoluteSize = state.parentFontDescription().isAbsoluteSize(); 184 185 if (primitiveValue->isPercentage()) 186 return FontDescription::Size(0, (primitiveValue->getFloatValue() * parentSize.value / 100.0f), parentIsAbsoluteSize); 187 188 return FontDescription::Size(0, computeFontSize(state, primitiveValue, parentSize), parentIsAbsoluteSize || !primitiveValue->isFontRelativeLength()); 189 } 190 191 FontWeight StyleBuilderConverter::convertFontWeight(StyleResolverState& state, CSSValue* value) 192 { 193 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 194 switch (primitiveValue->getValueID()) { 195 case CSSValueBolder: 196 return FontDescription::bolderWeight(state.parentStyle()->fontDescription().weight()); 197 case CSSValueLighter: 198 return FontDescription::lighterWeight(state.parentStyle()->fontDescription().weight()); 199 default: 200 return *primitiveValue; 201 } 202 } 203 204 FontDescription::VariantLigatures StyleBuilderConverter::convertFontVariantLigatures(StyleResolverState&, CSSValue* value) 205 { 206 if (value->isValueList()) { 207 FontDescription::VariantLigatures ligatures; 208 CSSValueList* valueList = toCSSValueList(value); 209 for (size_t i = 0; i < valueList->length(); ++i) { 210 CSSValue* item = valueList->item(i); 211 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(item); 212 switch (primitiveValue->getValueID()) { 213 case CSSValueNoCommonLigatures: 214 ligatures.common = FontDescription::DisabledLigaturesState; 215 break; 216 case CSSValueCommonLigatures: 217 ligatures.common = FontDescription::EnabledLigaturesState; 218 break; 219 case CSSValueNoDiscretionaryLigatures: 220 ligatures.discretionary = FontDescription::DisabledLigaturesState; 221 break; 222 case CSSValueDiscretionaryLigatures: 223 ligatures.discretionary = FontDescription::EnabledLigaturesState; 224 break; 225 case CSSValueNoHistoricalLigatures: 226 ligatures.historical = FontDescription::DisabledLigaturesState; 227 break; 228 case CSSValueHistoricalLigatures: 229 ligatures.historical = FontDescription::EnabledLigaturesState; 230 break; 231 case CSSValueNoContextual: 232 ligatures.contextual = FontDescription::DisabledLigaturesState; 233 break; 234 case CSSValueContextual: 235 ligatures.contextual = FontDescription::EnabledLigaturesState; 236 break; 237 default: 238 ASSERT_NOT_REACHED(); 239 break; 240 } 241 } 242 return ligatures; 243 } 244 245 ASSERT_WITH_SECURITY_IMPLICATION(value->isPrimitiveValue()); 246 ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNormal); 247 return FontDescription::VariantLigatures(); 248 } 249 250 EGlyphOrientation StyleBuilderConverter::convertGlyphOrientation(StyleResolverState&, CSSValue* value) 251 { 252 if (!value->isPrimitiveValue()) 253 return GO_0DEG; 254 255 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 256 if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_DEG) 257 return GO_0DEG; 258 259 float angle = fabsf(fmodf(primitiveValue->getFloatValue(), 360.0f)); 260 261 if (angle <= 45.0f || angle > 315.0f) 262 return GO_0DEG; 263 if (angle > 45.0f && angle <= 135.0f) 264 return GO_90DEG; 265 if (angle > 135.0f && angle <= 225.0f) 266 return GO_180DEG; 267 return GO_270DEG; 268 } 269 270 GridPosition StyleBuilderConverter::convertGridPosition(StyleResolverState&, CSSValue* value) 271 { 272 // We accept the specification's grammar: 273 // 'auto' | [ <integer> || <custom-ident> ] | [ span && [ <integer> || <custom-ident> ] ] | <custom-ident> 274 275 GridPosition position; 276 277 if (value->isPrimitiveValue()) { 278 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 279 // We translate <custom-ident> to <string> during parsing as it 280 // makes handling it more simple. 281 if (primitiveValue->isString()) { 282 position.setNamedGridArea(primitiveValue->getStringValue()); 283 return position; 284 } 285 286 ASSERT(primitiveValue->getValueID() == CSSValueAuto); 287 return position; 288 } 289 290 CSSValueList* values = toCSSValueList(value); 291 ASSERT(values->length()); 292 293 bool isSpanPosition = false; 294 // The specification makes the <integer> optional, in which case it default to '1'. 295 int gridLineNumber = 1; 296 String gridLineName; 297 298 CSSValueListIterator it = values; 299 CSSPrimitiveValue* currentValue = toCSSPrimitiveValue(it.value()); 300 if (currentValue->getValueID() == CSSValueSpan) { 301 isSpanPosition = true; 302 it.advance(); 303 currentValue = it.hasMore() ? toCSSPrimitiveValue(it.value()) : 0; 304 } 305 306 if (currentValue && currentValue->isNumber()) { 307 gridLineNumber = currentValue->getIntValue(); 308 it.advance(); 309 currentValue = it.hasMore() ? toCSSPrimitiveValue(it.value()) : 0; 310 } 311 312 if (currentValue && currentValue->isString()) { 313 gridLineName = currentValue->getStringValue(); 314 it.advance(); 315 } 316 317 ASSERT(!it.hasMore()); 318 if (isSpanPosition) 319 position.setSpanPosition(gridLineNumber, gridLineName); 320 else 321 position.setExplicitPosition(gridLineNumber, gridLineName); 322 323 return position; 324 } 325 326 GridTrackSize StyleBuilderConverter::convertGridTrackSize(StyleResolverState& state, CSSValue* value) 327 { 328 if (value->isPrimitiveValue()) 329 return GridTrackSize(convertGridTrackBreadth(state, toCSSPrimitiveValue(value))); 330 331 CSSFunctionValue* minmaxFunction = toCSSFunctionValue(value); 332 CSSValueList* arguments = minmaxFunction->arguments(); 333 ASSERT_WITH_SECURITY_IMPLICATION(arguments->length() == 2); 334 GridLength minTrackBreadth(convertGridTrackBreadth(state, toCSSPrimitiveValue(arguments->item(0)))); 335 GridLength maxTrackBreadth(convertGridTrackBreadth(state, toCSSPrimitiveValue(arguments->item(1)))); 336 return GridTrackSize(minTrackBreadth, maxTrackBreadth); 337 } 338 339 bool StyleBuilderConverter::convertGridTrackList(CSSValue* value, Vector<GridTrackSize>& trackSizes, NamedGridLinesMap& namedGridLines, OrderedNamedGridLines& orderedNamedGridLines, StyleResolverState& state) 340 { 341 // Handle 'none'. 342 if (value->isPrimitiveValue()) { 343 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 344 return primitiveValue->getValueID() == CSSValueNone; 345 } 346 347 if (!value->isValueList()) 348 return false; 349 350 size_t currentNamedGridLine = 0; 351 for (CSSValueListIterator i = value; i.hasMore(); i.advance()) { 352 CSSValue* currValue = i.value(); 353 if (currValue->isGridLineNamesValue()) { 354 CSSGridLineNamesValue* lineNamesValue = toCSSGridLineNamesValue(currValue); 355 for (CSSValueListIterator j = lineNamesValue; j.hasMore(); j.advance()) { 356 String namedGridLine = toCSSPrimitiveValue(j.value())->getStringValue(); 357 NamedGridLinesMap::AddResult result = namedGridLines.add(namedGridLine, Vector<size_t>()); 358 result.storedValue->value.append(currentNamedGridLine); 359 OrderedNamedGridLines::AddResult orderedInsertionResult = orderedNamedGridLines.add(currentNamedGridLine, Vector<String>()); 360 orderedInsertionResult.storedValue->value.append(namedGridLine); 361 } 362 continue; 363 } 364 365 ++currentNamedGridLine; 366 trackSizes.append(convertGridTrackSize(state, currValue)); 367 } 368 369 // The parser should have rejected any <track-list> without any <track-size> as 370 // this is not conformant to the syntax. 371 ASSERT(!trackSizes.isEmpty()); 372 return true; 373 } 374 375 void StyleBuilderConverter::createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap& namedGridAreas, NamedGridLinesMap& namedGridLines, GridTrackSizingDirection direction) 376 { 377 NamedGridAreaMap::const_iterator end = namedGridAreas.end(); 378 for (NamedGridAreaMap::const_iterator it = namedGridAreas.begin(); it != end; ++it) { 379 GridSpan areaSpan = direction == ForRows ? it->value.rows : it->value.columns; 380 { 381 NamedGridLinesMap::AddResult startResult = namedGridLines.add(it->key + "-start", Vector<size_t>()); 382 startResult.storedValue->value.append(areaSpan.resolvedInitialPosition.toInt()); 383 std::sort(startResult.storedValue->value.begin(), startResult.storedValue->value.end()); 384 } 385 { 386 NamedGridLinesMap::AddResult endResult = namedGridLines.add(it->key + "-end", Vector<size_t>()); 387 endResult.storedValue->value.append(areaSpan.resolvedFinalPosition.toInt() + 1); 388 std::sort(endResult.storedValue->value.begin(), endResult.storedValue->value.end()); 389 } 390 } 391 } 392 393 Length StyleBuilderConverter::convertLength(StyleResolverState& state, CSSValue* value) 394 { 395 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 396 Length result = primitiveValue->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData()); 397 result.setQuirk(primitiveValue->isQuirkValue()); 398 return result; 399 } 400 401 Length StyleBuilderConverter::convertLengthOrAuto(StyleResolverState& state, CSSValue* value) 402 { 403 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 404 Length result = primitiveValue->convertToLength<FixedConversion | PercentConversion | AutoConversion>(state.cssToLengthConversionData()); 405 result.setQuirk(primitiveValue->isQuirkValue()); 406 return result; 407 } 408 409 Length StyleBuilderConverter::convertLengthSizing(StyleResolverState& state, CSSValue* value) 410 { 411 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 412 switch (primitiveValue->getValueID()) { 413 case CSSValueInvalid: 414 return convertLength(state, value); 415 case CSSValueIntrinsic: 416 return Length(Intrinsic); 417 case CSSValueMinIntrinsic: 418 return Length(MinIntrinsic); 419 case CSSValueWebkitMinContent: 420 return Length(MinContent); 421 case CSSValueWebkitMaxContent: 422 return Length(MaxContent); 423 case CSSValueWebkitFillAvailable: 424 return Length(FillAvailable); 425 case CSSValueWebkitFitContent: 426 return Length(FitContent); 427 case CSSValueAuto: 428 return Length(Auto); 429 default: 430 ASSERT_NOT_REACHED(); 431 return Length(); 432 } 433 } 434 435 Length StyleBuilderConverter::convertLengthMaxSizing(StyleResolverState& state, CSSValue* value) 436 { 437 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 438 if (primitiveValue->getValueID() == CSSValueNone) 439 return Length(MaxSizeNone); 440 return convertLengthSizing(state, value); 441 } 442 443 LengthPoint StyleBuilderConverter::convertLengthPoint(StyleResolverState& state, CSSValue* value) 444 { 445 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 446 Pair* pair = primitiveValue->getPairValue(); 447 Length x = pair->first()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData()); 448 Length y = pair->second()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData()); 449 return LengthPoint(x, y); 450 } 451 452 LineBoxContain StyleBuilderConverter::convertLineBoxContain(StyleResolverState&, CSSValue* value) 453 { 454 if (value->isPrimitiveValue()) { 455 ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone); 456 return LineBoxContainNone; 457 } 458 459 return toCSSLineBoxContainValue(value)->value(); 460 } 461 462 float StyleBuilderConverter::convertNumberOrPercentage(StyleResolverState& state, CSSValue* value) 463 { 464 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 465 ASSERT(primitiveValue->isNumber() || primitiveValue->isPercentage()); 466 if (primitiveValue->isNumber()) 467 return primitiveValue->getFloatValue(); 468 return primitiveValue->getFloatValue() / 100.0f; 469 } 470 471 EPaintOrder StyleBuilderConverter::convertPaintOrder(StyleResolverState&, CSSValue* cssPaintOrder) 472 { 473 if (cssPaintOrder->isValueList()) { 474 int paintOrder = 0; 475 CSSValueListInspector iter(cssPaintOrder); 476 for (size_t i = 0; i < iter.length(); i++) { 477 CSSPrimitiveValue* value = toCSSPrimitiveValue(iter.item(i)); 478 479 EPaintOrderType paintOrderType = PT_NONE; 480 switch (value->getValueID()) { 481 case CSSValueFill: 482 paintOrderType = PT_FILL; 483 break; 484 case CSSValueStroke: 485 paintOrderType = PT_STROKE; 486 break; 487 case CSSValueMarkers: 488 paintOrderType = PT_MARKERS; 489 break; 490 default: 491 ASSERT_NOT_REACHED(); 492 break; 493 } 494 495 paintOrder |= (paintOrderType << kPaintOrderBitwidth*i); 496 } 497 return (EPaintOrder)paintOrder; 498 } 499 500 return PO_NORMAL; 501 } 502 503 PassRefPtr<QuotesData> StyleBuilderConverter::convertQuotes(StyleResolverState&, CSSValue* value) 504 { 505 if (value->isValueList()) { 506 CSSValueList* list = toCSSValueList(value); 507 RefPtr<QuotesData> quotes = QuotesData::create(); 508 for (size_t i = 0; i < list->length(); i += 2) { 509 CSSValue* first = list->item(i); 510 CSSValue* second = list->item(i + 1); 511 String startQuote = toCSSPrimitiveValue(first)->getStringValue(); 512 String endQuote = toCSSPrimitiveValue(second)->getStringValue(); 513 quotes->addPair(std::make_pair(startQuote, endQuote)); 514 } 515 return quotes.release(); 516 } 517 // FIXME: We should assert we're a primitive value with valueID = CSSValueNone 518 return QuotesData::create(); 519 } 520 521 LengthSize StyleBuilderConverter::convertRadius(StyleResolverState& state, CSSValue* value) 522 { 523 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 524 Pair* pair = primitiveValue->getPairValue(); 525 Length radiusWidth = pair->first()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData()); 526 Length radiusHeight = pair->second()->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData()); 527 float width = radiusWidth.value(); 528 float height = radiusHeight.value(); 529 ASSERT(width >= 0 && height >= 0); 530 if (width <= 0 || height <= 0) 531 return LengthSize(Length(0, Fixed), Length(0, Fixed)); 532 return LengthSize(radiusWidth, radiusHeight); 533 } 534 535 PassRefPtr<ShadowList> StyleBuilderConverter::convertShadow(StyleResolverState& state, CSSValue* value) 536 { 537 if (value->isPrimitiveValue()) { 538 ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNone); 539 return PassRefPtr<ShadowList>(); 540 } 541 542 const CSSValueList* valueList = toCSSValueList(value); 543 size_t shadowCount = valueList->length(); 544 ShadowDataVector shadows; 545 for (size_t i = 0; i < shadowCount; ++i) { 546 const CSSShadowValue* item = toCSSShadowValue(valueList->item(i)); 547 float x = item->x->computeLength<float>(state.cssToLengthConversionData()); 548 float y = item->y->computeLength<float>(state.cssToLengthConversionData()); 549 float blur = item->blur ? item->blur->computeLength<float>(state.cssToLengthConversionData()) : 0; 550 float spread = item->spread ? item->spread->computeLength<float>(state.cssToLengthConversionData()) : 0; 551 ShadowStyle shadowStyle = item->style && item->style->getValueID() == CSSValueInset ? Inset : Normal; 552 Color color; 553 if (item->color) 554 color = convertColor(state, item->color.get()); 555 else 556 color = state.style()->color(); 557 shadows.append(ShadowData(FloatPoint(x, y), blur, spread, shadowStyle, color)); 558 } 559 return ShadowList::adopt(shadows); 560 } 561 562 float StyleBuilderConverter::convertSpacing(StyleResolverState& state, CSSValue* value) 563 { 564 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 565 if (primitiveValue->getValueID() == CSSValueNormal) 566 return 0; 567 return primitiveValue->computeLength<float>(state.cssToLengthConversionData()); 568 } 569 570 PassRefPtr<SVGLengthList> StyleBuilderConverter::convertStrokeDasharray(StyleResolverState&, CSSValue* value) 571 { 572 if (!value->isValueList()) { 573 return SVGRenderStyle::initialStrokeDashArray(); 574 } 575 576 CSSValueList* dashes = toCSSValueList(value); 577 578 RefPtr<SVGLengthList> array = SVGLengthList::create(); 579 size_t length = dashes->length(); 580 for (size_t i = 0; i < length; ++i) { 581 CSSValue* currValue = dashes->item(i); 582 if (!currValue->isPrimitiveValue()) 583 continue; 584 585 CSSPrimitiveValue* dash = toCSSPrimitiveValue(dashes->item(i)); 586 array->append(SVGLength::fromCSSPrimitiveValue(dash)); 587 } 588 589 return array.release(); 590 } 591 592 StyleColor StyleBuilderConverter::convertStyleColor(StyleResolverState& state, CSSValue* value, bool forVisitedLink) 593 { 594 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 595 if (primitiveValue->getValueID() == CSSValueCurrentcolor) 596 return StyleColor::currentColor(); 597 return state.document().textLinkColors().colorFromPrimitiveValue(primitiveValue, Color(), forVisitedLink); 598 } 599 600 Color StyleBuilderConverter::convertSVGColor(StyleResolverState& state, CSSValue* value) 601 { 602 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 603 if (primitiveValue->isRGBColor()) 604 return primitiveValue->getRGBA32Value(); 605 ASSERT(primitiveValue->getValueID() == CSSValueCurrentcolor); 606 return state.style()->color(); 607 } 608 609 PassRefPtr<SVGLength> StyleBuilderConverter::convertSVGLength(StyleResolverState&, CSSValue* value) 610 { 611 return SVGLength::fromCSSPrimitiveValue(toCSSPrimitiveValue(value)); 612 } 613 614 float StyleBuilderConverter::convertTextStrokeWidth(StyleResolverState& state, CSSValue* value) 615 { 616 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value); 617 if (primitiveValue->getValueID()) { 618 float multiplier = convertLineWidth<float>(state, value); 619 return CSSPrimitiveValue::create(multiplier / 48, CSSPrimitiveValue::CSS_EMS)->computeLength<float>(state.cssToLengthConversionData()); 620 } 621 return primitiveValue->computeLength<float>(state.cssToLengthConversionData()); 622 } 623 624 } // namespace blink 625