[Impeller] hash less text stuff per frame for text rendering. (#55060)

The Glyph color and stroke property are only required for stroked text or COLR text, in all other cases its a no-op. We can do the text hashing faster if we let these properties be optional.

~Also as an experiment switches to absl containers which should be more reasonably performant than std containers.~ required more changes, will try again later
diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc
index 6dde4e6..8254902 100644
--- a/impeller/entity/contents/text_contents.cc
+++ b/impeller/entity/contents/text_contents.cc
@@ -222,8 +222,11 @@
             Point subpixel = TextFrame::ComputeSubpixelPosition(
                 glyph_position, font.GetAxisAlignment(), offset_, scale_);
             std::optional<std::pair<Rect, Rect>> maybe_atlas_glyph_bounds =
-                font_atlas->FindGlyphBounds(
-                    SubpixelGlyph{glyph_position.glyph, subpixel, properties_});
+                font_atlas->FindGlyphBounds(SubpixelGlyph{
+                    glyph_position.glyph, subpixel,
+                    (properties_.stroke || frame_->HasColor())
+                        ? std::optional<GlyphProperties>(properties_)
+                        : std::nullopt});
             if (!maybe_atlas_glyph_bounds.has_value()) {
               VALIDATION_LOG << "Could not find glyph position in the atlas.";
               continue;
diff --git a/impeller/typographer/backends/skia/typographer_context_skia.cc b/impeller/typographer/backends/skia/typographer_context_skia.cc
index 6533773..a86e2ee 100644
--- a/impeller/typographer/backends/skia/typographer_context_skia.cc
+++ b/impeller/typographer/backends/skia/typographer_context_skia.cc
@@ -208,7 +208,7 @@
                       const ScaledFont& scaled_font,
                       const SubpixelGlyph& glyph,
                       const Rect& scaled_bounds,
-                      const GlyphProperties& prop,
+                      const std::optional<GlyphProperties>& prop,
                       bool has_color) {
   const auto& metrics = scaled_font.font.GetMetrics();
   SkGlyphID glyph_id = glyph.glyph.index;
@@ -222,18 +222,17 @@
   sk_font.setSubpixel(true);
   sk_font.setSize(sk_font.getSize() * scaled_font.scale);
 
-  auto glyph_color =
-      has_color ? glyph.properties.color.ToARGB() : SK_ColorBLACK;
+  auto glyph_color = prop.has_value() ? prop->color.ToARGB() : SK_ColorBLACK;
 
   SkPaint glyph_paint;
   glyph_paint.setColor(glyph_color);
   glyph_paint.setBlendMode(SkBlendMode::kSrc);
-  if (prop.stroke) {
+  if (prop.has_value() && prop->stroke) {
     glyph_paint.setStroke(true);
-    glyph_paint.setStrokeWidth(prop.stroke_width * scaled_font.scale);
-    glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties.stroke_cap));
-    glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties.stroke_join));
-    glyph_paint.setStrokeMiter(prop.stroke_miter * scaled_font.scale);
+    glyph_paint.setStrokeWidth(prop->stroke_width * scaled_font.scale);
+    glyph_paint.setStrokeCap(ToSkiaCap(prop->stroke_cap));
+    glyph_paint.setStrokeJoin(ToSkiaJoin(prop->stroke_join));
+    glyph_paint.setStrokeMiter(prop->stroke_miter * scaled_font.scale);
   }
   canvas->save();
   canvas->translate(glyph.subpixel_offset.x, glyph.subpixel_offset.y);
@@ -384,12 +383,12 @@
                              Scalar scale) {
   SkRect scaled_bounds;
   SkPaint glyph_paint;
-  if (glyph.properties.stroke) {
+  if (glyph.properties.has_value() && glyph.properties->stroke) {
     glyph_paint.setStroke(true);
-    glyph_paint.setStrokeWidth(glyph.properties.stroke_width * scale);
-    glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties.stroke_cap));
-    glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties.stroke_join));
-    glyph_paint.setStrokeMiter(glyph.properties.stroke_miter * scale);
+    glyph_paint.setStrokeWidth(glyph.properties->stroke_width * scale);
+    glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties->stroke_cap));
+    glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties->stroke_join));
+    glyph_paint.setStrokeMiter(glyph.properties->stroke_miter * scale);
   }
   font.getBounds(&glyph.glyph.index, 1, &scaled_bounds, &glyph_paint);
 
