text: /*
   * Copyright 2020 Google LLC
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #include "gm/gm.h"
  #include "include/core/SkCanvas.h"
  #include "include/core/SkData.h"
  #include "include/core/SkEncodedImageFormat.h"
  #include "include/core/SkImage.h"
  #include "include/core/SkImageInfo.h"
  #include "include/core/SkSize.h"
  #include "include/core/SkString.h"
  #include "include/core/SkSurface.h"
  #include "tools/Resources.h"
  
  namespace skiagm {
  
  static const int imageWidth = 128;
  static const int imageHeight = 128;
  
  static sk_sp<SkImage> make_image(SkColorType colorType, SkAlphaType alphaType) {
      const char* resource;
      switch (colorType) {
          case kGray_8_SkColorType:
              if (alphaType != kOpaque_SkAlphaType) {
                  return nullptr;
              }
              resource = "images/grayscale.jpg";
              break;
          case kRGB_565_SkColorType:
          case kRGB_888x_SkColorType:
          case kRGB_101010x_SkColorType:
          case kBGR_101010x_SkColorType:
              if (alphaType != kOpaque_SkAlphaType) {
                  return nullptr;
              }
              resource = "images/color_wheel.jpg";
              break;
          default:
              resource = (kOpaque_SkAlphaType == alphaType) ? "images/color_wheel.jpg"
                                                            : "images/rainbow-gradient.png";
              break;
      }
  
      auto image = GetResourceAsImage(resource);
      if (!image) {
          return nullptr;
      }
  
      auto surface = SkSurface::MakeRaster(SkImageInfo::Make(image->width(), image->height(),
              colorType, alphaType, image->refColorSpace()));
      surface->getCanvas()->drawImage(image, 0, 0);
      return surface->makeImageSnapshot();
  }
  
  // This GM looks different depending on the colortype used, so we use different
  // names to treat them as different GMs.
  // All Variants draw images in pairs:
  // - First as an image of the SkColorType of the destination
  // - Next as the result of encoding and decoding the first image
  enum class Variant {
      // One pair, using an opaque image.
      kOpaque,
      // One pair, using a grayscale image.
      kGray,
      // An opaque pair followed by two more for premul and unpremul.
      kNormal,
  };
  
  class EncodeColorTypesGM : public GM {
  public:
      EncodeColorTypesGM(SkEncodedImageFormat format, int quality, Variant variant, const char* name)
          : fFormat(format)
          , fQuality(quality)
          , fVariant(variant)
          , fName(name)
      {}
  
  protected:
      SkString onShortName() override {
          const char* variant = fVariant == Variant::kOpaque ? "opaque-":
                                fVariant == Variant::kGray   ? "gray-"  :
                                                               ""       ;
          return SkStringPrintf("encode-%scolor-types-%s", variant, fName);
      }
  
      SkISize onISize() override {
          const int width = fVariant == Variant::kNormal ? imageWidth * 7 : imageWidth * 2;
          return SkISize::Make(width, imageHeight);
      }
  
      DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
          const auto colorType = canvas->imageInfo().colorType();
          switch (fVariant) {
              case Variant::kGray:
                  if (colorType != kGray_8_SkColorType) {
                      return DrawResult::kSkip;
                  }
                  break;
              case Variant::kOpaque:
                  if (colorType != kRGB_565_SkColorType     &&
                      colorType != kRGB_888x_SkColorType    &&
                      colorType != kRGB_101010x_SkColorType &&
                      colorType != kBGR_101010x_SkColorType)
                  {
                      return DrawResult::kSkip;
                  }
                  break;
              case Variant::kNormal:
                  if (colorType != kARGB_4444_SkColorType    &&
                      colorType != kRGBA_8888_SkColorType    &&
                      colorType != kBGRA_8888_SkColorType    &&
                      colorType != kRGBA_1010102_SkColorType &&
                      colorType != kBGRA_1010102_SkColorType &&
                      colorType != kRGBA_F16Norm_SkColorType &&
                      colorType != kRGBA_F16_SkColorType     &&
                      colorType != kRGBA_F32_SkColorType)
                  {
                      return DrawResult::kSkip;
                  }
              break;
          }
          const SkAlphaType alphaTypes[] = {
              kOpaque_SkAlphaType, kPremul_SkAlphaType, kUnpremul_SkAlphaType,
          };
  
          for (SkAlphaType alphaType : alphaTypes) {
              auto src = make_image(colorType, alphaType);
              auto decoded = src ? SkImage::MakeFromEncoded(src->encodeToData(fFormat, fQuality))
                                 : nullptr;
              if (!src || !decoded) {
                  break;
              }
  
              canvas->drawImage(src, 0.0f, 0.0f);
              canvas->translate((float) imageWidth, 0.0f);
  
              canvas->drawImage(decoded, 0.0f, 0.0f);
              canvas->translate((float) imageWidth * 1.5, 0.0f);
          }
          return DrawResult::kOk;
      }
  
  private:
      const SkEncodedImageFormat fFormat;
      const int                  fQuality;
      const Variant              fVariant;
      const char*                fName;
  
      typedef GM INHERITED;
  };
  
  
  #define DEF_ENCODE_GM(format, quality, variant, name) \
      static skiagm::GMRegistry SK_MACRO_CONCAT(SK_MACRO_APPEND_LINE(REG_), variant)(\
              [](){return std::unique_ptr<skiagm::GM>([](){\
                      return new EncodeColorTypesGM(format, quality, Variant::variant, name);\
                  }());});
  
  #define DEF_VARIANTS(format, quality, name)         \
      DEF_ENCODE_GM(format, quality, kNormal, name);  \
      DEF_ENCODE_GM(format, quality, kOpaque, name);  \
      DEF_ENCODE_GM(format, quality, kGray, name);
  
  DEF_VARIANTS(SkEncodedImageFormat::kWEBP, 100, "webp-lossless")
  DEF_VARIANTS(SkEncodedImageFormat::kWEBP,  80, "webp-lossy")
  }
  