text: /*
   * Copyright (C) 2016 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. 
   */
  
  #pragma once
  
  #include "FloatRect.h"
  #include "GraphicsContext.h"
  #include <wtf/FastMalloc.h>
  #include <wtf/Noncopyable.h>
  #include <wtf/text/WTFString.h>
  
  namespace WTF {
  class TextStream;
  }
  
  namespace WebCore {
  
  namespace DisplayList {
  
  enum class ItemType : uint8_t {
      Save,
      Restore,
      Translate,
      Rotate,
      Scale,
      ConcatenateCTM,
      SetCTM,
      SetState,
      SetLineCap,
      SetLineDash,
      SetLineJoin,
      SetMiterLimit,
      ClearShadow,
      Clip,
      ClipOut,
      ClipOutToPath,
      ClipPath,
      DrawGlyphs,
      DrawImage,
      DrawTiledImage,
      DrawTiledScaledImage,
  #if USE(CG) || USE(CAIRO) || USE(DIRECT2D)
      DrawNativeImage,
  #endif
      DrawPattern,
      DrawRect,
      DrawLine,
      DrawLinesForText,
      DrawDotsForDocumentMarker,
      DrawEllipse,
      DrawPath,
      DrawFocusRingPath,
      DrawFocusRingRects,
      FillRect,
      FillRectWithColor,
      FillRectWithGradient,
      FillCompositedRect,
      FillRoundedRect,
      FillRectWithRoundedHole,
      FillPath,
      FillEllipse,
      PutImageData,
      StrokeRect,
      StrokePath,
      StrokeEllipse,
      ClearRect,
      BeginTransparencyLayer,
      EndTransparencyLayer,
  #if USE(CG)
      ApplyStrokePattern, // FIXME: should not be a recorded item.
      ApplyFillPattern, // FIXME: should not be a recorded item.
  #endif
      ApplyDeviceScaleFactor,
  };
  
  class Item : public RefCounted<Item> {
  public:
      Item() = delete;
  
      WEBCORE_EXPORT Item(ItemType);
      WEBCORE_EXPORT virtual ~Item();
  
      ItemType type() const
      {
          return m_type;
      }
  
      virtual void apply(GraphicsContext&) const = 0;
  
      static constexpr bool isDisplayListItem = true;
  
      virtual bool isDrawingItem() const { return false; }
  
      // A state item is one preserved by Save/Restore.
      bool isStateItem() const
      {
          return isStateItemType(m_type);
      }
  
      static bool isStateItemType(ItemType itemType)
      {
          switch (itemType) {
          case ItemType::Translate:
          case ItemType::Rotate:
          case ItemType::Scale:
          case ItemType::ConcatenateCTM:
          case ItemType::SetCTM:
          case ItemType::SetState:
          case ItemType::SetLineCap:
          case ItemType::SetLineDash:
          case ItemType::SetLineJoin:
          case ItemType::SetMiterLimit:
          case ItemType::ClearShadow:
              return true;
          default:
              return false;
          }
          return false;
      }
  
  #if !defined(NDEBUG) || !LOG_DISABLED
      WTF::CString description() const;
  #endif
      static size_t sizeInBytes(const Item&);
  
      template<class Encoder> void encode(Encoder&) const;
      template<class Decoder> static Optional<Ref<Item>> decode(Decoder&);
  
  private:
      ItemType m_type;
  };
  
  enum AsTextFlag {
      None                            = 0,
      IncludesPlatformOperations      = 1 << 0,
  };
  
  typedef unsigned AsTextFlags;
  
  class DisplayList {
      WTF_MAKE_NONCOPYABLE(DisplayList); WTF_MAKE_FAST_ALLOCATED;
      friend class Recorder;
      friend class Replayer;
  public:
      DisplayList() = default;
      DisplayList(DisplayList&&) = default;
  
      DisplayList& operator=(DisplayList&&) = default;
  
      void dump(WTF::TextStream&) const;
  
      const Vector<Ref<Item>>& list() const { return m_list; }
      Item& itemAt(size_t index)
      {
          ASSERT(index < m_list.size());
          return m_list[index].get();
      }
  
      WEBCORE_EXPORT void clear();
  
      size_t itemCount() const { return m_list.size(); }
      size_t sizeInBytes() const;
      
      String asText(AsTextFlags) const;
  
  #if !defined(NDEBUG) || !LOG_DISABLED
      WTF::CString description() const;
      WEBCORE_EXPORT void dump() const;
  #endif
  
      template<class Encoder> void encode(Encoder&) const;
      template<class Decoder> static Optional<DisplayList> decode(Decoder&);
  
  
  private:
      Item& append(Ref<Item>&& item)
      {
          m_list.append(WTFMove(item));
          return m_list.last().get();
      }
  
      // Less efficient append, only used for tracking replay.
      void appendItem(Item& item)
      {
          m_list.append(item);
      }
  
      static bool shouldDumpForFlags(AsTextFlags, const Item&);
  
      Vector<Ref<Item>>& list() { return m_list; }
  
      Vector<Ref<Item>> m_list;
  };
  
  
  template<class Encoder>
  void DisplayList::encode(Encoder& encoder) const
  {
      encoder << static_cast<uint64_t>(m_list.size());
  
      for (auto& item : m_list)
          encoder << item.get();
  }
  
  template<class Decoder>
  Optional<DisplayList> DisplayList::decode(Decoder& decoder)
  {
      Optional<uint64_t> itemCount;
      decoder >> itemCount;
      if (!itemCount)
          return WTF::nullopt;
  
      DisplayList displayList;
  
      for (uint64_t i = 0; i < *itemCount; i++) {
          auto item = Item::decode(decoder);
          // FIXME: Once we can decode all types, failing to decode an item should turn into a decode failure.
          // For now, we just have to ignore it.
          if (!item)
              continue;
          displayList.append(WTFMove(*item));
      }
  
      return displayList;
  }
  
  } // DisplayList
  
  WTF::TextStream& operator<<(WTF::TextStream&, const DisplayList::DisplayList&);
  
  } // WebCore
  