diff --git a/impeller/typographer/font_glyph_pair.h b/impeller/typographer/font_glyph_pair.h
index c5d3c50..d4c12fa 100644
--- a/impeller/typographer/font_glyph_pair.h
+++ b/impeller/typographer/font_glyph_pair.h
@@ -8,6 +8,7 @@
 #include <unordered_map>
 #include <unordered_set>
 
+#include "fml/hash_combine.h"
 #include "impeller/geometry/color.h"
 #include "impeller/geometry/path.h"
 #include "impeller/geometry/point.h"
@@ -32,6 +33,19 @@
 struct ScaledFont {
   Font font;
   Scalar scale;
+
+  struct Hash {
+    constexpr std::size_t operator()(const impeller::ScaledFont& sf) const {
+      return fml::HashCombine(sf.font.GetHash(), sf.scale);
+    }
+  };
+
+  struct Equal {
+    constexpr bool operator()(const impeller::ScaledFont& lhs,
+                              const impeller::ScaledFont& rhs) const {
+      return lhs.font.IsEqual(rhs.font) && lhs.scale == rhs.scale;
+    }
+  };
 };
 
 //------------------------------------------------------------------------------
@@ -40,18 +54,58 @@
 struct SubpixelGlyph {
   Glyph glyph;
   Point subpixel_offset;
-  GlyphProperties properties;
+  std::optional<GlyphProperties> properties;
 
   SubpixelGlyph(Glyph p_glyph,
                 Point p_subpixel_offset,
-                GlyphProperties p_properties)
+                std::optional<GlyphProperties> p_properties)
       : glyph(p_glyph),
         subpixel_offset(p_subpixel_offset),
         properties(p_properties) {}
+
+  struct Hash {
+    constexpr std::size_t operator()(const impeller::SubpixelGlyph& sg) const {
+      if (!sg.properties.has_value()) {
+        return fml::HashCombine(sg.glyph.index, sg.subpixel_offset.x,
+                                sg.subpixel_offset.y);
+      }
+      return fml::HashCombine(
+          sg.glyph.index, sg.subpixel_offset.x, sg.subpixel_offset.y,
+          sg.properties->color.ToARGB(), sg.properties->stroke,
+          sg.properties->stroke_cap, sg.properties->stroke_join,
+          sg.properties->stroke_miter, sg.properties->stroke_width);
+    }
+  };
+
+  struct Equal {
+    constexpr bool operator()(const impeller::SubpixelGlyph& lhs,
+                              const impeller::SubpixelGlyph& rhs) const {
+      if (!lhs.properties.has_value() && !rhs.properties.has_value()) {
+        return lhs.glyph.index == rhs.glyph.index &&
+               lhs.glyph.type == rhs.glyph.type &&
+               lhs.subpixel_offset == rhs.subpixel_offset;
+      }
+      return lhs.glyph.index == rhs.glyph.index &&
+             lhs.glyph.type == rhs.glyph.type &&
+             lhs.subpixel_offset == rhs.subpixel_offset &&
+             lhs.properties.has_value() && rhs.properties.has_value() &&
+             lhs.properties->color.ToARGB() == rhs.properties->color.ToARGB() &&
+             lhs.properties->stroke == rhs.properties->stroke &&
+             lhs.properties->stroke_cap == rhs.properties->stroke_cap &&
+             lhs.properties->stroke_join == rhs.properties->stroke_join &&
+             lhs.properties->stroke_miter == rhs.properties->stroke_miter &&
+             lhs.properties->stroke_width == rhs.properties->stroke_width;
+    }
+  };
 };
 
 using FontGlyphMap =
-    std::unordered_map<ScaledFont, std::unordered_set<SubpixelGlyph>>;
+    std::unordered_map<ScaledFont,
+                       std::unordered_set<SubpixelGlyph,
+                                          SubpixelGlyph::Hash,
+                                          SubpixelGlyph::Equal>,
+                       ScaledFont::Hash,
+                       ScaledFont::Equal>;
 
 //------------------------------------------------------------------------------
 /// @brief      A font along with a glyph in that font rendered at a particular
@@ -66,46 +120,4 @@
 
 }  // namespace impeller
 
