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);
}
Exemple #4
0
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();
}
Exemple #6
0
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;
}