static PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> createSimplified(PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> leftSide, PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> rightSide, CalcOperator op) { CalculationCategory leftCategory = leftSide->category(); CalculationCategory rightCategory = rightSide->category(); ASSERT(leftCategory != CalcOther && rightCategory != CalcOther); bool isInteger = isIntegerResult(leftSide.get(), rightSide.get(), op); // Simplify numbers. if (leftCategory == CalcNumber && rightCategory == CalcNumber) { return CSSCalcPrimitiveValue::create(evaluateOperator(leftSide->doubleValue(), rightSide->doubleValue(), op), CSSPrimitiveValue::UnitType::Number, isInteger); } // Simplify addition and subtraction between same types. if (op == CalcAdd || op == CalcSubtract) { if (leftCategory == rightSide->category()) { CSSPrimitiveValue::UnitType leftType = leftSide->typeWithCalcResolved(); if (hasDoubleValue(leftType)) { CSSPrimitiveValue::UnitType rightType = rightSide->typeWithCalcResolved(); if (leftType == rightType) return CSSCalcPrimitiveValue::create(evaluateOperator(leftSide->doubleValue(), rightSide->doubleValue(), op), leftType, isInteger); CSSPrimitiveValue::UnitCategory leftUnitCategory = CSSPrimitiveValue::unitCategory(leftType); if (leftUnitCategory != CSSPrimitiveValue::UOther && leftUnitCategory == CSSPrimitiveValue::unitCategory(rightType)) { CSSPrimitiveValue::UnitType canonicalType = CSSPrimitiveValue::canonicalUnitTypeForCategory(leftUnitCategory); if (canonicalType != CSSPrimitiveValue::UnitType::Unknown) { double leftValue = leftSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(leftType); double rightValue = rightSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(rightType); return CSSCalcPrimitiveValue::create(evaluateOperator(leftValue, rightValue, op), canonicalType, isInteger); } } } } } else { // Simplify multiplying or dividing by a number for simplifiable types. ASSERT(op == CalcMultiply || op == CalcDivide); CSSCalcExpressionNode* numberSide = getNumberSide(leftSide.get(), rightSide.get()); if (!numberSide) return create(leftSide, rightSide, op); if (numberSide == leftSide && op == CalcDivide) return nullptr; CSSCalcExpressionNode* otherSide = leftSide == numberSide ? rightSide.get() : leftSide.get(); double number = numberSide->doubleValue(); if (std::isnan(number) || std::isinf(number)) return nullptr; if (op == CalcDivide && !number) return nullptr; CSSPrimitiveValue::UnitType otherType = otherSide->typeWithCalcResolved(); if (hasDoubleValue(otherType)) return CSSCalcPrimitiveValue::create(evaluateOperator(otherSide->doubleValue(), number, op), otherType, isInteger); } return create(leftSide, rightSide, op); }
double doubleValue() const override { if (hasDoubleValue(typeWithCalcResolved())) return m_value->getDoubleValue(); ASSERT_NOT_REACHED(); return 0; }
MediaTime::ComparisonFlags MediaTime::compare(const MediaTime& rhs, bool fuzzy) const { if ((isPositiveInfinite() && rhs.isPositiveInfinite()) || (isNegativeInfinite() && rhs.isNegativeInfinite()) || (isInvalid() && rhs.isInvalid()) || (isIndefinite() && rhs.isIndefinite())) return EqualTo; if (isInvalid()) return GreaterThan; if (rhs.isInvalid()) return LessThan; if (rhs.isNegativeInfinite() || isPositiveInfinite()) return GreaterThan; if (rhs.isPositiveInfinite() || isNegativeInfinite()) return LessThan; if (isIndefinite()) return GreaterThan; if (rhs.isIndefinite()) return LessThan; if (hasDoubleValue() && rhs.hasDoubleValue()) { if (m_timeValueAsDouble == rhs.m_timeValueAsDouble) return EqualTo; if (fuzzy && fabs(m_timeValueAsDouble - rhs.m_timeValueAsDouble) <= fuzzinessThreshold().toDouble()) return EqualTo; return m_timeValueAsDouble < rhs.m_timeValueAsDouble ? LessThan : GreaterThan; } MediaTime a = *this; MediaTime b = rhs; if (a.hasDoubleValue()) a.setTimeScale(DefaultTimeScale); if (b.hasDoubleValue()) b.setTimeScale(DefaultTimeScale); int64_t rhsWhole = b.m_timeValue / b.m_timeScale; int64_t lhsWhole = a.m_timeValue / a.m_timeScale; if (lhsWhole > rhsWhole) return GreaterThan; if (lhsWhole < rhsWhole) return LessThan; int64_t rhsRemain = b.m_timeValue % b.m_timeScale; int64_t lhsRemain = a.m_timeValue % a.m_timeScale; int64_t lhsFactor = lhsRemain * b.m_timeScale; int64_t rhsFactor = rhsRemain * a.m_timeScale; if (lhsFactor == rhsFactor) return EqualTo; return lhsFactor > rhsFactor ? GreaterThan : LessThan; }
double MediaTime::toDouble() const { if (isInvalid() || isIndefinite()) return std::numeric_limits<double>::quiet_NaN(); if (isPositiveInfinite()) return std::numeric_limits<double>::infinity(); if (isNegativeInfinite()) return -std::numeric_limits<double>::infinity(); if (hasDoubleValue()) return m_timeValueAsDouble; return static_cast<double>(m_timeValue) / m_timeScale; }
MediaTime MediaTime::operator-(const MediaTime& rhs) const { if (rhs.isInvalid() || isInvalid()) return invalidTime(); if (rhs.isIndefinite() || isIndefinite()) return indefiniteTime(); if (isPositiveInfinite() && rhs.isPositiveInfinite()) return invalidTime(); if (isNegativeInfinite() && rhs.isNegativeInfinite()) return invalidTime(); if (isPositiveInfinite() || rhs.isNegativeInfinite()) return positiveInfiniteTime(); if (isNegativeInfinite() || rhs.isPositiveInfinite()) return negativeInfiniteTime(); if (hasDoubleValue() && rhs.hasDoubleValue()) return MediaTime::createWithDouble(m_timeValueAsDouble - rhs.m_timeValueAsDouble); MediaTime a = *this; MediaTime b = rhs; if (a.hasDoubleValue()) a.setTimeScale(DefaultTimeScale); else if (b.hasDoubleValue()) b.setTimeScale(DefaultTimeScale); int32_t commonTimeScale; if (!leastCommonMultiple(this->m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale) commonTimeScale = MaximumTimeScale; a.setTimeScale(commonTimeScale); b.setTimeScale(commonTimeScale); while (!safeSub(a.m_timeValue, b.m_timeValue, a.m_timeValue)) { if (commonTimeScale == 1) return a.m_timeValue > 0 ? positiveInfiniteTime() : negativeInfiniteTime(); commonTimeScale /= 2; a.setTimeScale(commonTimeScale); b.setTimeScale(commonTimeScale); } return a; }
void MediaTime::setTimeScale(int32_t timeScale) { if (hasDoubleValue()) { *this = MediaTime::createWithDouble(m_timeValueAsDouble, timeScale); return; } if (timeScale == m_timeScale) return; timeScale = std::min(MaximumTimeScale, timeScale); int64_t wholePart = m_timeValue / m_timeScale; // If setting the time scale will cause an overflow, divide the // timescale by two until the number will fit, and round the // result. int64_t newWholePart; while (!safeMultiply(wholePart, timeScale, newWholePart)) timeScale /= 2; int64_t remainder = m_timeValue % m_timeScale; m_timeValue = newWholePart + (remainder * timeScale) / m_timeScale; m_timeScale = timeScale; }