InstantPage V2: fall back to 600x300 for zero-dimension map blocks
AI/server-sent .map blocks can arrive with dimensions == 0x0 (the wire w/h are required Int32, but the sender may put 0; our parse and both serializers preserve whatever arrives). A zero naturalSize.height hit instantPageV2MediaFrame's else branch and returned a height-0 frame: the map collapsed to no space, the caption slid up into it, and the V1 node's pin floated over the caption. A zero-sized MapSnapshotMediaResource would also make MKMapSnapshotter render nothing. Substitute PixelDimensions(600, 300) (2:1) whenever width <= 0 || height <= 0, feeding effectiveDimensions to BOTH the layout naturalSize AND the InstantPageMapAttribute so the snapshot resource is non-zero and actually renders. Scoped to the V2 .map arm; V1 (real web articles) always carries real dimensions and never trips this. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9b1573e87e
commit
071799368d
2 changed files with 17 additions and 2 deletions
|
|
@ -74,6 +74,7 @@ Every V2 block-media kind **except `.audio`** lays out **flush** with the bubble
|
|||
- **Full-width media bleeds `instantPageV2MediaEdgeBleed` (4pt) past the trailing edge.** The pageView sits at `x: -1` inside `containerNode` (a border-hiding hairline), so a frame at `x: 0, width: boundingWidth` falls ~1px short of the container's right rounded-clip edge → a 1px corner notch. A small over-bleed on **full-width** items only (`fillsWidth = scaledSize.width >= availableWidth - 1.0`) closes it; a genuinely small image gets no bleed. **The bleed never widens the bubble** because `layoutInstantPageV2` clamps `contentSize.width = min(maxX, boundingWidth)` (gated by `context.fitToWidth`, which both callers — the rich bubble and the send preview — pass `true`).
|
||||
- **Captions stay inset.** `layoutCaptionAndCredit` is still called with the page `horizontalInset` and offset by the **un-bled** `scaledSize.height`; the caption/credit text is inset under a full-bleed image. The `isCover && captionHeight > 0` cover-padding block is unchanged.
|
||||
- **Audio is the lone exception** and routes through the non-flush branch of `instantPageV2MediaFrame` (inset by `horizontalInset`, caller's cornerRadius), reproducing the legacy behavior exactly.
|
||||
- **`.map` blocks get a 600×300 (2:1) fallback when the sender omits dimensions.** AI/server-sent `.map` blocks can arrive with `dimensions == 0×0` (the wire `w`/`h` are *required* `Int32`, but the sender may put 0; our `pageBlockMap` parse and both serializers — Postbox `sw`/`sh`, FlatBuffers `required dimensions` — preserve whatever arrives, so the zero originates upstream). A zero `naturalSize.height` hits `instantPageV2MediaFrame`'s `else` branch and returns a **height-0** frame: the map collapses to no space, the caption slides up into it, and the V1 node's pin (positioned at `size.height*0.5 − 10 − pinSize/2`) floats over the caption. **The `.map` arm in `InstantPageV2Layout.swift` substitutes `PixelDimensions(600, 300)` whenever `width <= 0 || height <= 0`, and feeds that `effectiveDimensions` to BOTH the layout `naturalSize` AND the `InstantPageMapAttribute`** — the latter is essential because a `MapSnapshotMediaResource(width:0,height:0)` makes `MKMapSnapshotter` render nothing, so fixing only the frame would yield a correctly-sized *blank* box. Real web-article maps (the V1 renderer) always carry real dimensions, so V1 never trips this; the fallback is deliberately scoped to the V2 `.map` arm rather than V1 or the wire/parse layer.
|
||||
|
||||
## InstantPage V2 text item height (true font line box)
|
||||
|
||||
|
|
|
|||
|
|
@ -843,7 +843,21 @@ private func layoutBlock(
|
|||
horizontalInset: horizontalInset, context: &context)
|
||||
|
||||
case let .map(latitude, longitude, zoom, dimensions, caption):
|
||||
let naturalSize = CGSize(width: CGFloat(dimensions.width), height: CGFloat(dimensions.height))
|
||||
// AI/server-sent `.map` blocks can arrive with zero `dimensions` (the wire `w`/`h` are
|
||||
// required, but the sender may put 0). A zero `naturalSize.height` collapses the media
|
||||
// frame to height 0 (`instantPageV2MediaFrame`'s else branch) — the map takes no space,
|
||||
// the caption slides up into it, and the pin floats over the caption — and a zero-sized
|
||||
// `MapSnapshotMediaResource` makes `MKMapSnapshotter` render nothing. Substitute a sensible
|
||||
// default (a 2:1 map strip) for BOTH the layout size and the snapshot resource. Real web
|
||||
// articles (the V1 renderer) always carry real dimensions, so only the rich-message path
|
||||
// hits this; the fallback is scoped here rather than in V1 or the wire/parse layer.
|
||||
let effectiveDimensions: PixelDimensions
|
||||
if dimensions.width > 0 && dimensions.height > 0 {
|
||||
effectiveDimensions = dimensions
|
||||
} else {
|
||||
effectiveDimensions = PixelDimensions(width: 600, height: 300)
|
||||
}
|
||||
let naturalSize = CGSize(width: CGFloat(effectiveDimensions.width), height: CGFloat(effectiveDimensions.height))
|
||||
let map = TelegramMediaMap(
|
||||
latitude: latitude,
|
||||
longitude: longitude,
|
||||
|
|
@ -853,7 +867,7 @@ private func layoutBlock(
|
|||
liveBroadcastingTimeout: nil,
|
||||
liveProximityNotificationRadius: nil
|
||||
)
|
||||
let mapAttributes: [InstantPageImageAttribute] = [InstantPageMapAttribute(zoom: zoom, dimensions: dimensions.cgSize)]
|
||||
let mapAttributes: [InstantPageImageAttribute] = [InstantPageMapAttribute(zoom: zoom, dimensions: effectiveDimensions.cgSize)]
|
||||
let mediaIndex = context.mediaIndexCounter
|
||||
context.mediaIndexCounter += 1
|
||||
let instantPageMedia = InstantPageMedia(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue