Changeset 283013 in webkit


Ignore:
Timestamp:
Sep 23, 2021 3:01:16 PM (10 months ago)
Author:
commit-queue@webkit.org
Message:

Implement atan, acos, asin, atan2 calc functions
https://bugs.webkit.org/show_bug.cgi?id=229775

Patch by Nikos Mouchtaris <Nikos Mouchtaris> on 2021-09-23
Reviewed by Simon Fraser.

LayoutTests/imported/w3c:

  • web-platform-tests/css/css-values/acos-asin-atan-atan2-computed-expected.txt: Added.
  • web-platform-tests/css/css-values/acos-asin-atan-atan2-computed.html: Added.
  • web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid-expected.txt: Added.
  • web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid.html: Added.
  • web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize-expected.txt: Added.
  • web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize.html: Added.
  • web-platform-tests/css/support/numeric-testcommon.js:

Source/WebCore:

Added support for calc functions asin, acos, atan, atan2. Involved adding function CSS
keywords and handling for parsing these functions and their arguments as well as computing
the result based on the arguments. Spec for these functions:
https://drafts.csswg.org/css-values-4/#trig-funcs.

Tests: imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-computed.html

imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid.html
imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize.html

  • css/CSSValueKeywords.in:
  • css/calc/CSSCalcExpressionNodeParser.cpp:

(WebCore::CSSCalcExpressionNodeParser::parseCalcFunction):

  • css/calc/CSSCalcOperationNode.cpp:

(WebCore::determineCategory):
(WebCore::functionFromOperator):
(WebCore::CSSCalcOperationNode::createInverseTrig):
(WebCore::CSSCalcOperationNode::createAtan2):
(WebCore::CSSCalcOperationNode::combineChildren):
(WebCore::CSSCalcOperationNode::simplifyNode):
(WebCore::CSSCalcOperationNode::primitiveType const):
(WebCore::CSSCalcOperationNode::doubleValue const):
(WebCore::functionPrefixForOperator):
(WebCore::CSSCalcOperationNode::evaluateOperator):

  • css/calc/CSSCalcOperationNode.h:
  • css/calc/CSSCalcValue.cpp:

(WebCore::createCSS):
(WebCore::CSSCalcValue::isCalcFunction):

  • platform/calc/CalcExpressionOperation.cpp:

(WebCore::CalcExpressionOperation::evaluate const):
Return converted to degrees based on spec: https://drafts.csswg.org/css-values-4/#trig-funcs.

  • platform/calc/CalcOperator.cpp:

(WebCore::operator<<):

  • platform/calc/CalcOperator.h:
