/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include #include #include #include #include #include #include namespace facebook::react { template concept TextLayoutManagerWithPreparedLayout = requires( TextLayoutManagerT textLayoutManager, AttributedString attributedString, ParagraphAttributes paragraphAttributes, TextLayoutContext layoutContext, LayoutConstraints layoutConstraints, typename TextLayoutManagerT::PreparedLayout preparedLayout) { sizeof(typename TextLayoutManagerT::PreparedLayout); { textLayoutManager.prepareLayout(attributedString, paragraphAttributes, layoutContext, layoutConstraints) } -> std::same_as; { textLayoutManager.measurePreparedLayout(preparedLayout, layoutContext, layoutConstraints) } -> std::same_as; }; namespace detail { template struct PreparedLayoutT { using type = std::nullptr_t; }; template struct PreparedLayoutT { using type = typename T::PreparedLayout; }; /** * TextLayoutManagerExtended acts as an adapter for TextLayoutManager methods * which may not exist for a specific platform. Callers can check at * compile-time whether a method is supported, and calling if it is not will * terminate. */ template class TextLayoutManagerExtended { public: static constexpr bool supportsLineMeasurement() { return requires(TextLayoutManagerT textLayoutManager) { { textLayoutManager.measureLines(AttributedStringBox{}, ParagraphAttributes{}, Size{}) } -> std::same_as; }; } static constexpr bool supportsPreparedLayout() { return TextLayoutManagerWithPreparedLayout; } using PreparedLayout = typename PreparedLayoutT::type; TextLayoutManagerExtended(const TextLayoutManagerT &textLayoutManager) : textLayoutManager_(textLayoutManager) {} LinesMeasurements measureLines( const AttributedStringBox &attributedStringBox, const ParagraphAttributes ¶graphAttributes, const Size &size) { if constexpr (supportsLineMeasurement()) { return textLayoutManager_.measureLines(attributedStringBox, paragraphAttributes, size); } LOG(FATAL) << "Platform TextLayoutManager does not support measureLines"; } PreparedLayout prepareLayout( const AttributedString &attributedString, const ParagraphAttributes ¶graphAttributes, const TextLayoutContext &layoutContext, const LayoutConstraints &layoutConstraints) const { if constexpr (supportsPreparedLayout()) { return textLayoutManager_.prepareLayout(attributedString, paragraphAttributes, layoutContext, layoutConstraints); } LOG(FATAL) << "Platform TextLayoutManager does not support prepareLayout"; } TextMeasurement measurePreparedLayout( const PreparedLayout &layout, const TextLayoutContext &layoutContext, const LayoutConstraints &layoutConstraints) const { if constexpr (supportsPreparedLayout()) { return textLayoutManager_.measurePreparedLayout(layout, layoutContext, layoutConstraints); } LOG(FATAL) << "Platform TextLayoutManager does not support measurePreparedLayout"; } private: const TextLayoutManagerT &textLayoutManager_; }; } // namespace detail using TextLayoutManagerExtended = detail::TextLayoutManagerExtended; struct MeasuredPreparedLayout { LayoutConstraints layoutConstraints; TextMeasurement measurement; TextLayoutManagerExtended::PreparedLayout preparedLayout{}; }; } // namespace facebook::react