Length AnimatableLength::toLength(const CSSToLengthConversionData& conversionData, NumberRange range) const { // Avoid creating a CSSValue in the common cases if (m_lengthUnitType == CSSPrimitiveValue::UnitTypePixels) return Length(clampedNumber(range) * conversionData.zoom(), Fixed); if (m_lengthUnitType == CSSPrimitiveValue::UnitTypePercentage) return Length(clampedNumber(range), Percent); return toCSSPrimitiveValue(range)->convertToLength<AnyConversion>(conversionData); }
Length CSSLengthInterpolationType::resolveInterpolableLength(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, const CSSToLengthConversionData& conversionData, ValueRange range) { const InterpolableList& interpolableList = toInterpolableList(interpolableValue); bool hasPercentage = CSSLengthNonInterpolableValue::hasPercentage(nonInterpolableValue); double pixels = 0; double percentage = 0; for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) { double value = toInterpolableNumber(*interpolableList.get(i)).value(); if (i == CSSPrimitiveValue::UnitTypePercentage) { percentage = value; } else { CSSPrimitiveValue::UnitType type = CSSPrimitiveValue::lengthUnitTypeToUnitType(static_cast<CSSPrimitiveValue::LengthUnitType>(i)); pixels += conversionData.zoomedComputedPixels(value, type); } } return createLength(pixels, percentage, hasPercentage, range); }
Length LengthInterpolationFunctions::createLength( const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, const CSSToLengthConversionData& conversionData, ValueRange range) { const InterpolableList& interpolableList = toInterpolableList(interpolableValue); bool hasPercentage = CSSLengthNonInterpolableValue::hasPercentage(nonInterpolableValue); double pixels = 0; double percentage = 0; for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; i++) { double value = toInterpolableNumber(*interpolableList.get(i)).value(); if (value == 0) continue; if (i == CSSPrimitiveValue::UnitTypePercentage) { percentage = value; } else { CSSPrimitiveValue::UnitType type = CSSPrimitiveValue::lengthUnitTypeToUnitType( static_cast<CSSPrimitiveValue::LengthUnitType>(i)); pixels += conversionData.zoomedComputedPixels(value, type); } } if (percentage != 0) hasPercentage = true; if (pixels != 0 && hasPercentage) return Length( CalculationValue::create(PixelsAndPercent(pixels, percentage), range)); if (hasPercentage) return Length(clampToRange(percentage, range), Percent); return Length( CSSPrimitiveValue::clampToCSSLengthRange(clampToRange(pixels, range)), Fixed); }
TransformOperations TransformBuilder::createTransformOperations( const CSSValue& inValue, const CSSToLengthConversionData& conversionData) { TransformOperations operations; if (!inValue.isValueList()) { DCHECK_EQ(toCSSIdentifierValue(inValue).getValueID(), CSSValueNone); return operations; } float zoomFactor = conversionData.zoom(); for (auto& value : toCSSValueList(inValue)) { const CSSFunctionValue* transformValue = toCSSFunctionValue(value.get()); TransformOperation::OperationType transformType = getTransformOperationType(transformValue->functionType()); const CSSPrimitiveValue& firstValue = toCSSPrimitiveValue(transformValue->item(0)); switch (transformType) { case TransformOperation::Scale: case TransformOperation::ScaleX: case TransformOperation::ScaleY: { double sx = 1.0; double sy = 1.0; if (transformType == TransformOperation::ScaleY) { sy = firstValue.getDoubleValue(); } else { sx = firstValue.getDoubleValue(); if (transformType != TransformOperation::ScaleX) { if (transformValue->length() > 1) { const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); sy = secondValue.getDoubleValue(); } else { sy = sx; } } } operations.operations().append( ScaleTransformOperation::create(sx, sy, 1.0, transformType)); break; } case TransformOperation::ScaleZ: case TransformOperation::Scale3D: { double sx = 1.0; double sy = 1.0; double sz = 1.0; if (transformType == TransformOperation::ScaleZ) { sz = firstValue.getDoubleValue(); } else { sx = firstValue.getDoubleValue(); sy = toCSSPrimitiveValue(transformValue->item(1)).getDoubleValue(); sz = toCSSPrimitiveValue(transformValue->item(2)).getDoubleValue(); } operations.operations().append( ScaleTransformOperation::create(sx, sy, sz, transformType)); break; } case TransformOperation::Translate: case TransformOperation::TranslateX: case TransformOperation::TranslateY: { Length tx = Length(0, Fixed); Length ty = Length(0, Fixed); if (transformType == TransformOperation::TranslateY) ty = convertToFloatLength(firstValue, conversionData); else { tx = convertToFloatLength(firstValue, conversionData); if (transformType != TransformOperation::TranslateX) { if (transformValue->length() > 1) { const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); ty = convertToFloatLength(secondValue, conversionData); } } } operations.operations().append( TranslateTransformOperation::create(tx, ty, 0, transformType)); break; } case TransformOperation::TranslateZ: case TransformOperation::Translate3D: { Length tx = Length(0, Fixed); Length ty = Length(0, Fixed); double tz = 0; if (transformType == TransformOperation::TranslateZ) { tz = firstValue.computeLength<double>(conversionData); } else { tx = convertToFloatLength(firstValue, conversionData); ty = convertToFloatLength( toCSSPrimitiveValue(transformValue->item(1)), conversionData); tz = toCSSPrimitiveValue(transformValue->item(2)) .computeLength<double>(conversionData); } operations.operations().append( TranslateTransformOperation::create(tx, ty, tz, transformType)); break; } case TransformOperation::RotateX: case TransformOperation::RotateY: case TransformOperation::RotateZ: { double angle = firstValue.computeDegrees(); if (transformValue->length() == 1) { double x = transformType == TransformOperation::RotateX; double y = transformType == TransformOperation::RotateY; double z = transformType == TransformOperation::RotateZ; operations.operations().append( RotateTransformOperation::create(x, y, z, angle, transformType)); } else { // For SVG 'transform' attributes we generate 3-argument rotate() // functions. DCHECK_EQ(transformValue->length(), 3u); const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); const CSSPrimitiveValue& thirdValue = toCSSPrimitiveValue(transformValue->item(2)); operations.operations().append( RotateAroundOriginTransformOperation::create( angle, secondValue.computeLength<double>(conversionData), thirdValue.computeLength<double>(conversionData))); } break; } case TransformOperation::Rotate3D: { const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); const CSSPrimitiveValue& thirdValue = toCSSPrimitiveValue(transformValue->item(2)); const CSSPrimitiveValue& fourthValue = toCSSPrimitiveValue(transformValue->item(3)); double x = firstValue.getDoubleValue(); double y = secondValue.getDoubleValue(); double z = thirdValue.getDoubleValue(); double angle = fourthValue.computeDegrees(); operations.operations().append( RotateTransformOperation::create(x, y, z, angle, transformType)); break; } case TransformOperation::Skew: case TransformOperation::SkewX: case TransformOperation::SkewY: { double angleX = 0; double angleY = 0; double angle = firstValue.computeDegrees(); if (transformType == TransformOperation::SkewY) angleY = angle; else { angleX = angle; if (transformType == TransformOperation::Skew) { if (transformValue->length() > 1) { const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); angleY = secondValue.computeDegrees(); } } } operations.operations().append( SkewTransformOperation::create(angleX, angleY, transformType)); break; } case TransformOperation::Matrix: { double a = firstValue.getDoubleValue(); double b = toCSSPrimitiveValue(transformValue->item(1)).getDoubleValue(); double c = toCSSPrimitiveValue(transformValue->item(2)).getDoubleValue(); double d = toCSSPrimitiveValue(transformValue->item(3)).getDoubleValue(); double e = zoomFactor * toCSSPrimitiveValue(transformValue->item(4)).getDoubleValue(); double f = zoomFactor * toCSSPrimitiveValue(transformValue->item(5)).getDoubleValue(); operations.operations().append( MatrixTransformOperation::create(a, b, c, d, e, f)); break; } case TransformOperation::Matrix3D: { TransformationMatrix matrix( toCSSPrimitiveValue(transformValue->item(0)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(1)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(2)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(3)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(4)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(5)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(6)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(7)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(8)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(9)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(10)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(11)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(12)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(13)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(14)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(15)).getDoubleValue()); matrix.zoom(zoomFactor); operations.operations().append( Matrix3DTransformOperation::create(matrix)); break; } case TransformOperation::Perspective: { double p = firstValue.computeLength<double>(conversionData); ASSERT(p >= 0); operations.operations().append( PerspectiveTransformOperation::create(p)); break; } default: ASSERT_NOT_REACHED(); break; } } return operations; }
double CSSPrimitiveValue::computeLengthDouble(const CSSToLengthConversionData& conversionData) { // The logic in this function is duplicated in MediaValues::computeLength // because MediaValues::computeLength needs nearly identical logic, but we haven't found a way to make // CSSPrimitiveValue::computeLengthDouble more generic (to solve both cases) without hurting performance. if (type() == UnitType::Calc) return m_value.calc->computeLengthPx(conversionData); double factor; switch (type()) { case UnitType::Ems: factor = conversionData.emFontSize(); break; case UnitType::Exs: factor = conversionData.exFontSize(); break; case UnitType::Rems: factor = conversionData.remFontSize(); break; case UnitType::Chs: factor = conversionData.chFontSize(); break; case UnitType::Pixels: factor = 1.0; break; case UnitType::Centimeters: factor = cssPixelsPerCentimeter; break; case UnitType::Millimeters: factor = cssPixelsPerMillimeter; break; case UnitType::Inches: factor = cssPixelsPerInch; break; case UnitType::Points: factor = cssPixelsPerPoint; break; case UnitType::Picas: factor = cssPixelsPerPica; break; case UnitType::ViewportWidth: factor = conversionData.viewportWidthPercent(); break; case UnitType::ViewportHeight: factor = conversionData.viewportHeightPercent(); break; case UnitType::ViewportMin: factor = conversionData.viewportMinPercent(); break; case UnitType::ViewportMax: factor = conversionData.viewportMaxPercent(); break; case UnitType::CalcPercentageWithLength: case UnitType::CalcPercentageWithNumber: ASSERT_NOT_REACHED(); return -1.0; default: ASSERT_NOT_REACHED(); return -1.0; } // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference // as well as enforcing the implicit "smart minimum." double result = getDoubleValue() * factor; if (isFontRelativeLength()) return result; return result * conversionData.zoom(); }
double CSSPrimitiveValue::computeLengthDouble(const CSSToLengthConversionData& conversionData) const { if (m_primitiveUnitType == CSS_CALC) // The multiplier and factor is applied to each value in the calc expression individually return m_value.calc->computeLengthPx(conversionData); double factor; switch (primitiveType()) { case CSS_EMS: ASSERT(conversionData.style()); factor = conversionData.computingFontSize() ? conversionData.style()->fontDescription().specifiedSize() : conversionData.style()->fontDescription().computedSize(); break; case CSS_EXS: ASSERT(conversionData.style()); // FIXME: We have a bug right now where the zoom will be applied twice to EX units. // We really need to compute EX using fontMetrics for the original specifiedSize and not use // our actual constructed rendering font. if (conversionData.style()->fontMetrics().hasXHeight()) factor = conversionData.style()->fontMetrics().xHeight(); else factor = (conversionData.computingFontSize() ? conversionData.style()->fontDescription().specifiedSize() : conversionData.style()->fontDescription().computedSize()) / 2.0; break; case CSS_REMS: if (conversionData.rootStyle()) factor = conversionData.computingFontSize() ? conversionData.rootStyle()->fontDescription().specifiedSize() : conversionData.rootStyle()->fontDescription().computedSize(); else factor = 1.0; break; case CSS_CHS: ASSERT(conversionData.style()); factor = conversionData.style()->fontMetrics().zeroWidth(); break; case CSS_PX: factor = 1.0; break; case CSS_CM: factor = cssPixelsPerInch / 2.54; // (2.54 cm/in) break; case CSS_MM: factor = cssPixelsPerInch / 25.4; break; case CSS_IN: factor = cssPixelsPerInch; break; case CSS_PT: factor = cssPixelsPerInch / 72.0; break; case CSS_PC: // 1 pc == 12 pt factor = cssPixelsPerInch * 12.0 / 72.0; break; case CSS_CALC_PERCENTAGE_WITH_LENGTH: case CSS_CALC_PERCENTAGE_WITH_NUMBER: ASSERT_NOT_REACHED(); return -1.0; case CSS_VH: factor = conversionData.viewportHeightFactor(); break; case CSS_VW: factor = conversionData.viewportWidthFactor(); break; case CSS_VMAX: factor = conversionData.viewportMaxFactor(); break; case CSS_VMIN: factor = conversionData.viewportMinFactor(); break; default: ASSERT_NOT_REACHED(); return -1.0; } // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference // as well as enforcing the implicit "smart minimum." double result = getDoubleValue() * factor; if (conversionData.computingFontSize() || isFontRelativeLength()) return result; return result * conversionData.zoom(); }
bool FilterOperationResolver::createFilterOperations(CSSValue* inValue, const CSSToLengthConversionData& unadjustedConversionData, FilterOperations& outOperations, StyleResolverState& state) { ASSERT(outOperations.isEmpty()); if (!inValue) return false; if (inValue->isPrimitiveValue()) { CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(inValue); if (primitiveValue->getValueID() == CSSValueNone) return true; } if (!inValue->isValueList()) return false; float zoomFactor = unadjustedConversionData.zoom() * state.elementStyleResources().deviceScaleFactor(); const CSSToLengthConversionData& conversionData = unadjustedConversionData.copyWithAdjustedZoom(zoomFactor); FilterOperations operations; for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) { CSSValue* currValue = i.value(); if (!currValue->isFilterValue()) continue; CSSFilterValue* filterValue = toCSSFilterValue(i.value()); FilterOperation::OperationType operationType = filterOperationForType(filterValue->operationType()); if (operationType == FilterOperation::VALIDATED_CUSTOM) { // ValidatedCustomFilterOperation is not supposed to end up in the RenderStyle. ASSERT_NOT_REACHED(); continue; } if (operationType == FilterOperation::CUSTOM) { RefPtr<CustomFilterOperation> operation = createCustomFilterOperation(filterValue, state); if (!operation) return false; operations.operations().append(operation); continue; } if (operationType == FilterOperation::REFERENCE) { if (filterValue->length() != 1) continue; CSSValue* argument = filterValue->itemWithoutBoundsCheck(0); if (!argument->isSVGDocumentValue()) continue; CSSSVGDocumentValue* svgDocumentValue = toCSSSVGDocumentValue(argument); KURL url = state.document().completeURL(svgDocumentValue->url()); RefPtr<ReferenceFilterOperation> operation = ReferenceFilterOperation::create(svgDocumentValue->url(), url.fragmentIdentifier()); if (SVGURIReference::isExternalURIReference(svgDocumentValue->url(), state.document())) { if (!svgDocumentValue->loadRequested()) state.elementStyleResources().addPendingSVGDocument(operation.get(), svgDocumentValue); else if (svgDocumentValue->cachedSVGDocument()) ReferenceFilterBuilder::setDocumentResourceReference(operation.get(), adoptPtr(new DocumentResourceReference(svgDocumentValue->cachedSVGDocument()))); } operations.operations().append(operation); continue; } // Check that all parameters are primitive values, with the // exception of drop shadow which has a CSSShadowValue parameter. if (operationType != FilterOperation::DROP_SHADOW) { bool haveNonPrimitiveValue = false; for (unsigned j = 0; j < filterValue->length(); ++j) { if (!filterValue->itemWithoutBoundsCheck(j)->isPrimitiveValue()) { haveNonPrimitiveValue = true; break; } } if (haveNonPrimitiveValue) continue; } CSSPrimitiveValue* firstValue = filterValue->length() && filterValue->itemWithoutBoundsCheck(0)->isPrimitiveValue() ? toCSSPrimitiveValue(filterValue->itemWithoutBoundsCheck(0)) : 0; switch (filterValue->operationType()) { case CSSFilterValue::GrayscaleFilterOperation: case CSSFilterValue::SepiaFilterOperation: case CSSFilterValue::SaturateFilterOperation: { double amount = 1; if (filterValue->length() == 1) { amount = firstValue->getDoubleValue(); if (firstValue->isPercentage()) amount /= 100; } operations.operations().append(BasicColorMatrixFilterOperation::create(amount, operationType)); break; } case CSSFilterValue::HueRotateFilterOperation: { double angle = 0; if (filterValue->length() == 1) angle = firstValue->computeDegrees(); operations.operations().append(BasicColorMatrixFilterOperation::create(angle, operationType)); break; } case CSSFilterValue::InvertFilterOperation: case CSSFilterValue::BrightnessFilterOperation: case CSSFilterValue::ContrastFilterOperation: case CSSFilterValue::OpacityFilterOperation: { double amount = (filterValue->operationType() == CSSFilterValue::BrightnessFilterOperation) ? 0 : 1; if (filterValue->length() == 1) { amount = firstValue->getDoubleValue(); if (firstValue->isPercentage()) amount /= 100; } operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType)); break; } case CSSFilterValue::BlurFilterOperation: { Length stdDeviation = Length(0, Fixed); if (filterValue->length() >= 1) stdDeviation = firstValue->convertToLength<FixedConversion | PercentConversion>(conversionData); if (stdDeviation.isUndefined()) return false; operations.operations().append(BlurFilterOperation::create(stdDeviation)); break; } case CSSFilterValue::DropShadowFilterOperation: { if (filterValue->length() != 1) return false; CSSValue* cssValue = filterValue->itemWithoutBoundsCheck(0); if (!cssValue->isShadowValue()) continue; CSSShadowValue* item = toCSSShadowValue(cssValue); IntPoint location(item->x->computeLength<int>(conversionData), item->y->computeLength<int>(conversionData)); int blur = item->blur ? item->blur->computeLength<int>(conversionData) : 0; Color shadowColor; if (item->color) shadowColor = state.document().textLinkColors().colorFromPrimitiveValue(item->color.get(), state.style()->color()); operations.operations().append(DropShadowFilterOperation::create(location, blur, shadowColor.isValid() ? shadowColor : Color::transparent)); break; } case CSSFilterValue::UnknownFilterOperation: default: ASSERT_NOT_REACHED(); break; } } outOperations = operations; return true; }