| // 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/flow/layers/performance_overlay_layer.h" | 
 |  | 
 | #include <iomanip> | 
 | #include <iostream> | 
 | #include <memory> | 
 | #include <string> | 
 |  | 
 | #include "flow/stopwatch.h" | 
 | #include "flow/stopwatch_dl.h" | 
 | #include "flow/stopwatch_sk.h" | 
 | #include "third_party/skia/include/core/SkFont.h" | 
 | #include "third_party/skia/include/core/SkFontMgr.h" | 
 | #include "third_party/skia/include/core/SkTextBlob.h" | 
 | #include "third_party/skia/include/core/SkTypeface.h" | 
 | #include "txt/platform.h" | 
 | #ifdef IMPELLER_SUPPORTS_RENDERING | 
 | #include "impeller/typographer/backends/skia/text_frame_skia.h"  // nogncheck | 
 | #endif  // IMPELLER_SUPPORTS_RENDERING | 
 |  | 
 | namespace flutter { | 
 | namespace { | 
 |  | 
 | void VisualizeStopWatch(DlCanvas* canvas, | 
 |                         const bool impeller_enabled, | 
 |                         const Stopwatch& stopwatch, | 
 |                         SkScalar x, | 
 |                         SkScalar y, | 
 |                         SkScalar width, | 
 |                         SkScalar height, | 
 |                         bool show_graph, | 
 |                         bool show_labels, | 
 |                         const std::string& label_prefix, | 
 |                         const std::string& font_path) { | 
 |   const int label_x = 8;    // distance from x | 
 |   const int label_y = -10;  // distance from y+height | 
 |  | 
 |   if (show_graph) { | 
 |     SkRect visualization_rect = SkRect::MakeXYWH(x, y, width, height); | 
 |     std::unique_ptr<StopwatchVisualizer> visualizer; | 
 |  | 
 |     if (impeller_enabled) { | 
 |       visualizer = std::make_unique<DlStopwatchVisualizer>(stopwatch); | 
 |     } else { | 
 |       visualizer = std::make_unique<SkStopwatchVisualizer>(stopwatch); | 
 |     } | 
 |  | 
 |     visualizer->Visualize(canvas, visualization_rect); | 
 |   } | 
 |  | 
 |   if (show_labels) { | 
 |     auto text = PerformanceOverlayLayer::MakeStatisticsText( | 
 |         stopwatch, label_prefix, font_path); | 
 |     // Historically SK_ColorGRAY (== 0xFF888888) was used here | 
 |     DlPaint paint(DlColor(0xFF888888)); | 
 | #ifdef IMPELLER_SUPPORTS_RENDERING | 
 |     if (impeller_enabled) { | 
 |       canvas->DrawTextFrame(impeller::MakeTextFrameFromTextBlobSkia(text), | 
 |                             x + label_x, y + height + label_y, paint); | 
 |       return; | 
 |     } | 
 | #endif  // IMPELLER_SUPPORTS_RENDERING | 
 |     canvas->DrawTextBlob(text, x + label_x, y + height + label_y, paint); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | sk_sp<SkTextBlob> PerformanceOverlayLayer::MakeStatisticsText( | 
 |     const Stopwatch& stopwatch, | 
 |     const std::string& label_prefix, | 
 |     const std::string& font_path) { | 
 |   SkFont font; | 
 |   sk_sp<SkFontMgr> font_mgr = txt::GetDefaultFontManager(); | 
 |   if (font_path == "") { | 
 |     if (sk_sp<SkTypeface> face = font_mgr->matchFamilyStyle(nullptr, {})) { | 
 |       font = SkFont(face, 15); | 
 |     } else { | 
 |       // In Skia's Android fontmgr, matchFamilyStyle can return null instead | 
 |       // of falling back to a default typeface. If that's the case, we can use | 
 |       // legacyMakeTypeface, which *does* use that default typeface. | 
 |       font = SkFont(font_mgr->legacyMakeTypeface(nullptr, {}), 15); | 
 |     } | 
 |   } else { | 
 |     font = SkFont(font_mgr->makeFromFile(font_path.c_str()), 15); | 
 |   } | 
 |   // Make sure there's not an empty typeface returned, or we won't see any text. | 
 |   FML_DCHECK(font.getTypeface()->countGlyphs() > 0); | 
 |  | 
 |   double max_ms_per_frame = stopwatch.MaxDelta().ToMillisecondsF(); | 
 |   double average_ms_per_frame = stopwatch.AverageDelta().ToMillisecondsF(); | 
 |   std::stringstream stream; | 
 |   stream.setf(std::ios::fixed | std::ios::showpoint); | 
 |   stream << std::setprecision(1); | 
 |   stream << label_prefix << "  " << "max " << max_ms_per_frame << " ms/frame, " | 
 |          << "avg " << average_ms_per_frame << " ms/frame"; | 
 |   auto text = stream.str(); | 
 |   return SkTextBlob::MakeFromText(text.c_str(), text.size(), font, | 
 |                                   SkTextEncoding::kUTF8); | 
 | } | 
 |  | 
 | PerformanceOverlayLayer::PerformanceOverlayLayer(uint64_t options, | 
 |                                                  const char* font_path) | 
 |     : options_(options) { | 
 |   if (font_path != nullptr) { | 
 |     font_path_ = font_path; | 
 |   } | 
 | } | 
 |  | 
 | void PerformanceOverlayLayer::Diff(DiffContext* context, | 
 |                                    const Layer* old_layer) { | 
 |   DiffContext::AutoSubtreeRestore subtree(context); | 
 |   if (!context->IsSubtreeDirty()) { | 
 |     FML_DCHECK(old_layer); | 
 |     auto prev = old_layer->as_performance_overlay_layer(); | 
 |     context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(prev)); | 
 |   } | 
 |   context->AddLayerBounds(paint_bounds()); | 
 |   context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion()); | 
 | } | 
 |  | 
 | void PerformanceOverlayLayer::Paint(PaintContext& context) const { | 
 |   const int padding = 8; | 
 |  | 
 |   if (!options_) { | 
 |     return; | 
 |   } | 
 |  | 
 |   SkScalar x = paint_bounds().x() + padding; | 
 |   SkScalar y = paint_bounds().y() + padding; | 
 |   SkScalar width = paint_bounds().width() - (padding * 2); | 
 |   SkScalar height = paint_bounds().height() / 2; | 
 |   auto mutator = context.state_stack.save(); | 
 |  | 
 |   VisualizeStopWatch( | 
 |       context.canvas, context.impeller_enabled, context.raster_time, x, y, | 
 |       width, height - padding, options_ & kVisualizeRasterizerStatistics, | 
 |       options_ & kDisplayRasterizerStatistics, "Raster", font_path_); | 
 |  | 
 |   VisualizeStopWatch(context.canvas, context.impeller_enabled, context.ui_time, | 
 |                      x, y + height, width, height - padding, | 
 |                      options_ & kVisualizeEngineStatistics, | 
 |                      options_ & kDisplayEngineStatistics, "UI", font_path_); | 
 | } | 
 |  | 
 | }  // namespace flutter |