text: /*
   * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
   */
  
  #include "config.h"
  #include "FilterOperations.h"
  
  #include "FEGaussianBlur.h"
  #include "IntSize.h"
  #include "LengthFunctions.h"
  #include <wtf/text/TextStream.h>
  
  namespace WebCore {
  
  static inline IntSize outsetSizeForBlur(float stdDeviation)
  {
      auto kernelSize = FEGaussianBlur::calculateUnscaledKernelSize({ stdDeviation, stdDeviation });
  
      // We take the half kernel size and multiply it with three, because we run box blur three times.
      return {
          3 * kernelSize.width() / 2,
          3 * kernelSize.height() / 2
      };
  }
  
  bool FilterOperations::operator==(const FilterOperations& other) const
  {
      size_t size = m_operations.size();
      if (size != other.m_operations.size())
          return false;
      for (size_t i = 0; i < size; i++) {
          if (*m_operations[i] != *other.m_operations[i])
              return false;
      }
      return true;
  }
  
  bool FilterOperations::operationsMatch(const FilterOperations& other) const
  {
      size_t size = operations().size();
      if (size != other.operations().size())
          return false;
      for (size_t i = 0; i < size; ++i) {
          if (!operations()[i]->isSameType(*other.operations()[i]))
              return false;
      }
      return true;
  }
  
  bool FilterOperations::hasReferenceFilter() const
  {
      for (auto& operation : m_operations) {
          if (operation->type() == FilterOperation::REFERENCE)
              return true;
      }
      return false;
  }
  
  bool FilterOperations::hasOutsets() const
  {
      for (auto& operation : m_operations) {
          auto type = operation->type();
          if (type == FilterOperation::BLUR || type == FilterOperation::DROP_SHADOW)
              return true;
      }
      return false;
  }
  
  FilterOutsets FilterOperations::outsets() const
  {
      FilterOutsets totalOutsets;
      for (auto& operation : m_operations) {
          switch (operation->type()) {
          case FilterOperation::BLUR: {
              auto& blurOperation = downcast<BlurFilterOperation>(*operation);
              float stdDeviation = floatValueForLength(blurOperation.stdDeviation(), 0);
              IntSize outsetSize = outsetSizeForBlur(stdDeviation);
              FilterOutsets outsets(outsetSize.height(), outsetSize.width(), outsetSize.height(), outsetSize.width());
              totalOutsets += outsets;
              break;
          }
          case FilterOperation::DROP_SHADOW: {
              auto& dropShadowOperation = downcast<DropShadowFilterOperation>(*operation);
              IntSize outsetSize = outsetSizeForBlur(dropShadowOperation.stdDeviation());
              FilterOutsets outsets {
                  std::max(0, outsetSize.height() - dropShadowOperation.y()),
                  std::max(0, outsetSize.width() + dropShadowOperation.x()),
                  std::max(0, outsetSize.height() + dropShadowOperation.y()),
                  std::max(0, outsetSize.width() - dropShadowOperation.x())
              };
              totalOutsets += outsets;
              break;
          }
          default:
              break;
          }
      }
      return totalOutsets;
  }
  
  bool FilterOperations::hasFilterThatAffectsOpacity() const
  {
      for (auto& operation : m_operations) {
          if (operation->affectsOpacity())
              return true;
      }
      return false;
  }
  
  bool FilterOperations::hasFilterThatMovesPixels() const
  {
      for (auto& operation : m_operations) {
          if (operation->movesPixels())
              return true;
      }
      return false;
  }
  
  bool FilterOperations::hasFilterThatShouldBeRestrictedBySecurityOrigin() const
  {
      for (auto& operation : m_operations) {
          if (operation->shouldBeRestrictedBySecurityOrigin())
              return true;
      }
      return false;
  }
  
  TextStream& operator<<(TextStream& ts, const FilterOperations& filters)
  {
      for (size_t i = 0; i < filters.size(); ++i) {
          auto filter = filters.at(i);
          if (filter)
              ts << *filter;
          else
              ts << "(null)";
          if (i < filters.size() - 1)
              ts << " ";
      }
      return ts;
  }
  
  } // namespace WebCore
  