content: /*
   * Copyright (C) 2010 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.graphics;
  
  import android.annotation.NonNull;
  import android.annotation.Nullable;
  import android.util.Pools.SynchronizedPool;
  import android.view.DisplayListCanvas;
  import android.view.TextureLayer;
  
  import dalvik.annotation.optimization.CriticalNative;
  import dalvik.annotation.optimization.FastNative;
  
  /**
   * A Canvas implementation that records view system drawing operations for deferred rendering.
   * This is used in combination with RenderNode. This class keeps a list of all the Paint and
   * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being released while
   * the RecordingCanvas is still holding a native reference to the memory.
   *
   * This is obtained by calling {@link RenderNode#beginRecording()} and is valid until the matching
   * {@link RenderNode#endRecording()} is called. It must not be retained beyond that as it is
   * internally reused.
   */
  public final class RecordingCanvas extends DisplayListCanvas {
      // The recording canvas pool should be large enough to handle a deeply nested
      // view hierarchy because display lists are generated recursively.
      private static final int POOL_LIMIT = 25;
  
      /** @hide */
      public static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB
  
      private static final SynchronizedPool<RecordingCanvas> sPool =
              new SynchronizedPool<>(POOL_LIMIT);
  
      /**
       * TODO: Temporarily exposed for RenderNodeAnimator(Set)
       * @hide */
      public RenderNode mNode;
      private int mWidth;
      private int mHeight;
  
      /** @hide */
      static RecordingCanvas obtain(@NonNull RenderNode node, int width, int height) {
          if (node == null) throw new IllegalArgumentException("node cannot be null");
          RecordingCanvas canvas = sPool.acquire();
          if (canvas == null) {
              canvas = new RecordingCanvas(node, width, height);
          } else {
              nResetDisplayListCanvas(canvas.mNativeCanvasWrapper, node.mNativeRenderNode,
                      width, height);
          }
          canvas.mNode = node;
          canvas.mWidth = width;
          canvas.mHeight = height;
          return canvas;
      }
  
      /** @hide */
      void recycle() {
          mNode = null;
          sPool.release(this);
      }
  
      /** @hide */
      long finishRecording() {
          return nFinishRecording(mNativeCanvasWrapper);
      }
  
      /** @hide */
      @Override
      public boolean isRecordingFor(Object o) {
          return o == mNode;
      }
  
      ///////////////////////////////////////////////////////////////////////////
      // Constructors
      ///////////////////////////////////////////////////////////////////////////
  
      /** @hide */
      protected RecordingCanvas(@NonNull RenderNode node, int width, int height) {
          super(nCreateDisplayListCanvas(node.mNativeRenderNode, width, height));
          mDensity = 0; // disable bitmap density scaling
      }
  
      ///////////////////////////////////////////////////////////////////////////
      // Canvas management
      ///////////////////////////////////////////////////////////////////////////
  
  
      @Override
      public void setDensity(int density) {
          // drop silently, since RecordingCanvas doesn't perform density scaling
      }
  
      @Override
      public boolean isHardwareAccelerated() {
          return true;
      }
  
      @Override
      public void setBitmap(Bitmap bitmap) {
          throw new UnsupportedOperationException();
      }
  
      @Override
      public boolean isOpaque() {
          return false;
      }
  
      @Override
      public int getWidth() {
          return mWidth;
      }
  
      @Override
      public int getHeight() {
          return mHeight;
      }
  
      @Override
      public int getMaximumBitmapWidth() {
          return nGetMaximumTextureWidth();
      }
  
      @Override
      public int getMaximumBitmapHeight() {
          return nGetMaximumTextureHeight();
      }
  
      ///////////////////////////////////////////////////////////////////////////
      // Setup
      ///////////////////////////////////////////////////////////////////////////
  
      @Override
      public void enableZ() {
          nInsertReorderBarrier(mNativeCanvasWrapper, true);
      }
  
      @Override
      public void disableZ() {
          nInsertReorderBarrier(mNativeCanvasWrapper, false);
      }
  
      ///////////////////////////////////////////////////////////////////////////
      // Functor
      ///////////////////////////////////////////////////////////////////////////
  
      /**
       * Records the functor specified with the drawGLFunction function pointer. This is
       * functionality used by webview for calling into their renderer from our display lists.
       *
       * @param drawGLFunction A native function pointer
       *
       * @hide
       * @deprecated Use {@link #drawWebViewFunctor(int)}
       */
      @Deprecated
      public void callDrawGLFunction2(long drawGLFunction) {
          nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction, null);
      }
  
      /**
       * Records the functor specified with the drawGLFunction function pointer. This is
       * functionality used by webview for calling into their renderer from our display lists.
       *
       * @param drawGLFunctor A native function pointer
       * @param releasedCallback Called when the display list is destroyed, and thus
       * the functor is no longer referenced by this canvas's display list.
       *
       * NOTE: The callback does *not* necessarily mean that there are no longer
       * any references to the functor, just that the reference from this specific
       * canvas's display list has been released.
       *
       * @hide
       * @deprecated Use {@link #drawWebViewFunctor(int)}
       */
      @Deprecated
      public void drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback) {
          nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback);
      }
  
      /**
       * Calls the provided functor that was created via WebViewFunctor_create()
       * @hide
       */
      public void drawWebViewFunctor(int functor) {
          nDrawWebViewFunctor(mNativeCanvasWrapper, functor);
      }
  
      ///////////////////////////////////////////////////////////////////////////
      // Display list
      ///////////////////////////////////////////////////////////////////////////
  
      /**
       * Draws the specified display list onto this canvas.
       *
       * @param renderNode The RenderNode to draw.
       */
      @Override
      public void drawRenderNode(@NonNull RenderNode renderNode) {
          nDrawRenderNode(mNativeCanvasWrapper, renderNode.mNativeRenderNode);
      }
  
      ///////////////////////////////////////////////////////////////////////////
      // Hardware layer
      ///////////////////////////////////////////////////////////////////////////
  
      /**
       * Draws the specified layer onto this canvas.
       *
       * @param layer The layer to composite on this canvas
       * @hide
       */
      public void drawTextureLayer(TextureLayer layer) {
          nDrawTextureLayer(mNativeCanvasWrapper, layer.getLayerHandle());
      }
  
      ///////////////////////////////////////////////////////////////////////////
      // Drawing
      ///////////////////////////////////////////////////////////////////////////
  
      /**
       * Draws a circle
       *
       * @param cx
       * @param cy
       * @param radius
       * @param paint
       *
       * @hide
       */
      public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
              CanvasProperty<Float> radius, CanvasProperty<Paint> paint) {
          nDrawCircle(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
                  radius.getNativeContainer(), paint.getNativeContainer());
      }
  
      /**
       * Draws a round rect
       *
       * @param left
       * @param top
       * @param right
       * @param bottom
       * @param rx
       * @param ry
       * @param paint
       *
       * @hide
       */
      public void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top,
              CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx,
              CanvasProperty<Float> ry, CanvasProperty<Paint> paint) {
          nDrawRoundRect(mNativeCanvasWrapper, left.getNativeContainer(), top.getNativeContainer(),
                  right.getNativeContainer(), bottom.getNativeContainer(),
                  rx.getNativeContainer(), ry.getNativeContainer(),
                  paint.getNativeContainer());
      }
  
      /** @hide */
      @Override
      protected void throwIfCannotDraw(Bitmap bitmap) {
          super.throwIfCannotDraw(bitmap);
          int bitmapSize = bitmap.getByteCount();
          if (bitmapSize > MAX_BITMAP_SIZE) {
              throw new RuntimeException(
                      "Canvas: trying to draw too large(" + bitmapSize + "bytes) bitmap.");
          }
      }
  
  
      // ------------------ Fast JNI ------------------------
  
      @FastNative
      private static native void nCallDrawGLFunction(long renderer,
              long drawGLFunction, Runnable releasedCallback);
  
  
      // ------------------ Critical JNI ------------------------
  
      @CriticalNative
      private static native long nCreateDisplayListCanvas(long node, int width, int height);
      @CriticalNative
      private static native void nResetDisplayListCanvas(long canvas, long node,
              int width, int height);
      @CriticalNative
      private static native int nGetMaximumTextureWidth();
      @CriticalNative
      private static native int nGetMaximumTextureHeight();
      @CriticalNative
      private static native void nInsertReorderBarrier(long renderer, boolean enableReorder);
      @CriticalNative
      private static native long nFinishRecording(long renderer);
      @CriticalNative
      private static native void nDrawRenderNode(long renderer, long renderNode);
      @CriticalNative
      private static native void nDrawTextureLayer(long renderer, long layer);
      @CriticalNative
      private static native void nDrawCircle(long renderer, long propCx,
              long propCy, long propRadius, long propPaint);
      @CriticalNative
      private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
              long propRight, long propBottom, long propRx, long propRy, long propPaint);
      @CriticalNative
      private static native void nDrawWebViewFunctor(long canvas, int functor);
  }
  