-template <>
-struct std::hash<impeller::ScaledFont> {
-  constexpr std::size_t operator()(const impeller::ScaledFont& sf) const {
-    return fml::HashCombine(sf.font.GetHash(), sf.scale);
-  }
-};
-
-template <>
-struct std::equal_to<impeller::ScaledFont> {
-  constexpr bool operator()(const impeller::ScaledFont& lhs,
-                            const impeller::ScaledFont& rhs) const {
-    return lhs.font.IsEqual(rhs.font) && lhs.scale == rhs.scale;
-  }
-};
-
-template <>
-struct std::hash<impeller::SubpixelGlyph> {
-  constexpr std::size_t operator()(const impeller::SubpixelGlyph& sg) const {
-    return fml::HashCombine(
-        sg.glyph.index, sg.subpixel_offset.x, sg.subpixel_offset.y,
-        sg.properties.color.ToARGB(), sg.properties.stroke,
-        sg.properties.stroke_cap, sg.properties.stroke_join,
-        sg.properties.stroke_miter, sg.properties.stroke_width);
-  }
-};
-
-template <>
-struct std::equal_to<impeller::SubpixelGlyph> {
-  constexpr bool operator()(const impeller::SubpixelGlyph& lhs,
-                            const impeller::SubpixelGlyph& rhs) const {
-    return lhs.glyph.index == rhs.glyph.index &&
-           lhs.glyph.type == rhs.glyph.type &&
-           lhs.subpixel_offset == rhs.subpixel_offset &&
-           lhs.properties.color.ToARGB() == rhs.properties.color.ToARGB() &&
-           lhs.properties.stroke == rhs.properties.stroke &&
-           lhs.properties.stroke_cap == rhs.properties.stroke_cap &&
-           lhs.properties.stroke_join == rhs.properties.stroke_join &&
-           lhs.properties.stroke_miter == rhs.properties.stroke_miter &&
-           lhs.properties.stroke_width == rhs.properties.stroke_width;
-  }
-};
-
 #endif  // FLUTTER_IMPELLER_TYPOGRAPHER_FONT_GLYPH_PAIR_H_
diff --git a/impeller/typographer/glyph_atlas.h b/impeller/typographer/glyph_atlas.h
index b94fe90..587ece4 100644
--- a/impeller/typographer/glyph_atlas.h
+++ b/impeller/typographer/glyph_atlas.h
@@ -136,7 +136,11 @@
   const Type type_;
   std::shared_ptr<Texture> texture_;
 
-  std::unordered_map<ScaledFont, FontGlyphAtlas> font_atlas_map_;
+  std::unordered_map<ScaledFont,
+                     FontGlyphAtlas,
+                     ScaledFont::Hash,
+                     ScaledFont::Equal>
+      font_atlas_map_;
 
   GlyphAtlas(const GlyphAtlas&) = delete;
 
@@ -214,7 +218,11 @@
 
  private:
   friend class GlyphAtlas;
-  std::unordered_map<SubpixelGlyph, std::pair<Rect, Rect>> positions_;
+  std::unordered_map<SubpixelGlyph,
+                     std::pair<Rect, Rect>,
+                     SubpixelGlyph::Hash,
+                     SubpixelGlyph::Equal>
+      positions_;
 
   FontGlyphAtlas(const FontGlyphAtlas&) = delete;
 
diff --git a/impeller/typographer/text_frame.cc b/impeller/typographer/text_frame.cc
index a0ce36d..b715616 100644
--- a/impeller/typographer/text_frame.cc
+++ b/impeller/typographer/text_frame.cc
@@ -89,6 +89,10 @@
     Scalar scale,
     Point offset,
     const GlyphProperties& properties) const {
+  std::optional<GlyphProperties> lookup =
+      (properties.stroke || HasColor())
+          ? std::optional<GlyphProperties>(properties)
+          : std::nullopt;
   for (const TextRun& run : GetRuns()) {
     const Font& font = run.GetFont();
     auto rounded_scale =
@@ -98,7 +102,7 @@
          run.GetGlyphPositions()) {
       Point subpixel = ComputeSubpixelPosition(
           glyph_position, font.GetAxisAlignment(), offset, scale);
-      set.emplace(glyph_position.glyph, subpixel, properties);
+      set.emplace(glyph_position.glyph, subpixel, lookup);
     }
   }
 }
diff --git a/impeller/typographer/text_run.h b/impeller/typographer/text_run.h
index 6bec4d1..76da59f 100644
--- a/impeller/typographer/text_run.h
+++ b/impeller/typographer/text_run.h
@@ -7,7 +7,7 @@
 
 #include <vector>
 
-#include "impeller/geometry/matrix.h"
+#include "impeller/geometry/point.h"
 #include "impeller/typographer/font.h"
 #include "impeller/typographer/glyph.h"