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/parser/BisonCSSParser.h"
     34 #include "core/css/CSSPrimitiveValueMappings.h"
     35 #include "core/css/CSSShadowValue.h"
     36 #include "core/css/resolver/TransformBuilder.h"
     37 #include "core/rendering/svg/ReferenceFilterBuilder.h"
     38 #include "core/svg/SVGURIReference.h"
     39 
     40 namespace WebCore {
     41 
     42 static FilterOperation::OperationType filterOperationForType(CSSFilterValue::FilterOperationType type)
     43 {
     44     switch (type) {
     45     case CSSFilterValue::ReferenceFilterOperation:
     46         return FilterOperation::REFERENCE;
     47     case CSSFilterValue::GrayscaleFilterOperation:
     48         return FilterOperation::GRAYSCALE;
     49     case CSSFilterValue::SepiaFilterOperation:
     50         return FilterOperation::SEPIA;
     51     case CSSFilterValue::SaturateFilterOperation:
     52         return FilterOperation::SATURATE;
     53     case CSSFilterValue::HueRotateFilterOperation:
     54         return FilterOperation::HUE_ROTATE;
     55     case CSSFilterValue::InvertFilterOperation:
     56         return FilterOperation::INVERT;
     57     case CSSFilterValue::OpacityFilterOperation:
     58         return FilterOperation::OPACITY;
     59     case CSSFilterValue::BrightnessFilterOperation:
     60         return FilterOperation::BRIGHTNESS;
     61     case CSSFilterValue::ContrastFilterOperation:
     62         return FilterOperation::CONTRAST;
     63     case CSSFilterValue::BlurFilterOperation:
     64         return FilterOperation::BLUR;
     65     case CSSFilterValue::DropShadowFilterOperation:
     66         return FilterOperation::DROP_SHADOW;
     67     case CSSFilterValue::UnknownFilterOperation:
     68         return FilterOperation::NONE;
     69     }
     70     return FilterOperation::NONE;
     71 }
     72 
     73 bool FilterOperationResolver::createFilterOperations(CSSValue* inValue, const CSSToLengthConversionData& unadjustedConversionData, FilterOperations& outOperations, StyleResolverState& state)
     74 {
     75     ASSERT(outOperations.isEmpty());
     76 
     77     if (!inValue)
     78         return false;
     79 
     80     if (inValue->isPrimitiveValue()) {
     81         CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(inValue);
     82         if (primitiveValue->getValueID() == CSSValueNone)
     83             return true;
     84     }
     85 
     86     if (!inValue->isValueList())
     87         return false;
     88 
     89 #ifdef BLINK_SCALE_FILTERS_AT_RECORD_TIME
     90     float zoomFactor = unadjustedConversionData.zoom() * state.elementStyleResources().deviceScaleFactor();
     91 #else
     92     float zoomFactor = unadjustedConversionData.zoom();
     93 #endif
     94     const CSSToLengthConversionData& conversionData = unadjustedConversionData.copyWithAdjustedZoom(zoomFactor);
     95     FilterOperations operations;
     96     for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) {
     97         CSSValue* currValue = i.value();
     98         if (!currValue->isFilterValue())
     99             continue;
    100 
    101         CSSFilterValue* filterValue = toCSSFilterValue(i.value());
    102         FilterOperation::OperationType operationType = filterOperationForType(filterValue->operationType());
    103 
    104         if (operationType == FilterOperation::REFERENCE) {
    105             if (filterValue->length() != 1)
    106                 continue;
    107             CSSValue* argument = filterValue->itemWithoutBoundsCheck(0);
    108 
    109             if (!argument->isSVGDocumentValue())
    110                 continue;
    111 
    112             CSSSVGDocumentValue* svgDocumentValue = toCSSSVGDocumentValue(argument);
    113             KURL url = state.document().completeURL(svgDocumentValue->url());
    114 
    115             RefPtr<ReferenceFilterOperation> operation = ReferenceFilterOperation::create(svgDocumentValue->url(), AtomicString(url.fragmentIdentifier()));
    116             if (SVGURIReference::isExternalURIReference(svgDocumentValue->url(), state.document())) {
    117                 if (!svgDocumentValue->loadRequested())
    118                     state.elementStyleResources().addPendingSVGDocument(operation.get(), svgDocumentValue);
    119                 else if (svgDocumentValue->cachedSVGDocument())
    120                     ReferenceFilterBuilder::setDocumentResourceReference(operation.get(), adoptPtr(new DocumentResourceReference(svgDocumentValue->cachedSVGDocument())));
    121             }
    122             operations.operations().append(operation);
    123             continue;
    124         }
    125 
    126         // Check that all parameters are primitive values, with the
    127         // exception of drop shadow which has a CSSShadowValue parameter.
    128         if (operationType != FilterOperation::DROP_SHADOW) {
    129             bool haveNonPrimitiveValue = false;
    130             for (unsigned j = 0; j < filterValue->length(); ++j) {
    131                 if (!filterValue->itemWithoutBoundsCheck(j)->isPrimitiveValue()) {
    132                     haveNonPrimitiveValue = true;
    133                     break;
    134                 }
    135             }
    136             if (haveNonPrimitiveValue)
    137                 continue;
    138         }
    139 
    140         CSSPrimitiveValue* firstValue = filterValue->length() && filterValue->itemWithoutBoundsCheck(0)->isPrimitiveValue() ? toCSSPrimitiveValue(filterValue->itemWithoutBoundsCheck(0)) : 0;
    141         switch (filterValue->operationType()) {
    142         case CSSFilterValue::GrayscaleFilterOperation:
    143         case CSSFilterValue::SepiaFilterOperation:
    144         case CSSFilterValue::SaturateFilterOperation: {
    145             double amount = 1;
    146             if (filterValue->length() == 1) {
    147                 amount = firstValue->getDoubleValue();
    148                 if (firstValue->isPercentage())
    149                     amount /= 100;
    150             }
    151 
    152             operations.operations().append(BasicColorMatrixFilterOperation::create(amount, operationType));
    153             break;
    154         }
    155         case CSSFilterValue::HueRotateFilterOperation: {
    156             double angle = 0;
    157             if (filterValue->length() == 1)
    158                 angle = firstValue->computeDegrees();
    159 
    160             operations.operations().append(BasicColorMatrixFilterOperation::create(angle, operationType));
    161             break;
    162         }
    163         case CSSFilterValue::InvertFilterOperation:
    164         case CSSFilterValue::BrightnessFilterOperation:
    165         case CSSFilterValue::ContrastFilterOperation:
    166         case CSSFilterValue::OpacityFilterOperation: {
    167             double amount = (filterValue->operationType() == CSSFilterValue::BrightnessFilterOperation) ? 0 : 1;
    168             if (filterValue->length() == 1) {
    169                 amount = firstValue->getDoubleValue();
    170                 if (firstValue->isPercentage())
    171                     amount /= 100;
    172             }
    173 
    174             operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType));
    175             break;
    176         }
    177         case CSSFilterValue::BlurFilterOperation: {
    178             Length stdDeviation = Length(0, Fixed);
    179             if (filterValue->length() >= 1)
    180                 stdDeviation = firstValue->convertToLength<FixedConversion | PercentConversion>(conversionData);
    181             operations.operations().append(BlurFilterOperation::create(stdDeviation));
    182             break;
    183         }
    184         case CSSFilterValue::DropShadowFilterOperation: {
    185             if (filterValue->length() != 1)
    186                 return false;
    187 
    188             CSSValue* cssValue = filterValue->itemWithoutBoundsCheck(0);
    189             if (!cssValue->isShadowValue())
    190                 continue;
    191 
    192             CSSShadowValue* item = toCSSShadowValue(cssValue);
    193             IntPoint location(item->x->computeLength<int>(conversionData), item->y->computeLength<int>(conversionData));
    194             int blur = item->blur ? item->blur->computeLength<int>(conversionData) : 0;
    195             Color shadowColor = Color::transparent;
    196             if (item->color)
    197                 shadowColor = state.document().textLinkColors().colorFromPrimitiveValue(item->color.get(), state.style()->color());
    198 
    199             operations.operations().append(DropShadowFilterOperation::create(location, blur, shadowColor));
    200             break;
    201         }
    202         case CSSFilterValue::UnknownFilterOperation:
    203         default:
    204             ASSERT_NOT_REACHED();
    205             break;
    206         }
    207     }
    208 
    209     outOperations = operations;
    210     return true;
    211 }
    212 
    213 } // namespace WebCore
    214