chromium/components/services/font_data/font_data_service_impl.h

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_SERVICES_FONT_DATA_FONT_DATA_SERVICE_IMPL_H_
#define COMPONENTS_SERVICES_FONT_DATA_FONT_DATA_SERVICE_IMPL_H_

#include <stdint.h>

#include <map>
#include <memory>
#include <vector>

#include "base/memory/read_only_shared_memory_region.h"
#include "base/sequence_checker.h"
#include "components/services/font_data/public/mojom/font_data_service.mojom.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "third_party/skia/include/core/SkFontMgr.h"
#include "third_party/skia/include/core/SkTypeface.h"

namespace font_data_service {

// FontDataService (receiver) manages font requests from the renderer.
// Does the following:
//     1) Construct the SkTypeface based on the font request details via
//     DWriteFactory.
//     2) Store that SkTypeface as an SkStreamAsset (wrapper of the font data as
//     raw bytes) into a shared memory map to be fetched by the renderer.
//     3) Cache the value for future requests.
//
// Instantiated in the browser process and lives on a sequence running in the
// thread pool.
//
// This is meant to replace the existing renderer font integration.
// FontDataServiceImpl is the replacement to DWriteFontProxyImpl. This currently
// only runs on Windows desktop browser as part of an experiment: see
// crbug.com/335680565 for more details.
class FontDataServiceImpl : public mojom::FontDataService {
 public:
  FontDataServiceImpl();

  FontDataServiceImpl(const FontDataServiceImpl&) = delete;
  FontDataServiceImpl& operator=(const FontDataServiceImpl&) = delete;

  ~FontDataServiceImpl() override;

  void BindReceiver(mojo::PendingReceiver<mojom::FontDataService> receiver);
  static void ConnectToFontService(
      mojo::PendingReceiver<mojom::FontDataService> receiver);

  size_t GetCacheSizeForTesting() const {
    return typeface_to_asset_index_.size();
  }

  // FontDataService:
  // Provides font data from a cache that is populated on-demand. Font data will
  // match based on the `family_name` and `style` inputs. If there is no such
  // match, the font data will be null.
  void MatchFamilyName(const std::string& family_name,
                       mojom::TypefaceStylePtr style,
                       MatchFamilyNameCallback callback) override;

 private:
  // Checks the shared memory region cache and returns an index if found. On
  // cache miss, creates a new entry caching the data.
  size_t GetOrCreateAssetIndex(std::unique_ptr<SkStreamAsset> asset);

  mojo::ReceiverSet<mojom::FontDataService> receivers_;

  // The default font manager in the browser that creates the SkTypeface. On
  // Windows, this would be the DWrite font manager (SkFontMgr_DirectWrite).
  sk_sp<SkFontMgr> font_manager_;

  // Wrapper that binds the SkStreamAsset and its shared memory
  // map region. Used by the `assets_` cache.
  struct MappedAsset {
    MappedAsset() = delete;
    MappedAsset(std::unique_ptr<SkStreamAsset> asset,
                base::MappedReadOnlyRegion shared_memory);
    ~MappedAsset();
    MappedAsset(const MappedAsset&) = delete;
    MappedAsset& operator=(const MappedAsset&) = delete;

    std::unique_ptr<SkStreamAsset> asset;
    base::MappedReadOnlyRegion shared_memory;
  };
  // The primary font cache. Items must not be reordered after insertion.
  std::vector<std::unique_ptr<MappedAsset>> assets_;

  // Wrapper that binds the index and a ttc_index. Used for
  // typeface-to-asset-index lookup.
  struct MappedTypeface {
    size_t asset_index;

    // Set to index of this Typeface or 0 if the stream is not a collection.
    int ttc_index;
  };
  // A mapping of a typeface's identifier to the index in the cache (i.e.,
  // assets_).
  std::map<SkTypefaceID, MappedTypeface> typeface_to_asset_index_;

  // A mapping from a font data's base address to its index in the primary font
  // cache (i.e., assets_).
  std::map<intptr_t, size_t> address_to_asset_index_;

  SEQUENCE_CHECKER(sequence_checker_);
};

}  // namespace font_data_service

#endif  // COMPONENTS_SERVICES_FONT_DATA_FONT_DATA_SERVICE_IMPL_H_