<commit_before>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h"

#include "flutter/fml/trace_event.h"

namespace flutter {

AndroidExternalViewEmbedder::AndroidExternalViewEmbedder(
    std::shared_ptr<AndroidContext> android_context,
    std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
    const AndroidSurface::Factory& surface_factory)
    : ExternalViewEmbedder(),
      android_context_(android_context),
      jni_facade_(jni_facade),
      surface_factory_(surface_factory),
      surface_pool_(std::make_unique<SurfacePool>()) {}

// |ExternalViewEmbedder|
void AndroidExternalViewEmbedder::PrerollCompositeEmbeddedView(
    int view_id,
    std::unique_ptr<EmbeddedViewParams> params) {
  TRACE_EVENT0("flutter",
               "AndroidExternalViewEmbedder::PrerollCompositeEmbeddedView");

  auto rtree_factory = RTreeFactory();
  view_rtrees_.insert({view_id, rtree_factory.getInstance()});

  auto picture_recorder = std::make_unique<SkPictureRecorder>();
  picture_recorder->beginRecording(SkRect::Make(frame_size_), &rtree_factory);

  picture_recorders_.insert({view_id, std::move(picture_recorder)});
  composition_order_.push_back(view_id);
  // Update params only if they changed.
  if (view_params_.count(view_id) == 1 &&
      view_params_.at(view_id) == *params.get()) {
    return;
  }
  view_params_.insert_or_assign(view_id, EmbeddedViewParams(*params.get()));
}

// |ExternalViewEmbedder|
SkCanvas* AndroidExternalViewEmbedder::CompositeEmbeddedView(int view_id) {
  if (picture_recorders_.count(view_id) == 1) {
    return picture_recorders_.at(view_id)->getRecordingCanvas();
  }
  return nullptr;
}

// |ExternalViewEmbedder|
std::vector<SkCanvas*> AndroidExternalViewEmbedder::GetCurrentCanvases() {
  std::vector<SkCanvas*> canvases;
  for (size_t i = 0; i < composition_order_.size(); i++) {
    int64_t view_id = composition_order_[i];
    canvases.push_back(picture_recorders_.at(view_id)->getRecordingCanvas());
  }
  return canvases;
}

SkRect AndroidExternalViewEmbedder::GetViewRect(int view_id) const {
  const EmbeddedViewParams& params = view_params_.at(view_id);
  // TODO(egarciad): The rect should be computed from the mutator stack.
  // https://github.com/flutter/flutter/issues/59821
  return SkRect::MakeXYWH(params.finalBoundingRect().x(),                     //
                          params.finalBoundingRect().y(),                     //
                          params.sizePoints().width() * device_pixel_ratio_,  //
                          params.sizePoints().height() * device_pixel_ratio_  //
  );
}

// |ExternalViewEmbedder|
bool AndroidExternalViewEmbedder::SubmitFrame(
    GrContext* context,
    std::unique_ptr<SurfaceFrame> frame) {
  TRACE_EVENT0("flutter", "AndroidExternalViewEmbedder::SubmitFrame");

  if (should_run_rasterizer_on_platform_thread_) {
    // Don't submit the current frame if the frame will be resubmitted.
    return true;
  }

  std::unordered_map<int64_t, std::list<SkRect>> overlay_layers;
  std::unordered_map<int64_t, sk_sp<SkPicture>> pictures;
  SkCanvas* background_canvas = frame->SkiaCanvas();

  // Restore the clip context after exiting this method since it's changed
  // below.
  SkAutoCanvasRestore save(background_canvas, /*doSave=*/true);

  for (size_t i = 0; i < composition_order_.size(); i++) {
    int64_t view_id = composition_order_[i];
    SkRect view_rect = GetViewRect(view_id);

    // Display the platform view. If it's already displayed, then it's
    // just positioned and sized.
    jni_facade_->FlutterViewOnDisplayPlatformView(view_id,            //
                                                  view_rect.x(),      //
                                                  view_rect.y(),      //
                                                  view_rect.width(),  //
                                                  view_rect.height()  //
    );

    sk_sp<SkPicture> picture =
        picture_recorders_.at(view_id)->finishRecordingAsPicture();
    FML_CHECK(picture);
    pictures.insert({view_id, picture});
    sk_sp<RTree> rtree = view_rtrees_.at(view_id);
    // Determinate if Flutter UI intersects with any of the previous
    // platform views stacked by z position.
    //
    // This is done by querying the r-tree that holds the records for the
    // picture recorder corresponding to the flow layers added after a platform
    // view layer.
    for (ssize_t j = i; j >= 0; j--) {
      int64_t current_view_id = composition_order_[j];
      SkRect current_view_rect = GetViewRect(current_view_id);
      // Each rect corresponds to a native view that renders Flutter UI.
      std::list<SkRect> intersection_rects =
          rtree->searchNonOverlappingDrawnRects(current_view_rect);
      auto allocation_size = intersection_rects.size();

      // Limit the number of native views, so it doesn't grow forever.
      //
      // In this case, the rects are merged into a single one that is the union
      // of all the rects.
      if (allocation_size > kMaxLayerAllocations) {
        SkRect joined_rect;
        for (const SkRect& rect : intersection_rects) {
          joined_rect.join(rect);
        }
        intersection_rects.clear();
        intersection_rects.push_back(joined_rect);
      }
      for (SkRect& intersection_rect : intersection_rects) {
        // Get the intersection rect between the current rect
        // and the platform view rect.
        // joined_rect.intersect(platform_view_rect);
        // Subpixels in the platform may not align with the canvas subpixels.
        //
        // To workaround it, round the floating point bounds and make the rect
        // slighly larger. For example, {0.3, 0.5, 3.1, 4.7} becomes {0, 0, 4,
        // 5}.
        intersection_rect.set(intersection_rect.roundOut());
        // Clip the background canvas, so it doesn't contain any of the pixels
        // drawn on the overlay layer.
        background_canvas->clipRect(intersection_rect, SkClipOp::kDifference);
      }
      overlay_layers.insert({current_view_id, intersection_rects});
    }
    background_canvas->drawPicture(pictures.at(view_id));
  }
  // Submit the background canvas frame before switching the GL context to
  // the surfaces above.
  frame->Submit();

  for (int64_t view_id : composition_order_) {
    for (const SkRect& overlay_rect : overlay_layers.at(view_id)) {
      CreateSurfaceIfNeeded(context,               //
                            view_id,               //
                            pictures.at(view_id),  //
                            overlay_rect           //
                            )
          ->Submit();
    }
  }
  return true;
}

// |ExternalViewEmbedder|
std::unique_ptr<SurfaceFrame>
AndroidExternalViewEmbedder::CreateSurfaceIfNeeded(GrContext* context,
                                                   int64_t view_id,<commit_msg>Move OnDisplayPlatformView JNI call (#19258)<commit_after>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h"

#include "flutter/fml/trace_event.h"

namespace flutter {

AndroidExternalViewEmbedder::AndroidExternalViewEmbedder(
    std::shared_ptr<AndroidContext> android_context,
    std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
    const AndroidSurface::Factory& surface_factory)
    : ExternalViewEmbedder(),
      android_context_(android_context),
      jni_facade_(jni_facade),
      surface_factory_(surface_factory),
      surface_pool_(std::make_unique<SurfacePool>()) {}

// |ExternalViewEmbedder|
void AndroidExternalViewEmbedder::PrerollCompositeEmbeddedView(
    int view_id,
    std::unique_ptr<EmbeddedViewParams> params) {
  TRACE_EVENT0("flutter",
               "AndroidExternalViewEmbedder::PrerollCompositeEmbeddedView");

  auto rtree_factory = RTreeFactory();
  view_rtrees_.insert({view_id, rtree_factory.getInstance()});

  auto picture_recorder = std::make_unique<SkPictureRecorder>();
  picture_recorder->beginRecording(SkRect::Make(frame_size_), &rtree_factory);

  picture_recorders_.insert({view_id, std::move(picture_recorder)});
  composition_order_.push_back(view_id);
  // Update params only if they changed.
  if (view_params_.count(view_id) == 1 &&
      view_params_.at(view_id) == *params.get()) {
    return;
  }
  view_params_.insert_or_assign(view_id, EmbeddedViewParams(*params.get()));
}

// |ExternalViewEmbedder|
SkCanvas* AndroidExternalViewEmbedder::CompositeEmbeddedView(int view_id) {
  if (picture_recorders_.count(view_id) == 1) {
    return picture_recorders_.at(view_id)->getRecordingCanvas();
  }
  return nullptr;
}

// |ExternalViewEmbedder|
std::vector<SkCanvas*> AndroidExternalViewEmbedder::GetCurrentCanvases() {
  std::vector<SkCanvas*> canvases;
  for (size_t i = 0; i < composition_order_.size(); i++) {
    int64_t view_id = composition_order_[i];
    canvases.push_back(picture_recorders_.at(view_id)->getRecordingCanvas());
  }
  return canvases;
}

SkRect AndroidExternalViewEmbedder::GetViewRect(int view_id) const {
  const EmbeddedViewParams& params = view_params_.at(view_id);
  // TODO(egarciad): The rect should be computed from the mutator stack.
  // https://github.com/flutter/flutter/issues/59821
  return SkRect::MakeXYWH(params.finalBoundingRect().x(),                     //
                          params.finalBoundingRect().y(),                     //
                          params.sizePoints().width() * device_pixel_ratio_,  //
                          params.sizePoints().height() * device_pixel_ratio_  //
  );
}

// |ExternalViewEmbedder|
bool AndroidExternalViewEmbedder::SubmitFrame(
    GrContext* context,
    std::unique_ptr<SurfaceFrame> frame) {
  TRACE_EVENT0("flutter", "AndroidExternalViewEmbedder::SubmitFrame");

  if (should_run_rasterizer_on_platform_thread_) {
    // Don't submit the current frame if the frame will be resubmitted.
    return true;
  }

  std::unordered_map<int64_t, std::list<SkRect>> overlay_layers;
  std::unordered_map<int64_t, sk_sp<SkPicture>> pictures;
  SkCanvas* background_canvas = frame->SkiaCanvas();

  // Restore the clip context after exiting this method since it's changed
  // below.
  SkAutoCanvasRestore save(background_canvas, /*doSave=*/true);

  for (size_t i = 0; i < composition_order_.size(); i++) {
    int64_t view_id = composition_order_[i];

    sk_sp<SkPicture> picture =
        picture_recorders_.at(view_id)->finishRecordingAsPicture();
    FML_CHECK(picture);
    pictures.insert({view_id, picture});
    sk_sp<RTree> rtree = view_rtrees_.at(view_id);
    // Determinate if Flutter UI intersects with any of the previous
    // platform views stacked by z position.
    //
    // This is done by querying the r-tree that holds the records for the
    // picture recorder corresponding to the flow layers added after a platform
    // view layer.
    for (ssize_t j = i; j >= 0; j--) {
      int64_t current_view_id = composition_order_[j];
      SkRect current_view_rect = GetViewRect(current_view_id);
      // Each rect corresponds to a native view that renders Flutter UI.
      std::list<SkRect> intersection_rects =
          rtree->searchNonOverlappingDrawnRects(current_view_rect);
      auto allocation_size = intersection_rects.size();

      // Limit the number of native views, so it doesn't grow forever.
      //
      // In this case, the rects are merged into a single one that is the union
      // of all the rects.
      if (allocation_size > kMaxLayerAllocations) {
        SkRect joined_rect;
        for (const SkRect& rect : intersection_rects) {
          joined_rect.join(rect);
        }
        intersection_rects.clear();
        intersection_rects.push_back(joined_rect);
      }
      for (SkRect& intersection_rect : intersection_rects) {
        // Get the intersection rect between the current rect
        // and the platform view rect.
        // joined_rect.intersect(platform_view_rect);
        // Subpixels in the platform may not align with the canvas subpixels.
        //
        // To workaround it, round the floating point bounds and make the rect
        // slighly larger. For example, {0.3, 0.5, 3.1, 4.7} becomes {0, 0, 4,
        // 5}.
        intersection_rect.set(intersection_rect.roundOut());
        // Clip the background canvas, so it doesn't contain any of the pixels
        // drawn on the overlay layer.
        background_canvas->clipRect(intersection_rect, SkClipOp::kDifference);
      }
      overlay_layers.insert({current_view_id, intersection_rects});
    }
    background_canvas->drawPicture(pictures.at(view_id));
  }
  // Submit the background canvas frame before switching the GL context to
  // the surfaces above.
  frame->Submit();

  for (int64_t view_id : composition_order_) {
    SkRect view_rect = GetViewRect(view_id);
    // Display the platform view. If it's already displayed, then it's
    // just positioned and sized.
    jni_facade_->FlutterViewOnDisplayPlatformView(view_id,            //
                                                  view_rect.x(),      //
                                                  view_rect.y(),      //
                                                  view_rect.width(),  //
                                                  view_rect.height()  //
    );
    for (const SkRect& overlay_rect : overlay_layers.at(view_id)) {
      CreateSurfaceIfNeeded(context,               //
                            view_id,               //
                            pictures.at(view_id),  //
                            overlay_rect           //
                            )
          ->Submit();
    }
  }
  return true;
}

// |ExternalViewEmbedder|
std::unique_ptr<SurfaceFrame>
AndroidExternalViewEmbedder::CreateSurfaceIfNeeded(GrContext* context,
                                                   int64_t view_id,
{'fraction_non_alphanumeric': 0.10205952884751023, 'fraction_numerical': 0.006277331076315418, 'mean_word_length': 2.7830843116328707, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 61, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2562861', 'n_tokens_mistral': 4221, 'n_tokens_neox': 4054, 'n_words': 915}