Home | History | Annotate | Download | only in resolver
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde (at) carewolf.com)
      4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit (at) nickshanks.com)
      5  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
      6  * Copyright (C) 2007 Alexey Proskuryakov <ap (at) webkit.org>
      7  * Copyright (C) 2007, 2008 Eric Seidel <eric (at) webkit.org>
      8  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
      9  * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
     10  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
     11  * Copyright (C) 2012 Google Inc. All rights reserved.
     12  *
     13  * This library is free software; you can redistribute it and/or
     14  * modify it under the terms of the GNU Library General Public
     15  * License as published by the Free Software Foundation; either
     16  * version 2 of the License, or (at your option) any later version.
     17  *
     18  * This library is distributed in the hope that it will be useful,
     19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     21  * Library General Public License for more details.
     22  *
     23  * You should have received a copy of the GNU Library General Public License
     24  * along with this library; see the file COPYING.LIB.  If not, write to
     25  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     26  * Boston, MA 02110-1301, USA.
     27  */
     28 
     29 #include "config.h"
     30 #include "core/css/resolver/FilterOperationResolver.h"
     31 
     32 #include "core/css/CSSFilterValue.h"
     33 #include "core/css/CSSPrimitiveValueMappings.h"
     34 #include "core/css/CSSShadowValue.h"
     35 #include "core/css/resolver/TransformBuilder.h"
     36 #include "core/rendering/svg/ReferenceFilterBuilder.h"
     37 #include "core/svg/SVGURIReference.h"
     38 
     39 namespace blink {
     40 
     41 static FilterOperation::OperationType filterOperationForType(CSSFilterValue::FilterOperationType type)
     42 {
     43     switch (type) {
     44     case CSSFilterValue::ReferenceFilterOperation:
     45         return FilterOperation::REFERENCE;
     46     case CSSFilterValue::GrayscaleFilterOperation:
     47         return FilterOperation::GRAYSCALE;
     48     case CSSFilterValue::SepiaFilterOperation:
     49         return FilterOperation::SEPIA;
     50     case CSSFilterValue::SaturateFilterOperation:
     51         return FilterOperation::SATURATE;
     52     case CSSFilterValue::HueRotateFilterOperation:
     53         return FilterOperation::HUE_ROTATE;
     54     case CSSFilterValue::InvertFilterOperation:
     55         return FilterOperation::INVERT;
     56     case CSSFilterValue::OpacityFilterOperation:
     57         return FilterOperation::OPACITY;
     58     case CSSFilterValue::BrightnessFilterOperation:
     59         return FilterOperation::BRIGHTNESS;
     60     case CSSFilterValue::ContrastFilterOperation:
     61         return FilterOperation::CONTRAST;
     62     case CSSFilterValue::BlurFilterOperation:
     63         return FilterOperation::BLUR;
     64     case CSSFilterValue::DropShadowFilterOperation:
     65         return FilterOperation::DROP_SHADOW;
     66     case CSSFilterValue::UnknownFilterOperation:
     67         return FilterOperation::NONE;
     68     }
     69     return FilterOperation::NONE;
     70 }
     71 
     72 bool FilterOperationResolver::createFilterOperations(CSSValue* inValue, const CSSToLengthConversionData& unadjustedConversionData, FilterOperations& outOperations, StyleResolverState& state)
     73 {
     74     ASSERT(outOperations.isEmpty());
     75 
     76     if (!inValue)
     77         return false;
     78 
     79     if (inValue->isPrimitiveValue()) {
     80         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(inValue);
     81         if (primitiveValue->getValueID() == CSSValueNone)
     82             return true;
     83     }
     84 
     85     if (!inValue->isValueList())
     86         return false;
     87 
     88     float zoomFactor = unadjustedConversionData.zoom();
     89     const CSSToLengthConversionData& conversionData = unadjustedConversionData.copyWithAdjustedZoom(zoomFactor);
     90     FilterOperations operations;
     91     for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) {
     92         CSSValue* currValue = i.value();
     93         if (!currValue->isFilterValue())
     94             continue;
     95 
     96         CSSFilterValue* filterValue = toCSSFilterValue(i.value());
     97         FilterOperation::OperationType operationType = filterOperationForType(filterValue->operationType());
     98 
     99         if (operationType == FilterOperation::REFERENCE) {
    100             if (filterValue->length() != 1)
    101                 continue;
    102             CSSValue* argument = filterValue->item(0);
    103 
    104             if (!argument->isSVGDocumentValue())
    105                 continue;
    106 
    107             CSSSVGDocumentValue* svgDocumentValue = toCSSSVGDocumentValue(argument);
    108             KURL url = state.document().completeURL(svgDocumentValue->url());
    109 
    110             RefPtr<ReferenceFilterOperation> operation = ReferenceFilterOperation::create(svgDocumentValue->url(), AtomicString(url.fragmentIdentifier()));
    111             if (SVGURIReference::isExternalURIReference(svgDocumentValue->url(), state.document())) {
    112                 if (!svgDocumentValue->loadRequested())
    113                     state.elementStyleResources().addPendingSVGDocument(operation.get(), svgDocumentValue);
    114                 else if (svgDocumentValue->cachedSVGDocument())
    115                     ReferenceFilterBuilder::setDocumentResourceReference(operation.get(), adoptPtr(new DocumentResourceReference(svgDocumentValue->cachedSVGDocument())));
    116             }
    117             operations.operations().append(operation);
    118             continue;
    119         }
    120 
    121         // Check that all parameters are primitive values, with the
    122         // exception of drop shadow which has a CSSShadowValue parameter.
    123         if (operationType != FilterOperation::DROP_SHADOW) {
    124             bool haveNonPrimitiveValue = false;
    125             for (unsigned j = 0; j < filterValue->length(); ++j) {
    126                 if (!filterValue->item(j)->isPrimitiveValue()) {
    127                     haveNonPrimitiveValue = true;
    128                     break;
    129                 }
    130             }
    131             if (haveNonPrimitiveValue)
    132                 continue;
    133         }
    134 
    135         CSSPrimitiveValue* firstValue = filterValue->length() && filterValue->item(0)->isPrimitiveValue() ? toCSSPrimitiveValue(filterValue->item(0)) : 0;
    136         switch (filterValue->operationType()) {
    137         case CSSFilterValue::GrayscaleFilterOperation:
    138         case CSSFilterValue::SepiaFilterOperation:
    139         case CSSFilterValue::SaturateFilterOperation: {
    140             double amount = 1;
    141             if (filterValue->length() == 1) {
    142                 amount = firstValue->getDoubleValue();
    143                 if (firstValue->isPercentage())
    144                     amount /= 100;
    145             }
    146 
    147             operations.operations().append(BasicColorMatrixFilterOperation::create(amount, operationType));
    148             break;
    149         }
    150         case CSSFilterValue::HueRotateFilterOperation: {
    151             double angle = 0;
    152             if (filterValue->length() == 1)
    153                 angle = firstValue->computeDegrees();
    154 
    155             operations.operations().append(BasicColorMatrixFilterOperation::create(angle, operationType));
    156             break;
    157         }
    158         case CSSFilterValue::InvertFilterOperation:
    159         case CSSFilterValue::BrightnessFilterOperation:
    160         case CSSFilterValue::ContrastFilterOperation:
    161         case CSSFilterValue::OpacityFilterOperation: {
    162             double amount = (filterValue->operationType() == CSSFilterValue::BrightnessFilterOperation) ? 0 : 1;
    163             if (filterValue->length() == 1) {
    164                 amount = firstValue->getDoubleValue();
    165                 if (firstValue->isPercentage())
    166                     amount /= 100;
    167             }
    168 
    169             operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType));
    170             break;
    171         }
    172         case CSSFilterValue::BlurFilterOperation: {
    173             Length stdDeviation = Length(0, Fixed);
    174             if (filterValue->length() >= 1)
    175                 stdDeviation = firstValue->convertToLength<FixedConversion | PercentConversion>(conversionData);
    176             operations.operations().append(BlurFilterOperation::create(stdDeviation));
    177             break;
    178         }
    179         case CSSFilterValue::DropShadowFilterOperation: {
    180             if (filterValue->length() != 1)
    181                 return false;
    182 
    183             CSSValue* cssValue = filterValue->item(0);
    184             if (!cssValue->isShadowValue())
    185                 continue;
    186 
    187             CSSShadowValue* item = toCSSShadowValue(cssValue);
    188             IntPoint location(item->x->computeLength<int>(conversionData), item->y->computeLength<int>(conversionData));
    189             int blur = item->blur ? item->blur->computeLength<int>(conversionData) : 0;
    190             Color shadowColor = Color::transparent;
    191             if (item->color)
    192                 shadowColor = state.document().textLinkColors().colorFromPrimitiveValue(item->color.get(), state.style()->color());
    193 
    194             operations.operations().append(DropShadowFilterOperation::create(location, blur, shadowColor));
    195             break;
    196         }
    197         case CSSFilterValue::UnknownFilterOperation:
    198         default:
    199             ASSERT_NOT_REACHED();
    200             break;
    201         }
    202     }
    203 
    204     outOperations = operations;
    205     return true;
    206 }
    207 
    208 } // namespace blink
    209