( node: DOMElement, output: Output, offsetX: number, offsetY: number, hasRemovedChild: boolean, prevScreen: Screen | undefined, inheritedBackgroundColor: Color | undefined, )
| 1255 | // rects (NewMessagesPill's inner Text with backgroundColor). Opaque |
| 1256 | // absolute siblings fill their entire rect — direct blit is safe. |
| 1257 | function renderChildren( |
| 1258 | node: DOMElement, |
| 1259 | output: Output, |
| 1260 | offsetX: number, |
| 1261 | offsetY: number, |
| 1262 | hasRemovedChild: boolean, |
| 1263 | prevScreen: Screen | undefined, |
| 1264 | inheritedBackgroundColor: Color | undefined, |
| 1265 | ): void { |
| 1266 | let seenDirtyChild = false |
| 1267 | let seenDirtyClipped = false |
| 1268 | for (const childNode of node.childNodes) { |
| 1269 | const childElem = childNode as DOMElement |
| 1270 | // Capture dirty before rendering — renderNodeToOutput clears the flag |
| 1271 | const wasDirty = childElem.dirty |
| 1272 | const isAbsolute = childElem.style.position === 'absolute' |
| 1273 | renderNodeToOutput(childElem, output, { |
| 1274 | offsetX, |
| 1275 | offsetY, |
| 1276 | prevScreen: hasRemovedChild || seenDirtyChild ? undefined : prevScreen, |
| 1277 | // Short-circuits on seenDirtyClipped (false in the common case) so |
| 1278 | // the opaque/bg reads don't happen per-child per-frame. |
| 1279 | skipSelfBlit: |
| 1280 | seenDirtyClipped && |
| 1281 | isAbsolute && |
| 1282 | !childElem.style.opaque && |
| 1283 | childElem.style.backgroundColor === undefined, |
| 1284 | inheritedBackgroundColor, |
| 1285 | }) |
| 1286 | if (wasDirty && !seenDirtyChild) { |
| 1287 | if (!clipsBothAxes(childElem) || isAbsolute) { |
| 1288 | seenDirtyChild = true |
| 1289 | } else { |
| 1290 | seenDirtyClipped = true |
| 1291 | } |
| 1292 | } |
| 1293 | } |
| 1294 | } |
| 1295 | |
| 1296 | function clipsBothAxes(node: DOMElement): boolean { |
| 1297 | const ox = node.style.overflowX ?? node.style.overflow |
no test coverage detected