diff --git a/.maestro/enrichedMarkdownText/screenshots/ios/inline_math_display.png b/.maestro/enrichedMarkdownText/screenshots/ios/inline_math_display.png index 554ba6ea2..8aee9318e 100644 Binary files a/.maestro/enrichedMarkdownText/screenshots/ios/inline_math_display.png and b/.maestro/enrichedMarkdownText/screenshots/ios/inline_math_display.png differ diff --git a/packages/react-native-enriched-markdown/ios/attachments/ENRMMathInlineAttachment.h b/packages/react-native-enriched-markdown/ios/attachments/ENRMMathInlineAttachment.h index 4bfb1dd1d..956792262 100644 --- a/packages/react-native-enriched-markdown/ios/attachments/ENRMMathInlineAttachment.h +++ b/packages/react-native-enriched-markdown/ios/attachments/ENRMMathInlineAttachment.h @@ -9,6 +9,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) CGFloat fontSize; @property (nonatomic, strong, nullable) RCTUIColor *mathTextColor; +@property (nonatomic, readonly) CGFloat boxHeight; + #if TARGET_OS_OSX /// Pre-renders the formula into self.image and sets self.bounds. /// Must be called after latex/fontSize/mathTextColor are set, before the diff --git a/packages/react-native-enriched-markdown/ios/attachments/ENRMMathInlineAttachment.m b/packages/react-native-enriched-markdown/ios/attachments/ENRMMathInlineAttachment.m index 4c5c5be81..6c02fdb50 100644 --- a/packages/react-native-enriched-markdown/ios/attachments/ENRMMathInlineAttachment.m +++ b/packages/react-native-enriched-markdown/ios/attachments/ENRMMathInlineAttachment.m @@ -10,6 +10,14 @@ @implementation ENRMMathInlineAttachment +- (CGFloat)boxHeight +{ +#if !TARGET_OS_OSX + [self prepareIfNeeded]; +#endif + return _cachedSize.height; +} + #if !TARGET_OS_OSX - (void)prepareIfNeeded diff --git a/packages/react-native-enriched-markdown/ios/utils/ParagraphStyleUtils.m b/packages/react-native-enriched-markdown/ios/utils/ParagraphStyleUtils.m index 550bd7033..54c22c24f 100644 --- a/packages/react-native-enriched-markdown/ios/utils/ParagraphStyleUtils.m +++ b/packages/react-native-enriched-markdown/ios/utils/ParagraphStyleUtils.m @@ -284,7 +284,8 @@ void applyBaselineOffset(NSMutableAttributedString *output, NSRange range) return; } - __block CGFloat maximumLineHeight = 0; + // Math paragraphs leave maximumLineHeight at 0, so fall back to minimumLineHeight. + __block CGFloat targetLineHeight = 0; [output enumerateAttribute:NSParagraphStyleAttributeName inRange:range options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired @@ -292,29 +293,59 @@ void applyBaselineOffset(NSMutableAttributedString *output, NSRange range) if (!paragraphStyle) { return; } - maximumLineHeight = MAX(paragraphStyle.maximumLineHeight, maximumLineHeight); + CGFloat clamp = MAX(paragraphStyle.maximumLineHeight, paragraphStyle.minimumLineHeight); + targetLineHeight = MAX(clamp, targetLineHeight); }]; - if (maximumLineHeight <= 0) { + if (targetLineHeight <= 0) { return; } - __block CGFloat maximumFontLineHeight = 0; - [output enumerateAttribute:NSFontAttributeName - inRange:range - options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired - usingBlock:^(UIFont *font, __unused NSRange subrange, __unused BOOL *stop) { - if (!font) { - return; - } - maximumFontLineHeight = MAX(UIFontLineHeight(font), maximumFontLineHeight); - }]; + // Center on real text; on a math-only line center the math box instead of its font. + __block CGFloat textLineHeight = 0; +#if ENRICHED_MARKDOWN_MATH + __block BOOL hasMath = NO; +#endif + [output enumerateAttributesInRange:range + options:0 + usingBlock:^(NSDictionary *attrs, __unused NSRange subrange, + __unused BOOL *stop) { +#if ENRICHED_MARKDOWN_MATH + if ([attrs[NSAttachmentAttributeName] isKindOfClass:[ENRMMathInlineAttachment class]]) { + hasMath = YES; + return; + } +#endif + UIFont *font = attrs[NSFontAttributeName]; + if (font) { + textLineHeight = MAX(UIFontLineHeight(font), textLineHeight); + } + }]; + + CGFloat contentLineHeight = textLineHeight; + +#if ENRICHED_MARKDOWN_MATH + // Math only grows the content height, so measure it (parsing LaTeX) only when text + // alone wouldn't already fill the line. + if (hasMath && targetLineHeight > textLineHeight) { + __block CGFloat mathBoxHeight = 0; + [output enumerateAttribute:NSAttachmentAttributeName + inRange:range + options:0 + usingBlock:^(id value, __unused NSRange subrange, __unused BOOL *stop) { + if ([value isKindOfClass:[ENRMMathInlineAttachment class]]) { + mathBoxHeight = MAX(((ENRMMathInlineAttachment *)value).boxHeight, mathBoxHeight); + } + }]; + contentLineHeight = MAX(textLineHeight, mathBoxHeight); + } +#endif - if (maximumFontLineHeight <= 0 || maximumLineHeight < maximumFontLineHeight) { + if (contentLineHeight <= 0 || targetLineHeight <= contentLineHeight) { return; } - CGFloat baseLineOffset = (maximumLineHeight - maximumFontLineHeight) / 2.0; + CGFloat baseLineOffset = (targetLineHeight - contentLineHeight) / 2.0; [output enumerateAttribute:NSBaselineOffsetAttributeName inRange:range