Location:
trunk
Files:
6 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r282922 r283013  
     12021-09-23  Nikos Mouchtaris  <nmouchtaris@apple.com>
     2
     3        Implement atan, acos, asin, atan2 calc functions
     4        https://bugs.webkit.org/show_bug.cgi?id=229775
     5
     6        Reviewed by Simon Fraser.
     7
     8        * web-platform-tests/css/css-values/acos-asin-atan-atan2-computed-expected.txt: Added.
     9        * web-platform-tests/css/css-values/acos-asin-atan-atan2-computed.html: Added.
     10        * web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid-expected.txt: Added.
     11        * web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid.html: Added.
     12        * web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize-expected.txt: Added.
     13        * web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize.html: Added.
     14        * web-platform-tests/css/support/numeric-testcommon.js:
     15
    1162021-09-22  Myles C. Maxfield  <mmaxfield@apple.com>
    217
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/support/numeric-testcommon.js

    r282402 r283013  
    185185        const expectedValue = getComputedStyle(testEl)[prop];
    186186        assert_not_equals(expectedValue, '', `${expectedString} isn't valid in '${prop}'; got the default value instead.`)
    187         if(approx && type == "number"){
     187        if(approx && (type == "number" || type == "angle")){
    188188            let parsedUsed = usedValue.split('(')[1].split(')')[0].split(',').map(parseFloat);
    189189            let parsedExpected = expectedValue.split('(')[1].split(')')[0].split(',').map(parseFloat);
  • trunk/Source/WebCore/ChangeLog

    r282988 r283013  
     12021-09-23  Nikos Mouchtaris  <nmouchtaris@apple.com>
     2
     3        Implement atan, acos, asin, atan2 calc functions
     4        https://bugs.webkit.org/show_bug.cgi?id=229775
     5
     6        Reviewed by Simon Fraser.
     7
     8        Added support for calc functions asin, acos, atan, atan2. Involved adding function CSS 
     9        keywords and handling for parsing these functions and their arguments as well as computing
     10        the result based on the arguments. Spec for these functions:
     11        https://drafts.csswg.org/css-values-4/#trig-funcs.
     12
     13        Tests: imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-computed.html
     14               imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid.html
     15               imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize.html
     16
     17        * css/CSSValueKeywords.in:
     18        * css/calc/CSSCalcExpressionNodeParser.cpp:
     19        (WebCore::CSSCalcExpressionNodeParser::parseCalcFunction):
     20        * css/calc/CSSCalcOperationNode.cpp:
     21        (WebCore::determineCategory):
     22        (WebCore::functionFromOperator):
     23        (WebCore::CSSCalcOperationNode::createInverseTrig):
     24        (WebCore::CSSCalcOperationNode::createAtan2):
     25        (WebCore::CSSCalcOperationNode::combineChildren):
     26        (WebCore::CSSCalcOperationNode::simplifyNode):
     27        (WebCore::CSSCalcOperationNode::primitiveType const):
     28        (WebCore::CSSCalcOperationNode::doubleValue const):
     29        (WebCore::functionPrefixForOperator):
     30        (WebCore::CSSCalcOperationNode::evaluateOperator):
     31        * css/calc/CSSCalcOperationNode.h:
     32        * css/calc/CSSCalcValue.cpp:
     33        (WebCore::createCSS):
     34        (WebCore::CSSCalcValue::isCalcFunction):
     35        * platform/calc/CalcExpressionOperation.cpp:
     36        (WebCore::CalcExpressionOperation::evaluate const):
     37        Return converted to degrees based on spec: https://drafts.csswg.org/css-values-4/#trig-funcs.
     38        * platform/calc/CalcOperator.cpp:
     39        (WebCore::operator<<):
     40        * platform/calc/CalcOperator.h:
     41
    1422021-09-23  Tim Horton  <timothy_horton@apple.com>
    243
  • trunk/Source/WebCore/css/CSSValueKeywords.in

    r282851 r283013  
    13541354exp
    13551355log
     1356asin
     1357acos
     1358atan
     1359atan2
    13561360
    13571361from-image
  • trunk/Source/WebCore/css/calc/CSSCalcExpressionNodeParser.cpp

    r282795 r283013  
    138138    case CSSValueCos:
    139139    case CSSValueTan:
     140   
     141    case CSSValueAcos:
     142    case CSSValueAsin:
     143    case CSSValueAtan:
    140144    case CSSValueCalc:
    141145        maxArgumentCount = 1;
    142146        break;
    143     // TODO: clamp, sin, cos, tan, asin, acos, atan, atan2, pow, sqrt, hypot.
     147    case CSSValueAtan2:
     148        maxArgumentCount = 2;
     149        break;
     150    // TODO: pow, sqrt, hypot.
    144151    default:
    145152        break;
     
    199206        result = CSSCalcOperationNode::createExp(WTFMove(nodes));
    200207        break;
    201     // TODO: clamp, sin, cos, tan, asin, acos, atan, atan2, pow, sqrt, hypot
     208    case CSSValueAcos:
     209        result = CSSCalcOperationNode::createInverseTrig(CalcOperator::Acos, WTFMove(nodes));
     210        break;
     211    case CSSValueAsin:
     212        result = CSSCalcOperationNode::createInverseTrig(CalcOperator::Asin, WTFMove(nodes));
     213        break;
     214    case CSSValueAtan:
     215        result = CSSCalcOperationNode::createInverseTrig(CalcOperator::Atan, WTFMove(nodes));
     216        break;
     217    case CSSValueAtan2:
     218        result = CSSCalcOperationNode::createAtan2(WTFMove(nodes));
     219        break;
     220    // TODO: pow, sqrt, hypot
    202221    default:
    203222        break;
  • trunk/Source/WebCore/css/calc/CSSCalcOperationNode.cpp

    r282795 r283013  
    8282    case CalcOperator::Log:
    8383    case CalcOperator::Exp:
     84    case CalcOperator::Asin:
     85    case CalcOperator::Acos:
     86    case CalcOperator::Atan:
     87    case CalcOperator::Atan2:
    8488        ASSERT_NOT_REACHED();
    8589        return CalculationCategory::Other;
     
    155159        case CalcOperator::Log:
    156160        case CalcOperator::Exp:
     161        case CalcOperator::Asin:
     162        case CalcOperator::Acos:
     163        case CalcOperator::Atan:
     164        case CalcOperator::Atan2:
    157165            // The type of a min(), max(), or clamp() expression is the result of adding the types of its comma-separated calculations
    158166            return CalculationCategory::Other;
     
    276284    case CalcOperator::Log:
    277285        return CSSValueLog;
     286    case CalcOperator::Asin:
     287        return CSSValueAsin;
     288    case CalcOperator::Acos:
     289        return CSSValueAcos;
     290    case CalcOperator::Atan:
     291        return CSSValueAtan;
     292    case CalcOperator::Atan2:
     293        return CSSValueAtan2;
    278294    }
    279295    return CSSValueCalc;
     
    312328
    313329    return adoptRef(new CSSCalcOperationNode(newCategory, CalcOperator::Add, WTFMove(values)));
     330}
     331
     332RefPtr<CSSCalcOperationNode> CSSCalcOperationNode::createInverseTrig(CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& values)
     333{
     334    if (values.size() != 1)
     335        return nullptr;
     336
     337    auto childCategory = values[0]->category();
     338    if (childCategory != CalculationCategory::Number) {
     339        LOG_WITH_STREAM(Calc, stream << "Failed to create trig node because unable to determine category from " << prettyPrintNodes(values));
     340        return nullptr;
     341    }
     342
     343    return adoptRef(new CSSCalcOperationNode(CalculationCategory::Angle, op, WTFMove(values)));
     344}
     345
     346RefPtr<CSSCalcOperationNode> CSSCalcOperationNode::createAtan2(Vector<Ref<CSSCalcExpressionNode>>&& values)
     347{
     348    if (values.size() != 2)
     349        return nullptr;
     350
     351    auto child1Category = values[0]->category();
     352    auto child2Category = values[1]->category();
     353    if (child1Category != child2Category) {
     354        LOG_WITH_STREAM(Calc, stream << "Failed to create atan2 node because unable to determine category from " << prettyPrintNodes(values));
     355        return nullptr;
     356    }
     357    return adoptRef(new CSSCalcOperationNode(CalculationCategory::Angle, CalcOperator::Atan2, WTFMove(values)));
    314358}
    315359
     
    485529            double resolvedValue = doubleValue(m_children[0]->primitiveType());
    486530            auto newChild = CSSCalcPrimitiveValueNode::create(CSSPrimitiveValue::create(resolvedValue, CSSUnitType::CSS_NUMBER));
    487 
     531            m_children.clear();
     532            m_children.append(WTFMove(newChild));
     533        }
     534       
     535        if (m_children.size() == 1 && isInverseTrigNode()) {
     536            double resolvedValue = doubleValue(m_children[0]->primitiveType());
     537            auto newChild = CSSCalcPrimitiveValueNode::create(CSSPrimitiveValue::create(resolvedValue, CSSUnitType::CSS_DEG));
    488538            m_children.clear();
    489539            m_children.append(WTFMove(newChild));
     
    622672        m_children.append(WTFMove(newChild));
    623673    }
     674   
     675    if (calcOperator() == CalcOperator::Atan2) {
     676        double resolvedValue = doubleValue(m_children[0]->primitiveType());
     677        auto newChild = CSSCalcPrimitiveValueNode::create(CSSPrimitiveValue::create(resolvedValue, CSSUnitType::CSS_DEG));
     678        m_children.clear();
     679        m_children.append(WTFMove(newChild));
     680    }
    624681}
    625682
     
    680737        auto& calcOperationNode = downcast<CSSCalcOperationNode>(rootNode.get());
    681738        // Simplify operations with only one child node (other than root and operations that only need one node).
    682         if (calcOperationNode.children().size() == 1 && depth && !calcOperationNode.isTrigNode() && !calcOperationNode.isExpNode())
     739        if (calcOperationNode.children().size() == 1 && depth && !calcOperationNode.isTrigNode() && !calcOperationNode.isExpNode() && !calcOperationNode.isInverseTrigNode())
    683740            return WTFMove(calcOperationNode.children()[0]);
    684741       
     
    702759            calcOperationNode.combineChildren();
    703760       
     761        if (calcOperationNode.isInverseTrigNode() && depth)
     762            calcOperationNode.combineChildren();
     763       
     764        if (calcOperationNode.isAtan2Node() && depth)
     765            calcOperationNode.combineChildren();
     766
    704767        // If only one child remains, return the child (except at the root).
    705768        auto shouldCombineParentWithOnlyChild = [](const CSSCalcOperationNode& parent, int depth)
     
    789852    case CalculationCategory::Time:
    790853    case CalculationCategory::Frequency:
    791         if (m_children.size() == 1)
     854        if (m_children.size() == 1 && !isInverseTrigNode())
    792855            return m_children.first()->primitiveType();
    793856        return canonicalUnitTypeForCalculationCategory(unitCategory);
     
    835898        if (isTrigNode() && unitType != CSSUnitType::CSS_NUMBER)
    836899            childType = CSSUnitType::CSS_RAD;
     900        if (isInverseTrigNode())
     901            childType = CSSUnitType::CSS_NUMBER;
     902        if (isAtan2Node())
     903            childType = child->primitiveType();
    837904        return child->doubleValue(childType);
    838905    }));
     
    895962    case CalcOperator::Exp: return "exp(";
    896963    case CalcOperator::Log: return "log(";
     964    case CalcOperator::Asin: return "asin(";
     965    case CalcOperator::Acos: return "acos(";
     966    case CalcOperator::Atan: return "atan(";
     967    case CalcOperator::Atan2: return "atan2(";
    897968    }
    898969   
     
    11231194        return std::exp(children[0]);
    11241195    }
     1196    case CalcOperator::Asin: {
     1197        if (children.size() != 1)
     1198            return std::numeric_limits<double>::quiet_NaN();
     1199        return rad2deg(std::asin(children[0]));
     1200    }
     1201    case CalcOperator::Acos: {
     1202        if (children.size() != 1)
     1203            return std::numeric_limits<double>::quiet_NaN();
     1204        return rad2deg(std::acos(children[0]));
     1205    }
     1206    case CalcOperator::Atan: {
     1207        if (children.size() != 1)
     1208            return std::numeric_limits<double>::quiet_NaN();
     1209        return rad2deg(std::atan(children[0]));
     1210    }
     1211    case CalcOperator::Atan2: {
     1212        if (children.size() != 2)
     1213            return std::numeric_limits<double>::quiet_NaN();
     1214        return rad2deg(atan2(children[0], children[1]));
     1215    }
    11251216    }
    11261217    ASSERT_NOT_REACHED();
  • trunk/Source/WebCore/css/calc/CSSCalcOperationNode.h

    r282795 r283013  
    4141    static RefPtr<CSSCalcOperationNode> createLog(Vector<Ref<CSSCalcExpressionNode>>&& values);
    4242    static RefPtr<CSSCalcOperationNode> createExp(Vector<Ref<CSSCalcExpressionNode>>&& values);
     43    static RefPtr<CSSCalcOperationNode> createInverseTrig(CalcOperator, Vector<Ref<CSSCalcExpressionNode>>&& values);
     44    static RefPtr<CSSCalcOperationNode> createAtan2(Vector<Ref<CSSCalcExpressionNode>>&& values);
    4345
    4446    static Ref<CSSCalcExpressionNode> simplify(Ref<CSSCalcExpressionNode>&&);
     
    5254    bool isTrigNode() const { return m_operator == CalcOperator::Sin || m_operator == CalcOperator::Cos || m_operator == CalcOperator::Tan; }
    5355    bool isExpNode() const { return m_operator == CalcOperator::Exp || m_operator == CalcOperator::Log; }
     56    bool isInverseTrigNode() const { return m_operator == CalcOperator::Asin || m_operator == CalcOperator::Acos || m_operator == CalcOperator::Atan; }
     57    bool isAtan2Node() const { return m_operator == CalcOperator::Atan2; }
    5458    bool shouldSortChildren() const { return isCalcSumNode() || isCalcProductNode(); }
    5559
  • trunk/Source/WebCore/css/calc/CSSCalcValue.cpp

    r282795 r283013  
    193193            return CSSCalcOperationNode::createExp(WTFMove(children));
    194194        }
     195        case CalcOperator::Asin:
     196        case CalcOperator::Acos:
     197        case CalcOperator::Atan: {
     198            auto children = createCSS(operationChildren, style);
     199            if (children.size() != 1)
     200                return nullptr;
     201            return CSSCalcOperationNode::createInverseTrig(op, WTFMove(children));
     202        }
     203        case CalcOperator::Atan2: {
     204            auto children = createCSS(operationChildren, style);
     205            if (children.size() != 2)
     206                return nullptr;
     207            return CSSCalcOperationNode::createAtan2(WTFMove(children));
     208        }
    195209        }
    196210        return nullptr;
     
    309323    case CSSValueExp:
    310324    case CSSValueLog:
     325    case CSSValueAsin:
     326    case CSSValueAcos:
     327    case CSSValueAtan:
     328    case CSSValueAtan2:
    311329        return true;
    312330    default:
  • trunk/Source/WebCore/platform/calc/CalcExpressionOperation.cpp

    r282795 r283013  
    115115        return std::exp(m_children[0]->evaluate(maxValue));
    116116    }
     117    case CalcOperator::Asin: {
     118        if (m_children.size() != 1)
     119            return std::numeric_limits<float>::quiet_NaN();
     120        return rad2deg(std::asin(m_children[0]->evaluate(maxValue)));
     121    }
     122    case CalcOperator::Acos: {
     123        if (m_children.size() != 1)
     124            return std::numeric_limits<float>::quiet_NaN();
     125        return rad2deg(std::acos(m_children[0]->evaluate(maxValue)));
     126    }
     127    case CalcOperator::Atan: {
     128        if (m_children.size() != 1)
     129            return std::numeric_limits<float>::quiet_NaN();
     130        return rad2deg(std::atan(m_children[0]->evaluate(maxValue)));
     131    }
     132    case CalcOperator::Atan2: {
     133        if (m_children.size() != 2)
     134            return std::numeric_limits<float>::quiet_NaN();
     135        return rad2deg(atan2(m_children[0]->evaluate(maxValue), m_children[1]->evaluate(maxValue)));
     136    }
    117137    }
    118138    ASSERT_NOT_REACHED();
  • trunk/Source/WebCore/platform/calc/CalcOperator.cpp

    r282795 r283013  
    4646    case CalcOperator::Exp: ts << "exp"; break;
    4747    case CalcOperator::Log: ts << "log"; break;
     48    case CalcOperator::Asin: ts << "asin"; break;
     49    case CalcOperator::Acos: ts << "acos"; break;
     50    case CalcOperator::Atan: ts << "atan"; break;
     51    case CalcOperator::Atan2: ts << "atan2"; break;
    4852    }
    4953    return ts;
  • trunk/Source/WebCore/platform/calc/CalcOperator.h

    r282795 r283013  
    4444    Exp,
    4545    Log,
     46    Asin,
     47    Acos,
     48    Atan,
     49    Atan2,
    4650};
    4751
Note: See TracChangeset for help on using the changeset viewer.