text: /*
   * Copyright 2020 Google Inc.
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #include "include/core/SkColorFilter.h"
  #include "include/effects/SkImageFilters.h"
  #include "include/private/SkColorData.h"
  #include "modules/svg/include/SkSVGAttributeParser.h"
  #include "modules/svg/include/SkSVGFeColorMatrix.h"
  #include "modules/svg/include/SkSVGFilterContext.h"
  #include "modules/svg/include/SkSVGRenderContext.h"
  #include "modules/svg/include/SkSVGValue.h"
  
  bool SkSVGFeColorMatrix::parseAndSetAttribute(const char* name, const char* value) {
      return INHERITED::parseAndSetAttribute(name, value) ||
             this->setType(
                     SkSVGAttributeParser::parse<SkSVGFeColorMatrixType>("type", name, value)) ||
             this->setValues(
                     SkSVGAttributeParser::parse<SkSVGFeColorMatrixValues>("values", name, value));
  }
  
  SkColorMatrix SkSVGFeColorMatrix::makeMatrixForType() const {
      if (fValues.empty() && fType != SkSVGFeColorMatrixType::kLuminanceToAlpha) {
          return SkColorMatrix();
      }
  
      switch (fType) {
          case SkSVGFeColorMatrixType::kMatrix: {
              if (fValues.count() < 20) {
                  return SkColorMatrix();
              }
              SkColorMatrix m;
              m.setRowMajor(this->fValues.begin());
              return m;
          }
          case SkSVGFeColorMatrixType::kSaturate:
              return MakeSaturate(fValues.count() > 0 ? fValues[0] : 1);
          case SkSVGFeColorMatrixType::kHueRotate:
              return MakeHueRotate(fValues.count() > 0 ? fValues[0] : 0);
          case SkSVGFeColorMatrixType::kLuminanceToAlpha:
              return MakeLuminanceToAlpha();
      }
  
      SkUNREACHABLE;
  }
  
  SkColorMatrix SkSVGFeColorMatrix::MakeSaturate(SkSVGNumberType s) {
      SkColorMatrix m;
      m.setSaturation(s);
      return m;
  }
  
  SkColorMatrix SkSVGFeColorMatrix::MakeHueRotate(SkSVGNumberType degrees) {
      const SkScalar theta = SkDegreesToRadians(degrees);
      const SkSVGNumberType c = SkScalarCos(theta);
      const SkSVGNumberType s = SkScalarSin(theta);
      return SkColorMatrix(
          0.213f + c* 0.787f + s*-0.213f,
          0.715f + c*-0.715f + s*-0.715f,
          0.072f + c*-0.072f + s* 0.928f,
          0,
          0,
  
          0.213f + c*-0.213f + s* 0.143f,
          0.715f + c* 0.285f + s* 0.140f,
          0.072f + c*-0.072f + s*-0.283f,
          0,
          0,
  
          0.213f + c*-0.213f + s*-0.787f,
          0.715f + c*-0.715f + s* 0.715f,
          0.072f + c* 0.928f + s* 0.072f,
          0,
          0,
  
          0,0,0,1,0
      );
  }
  
  SkColorMatrix SkSVGFeColorMatrix::MakeLuminanceToAlpha() {
      return SkColorMatrix(
          0, 0, 0, 0, 0,
          0, 0, 0, 0, 0,
          0, 0, 0, 0, 0,
          SK_LUM_COEFF_R, SK_LUM_COEFF_G, SK_LUM_COEFF_B, 0, 0
      );
  }
  
  sk_sp<SkImageFilter> SkSVGFeColorMatrix::onMakeImageFilter(const SkSVGRenderContext& ctx,
                                                             const SkSVGFilterContext& fctx) const {
      return SkImageFilters::ColorFilter(SkColorFilters::Matrix(makeMatrixForType()),
                                         fctx.resolveInput(ctx, this->getIn()),
                                         this->resolveFilterSubregion(ctx, fctx));
  }
  
  template <> bool SkSVGAttributeParser::parse(SkSVGFeColorMatrixValues* values) {
      SkSVGNumberType value;
      if (!this->parse(&value)) {
          return false;
      }
  
      values->push_back(value);
      while (true) {
          if (!this->parse(&value) || values->count() >= 20) {
              break;
          }
          values->push_back(value);
      }
  
      return this->parseEOSToken();
  }
  
  template <> bool SkSVGAttributeParser::parse(SkSVGFeColorMatrixType* type) {
      static constexpr std::tuple<const char*, SkSVGFeColorMatrixType> gTypeMap[] = {
              {"matrix", SkSVGFeColorMatrixType::kMatrix},
              {"saturate", SkSVGFeColorMatrixType::kSaturate},
              {"hueRotate", SkSVGFeColorMatrixType::kHueRotate},
              {"luminanceToAlpha", SkSVGFeColorMatrixType::kLuminanceToAlpha},
      };
  
      return this->parseEnumMap(gTypeMap, type) && this->parseEOSToken();
  }
  