( node: DOMElement, output: Output, offsetX: number, offsetY: number, hasRemovedChild: boolean, prevScreen: Screen | undefined, inheritedBackgroundColor: Color | undefined, )
| 1273 | // rects (NewMessagesPill's inner Text with backgroundColor). Opaque |
| 1274 | // absolute siblings fill their entire rect — direct blit is safe. |
| 1275 | function renderChildren( |
| 1276 | node: DOMElement, |
| 1277 | output: Output, |
| 1278 | offsetX: number, |
| 1279 | offsetY: number, |
| 1280 | hasRemovedChild: boolean, |
| 1281 | prevScreen: Screen | undefined, |
| 1282 | inheritedBackgroundColor: Color | undefined, |
| 1283 | ): void { |
| 1284 | let seenDirtyChild = false |
| 1285 | let seenDirtyClipped = false |
| 1286 | for (const childNode of node.childNodes) { |
| 1287 | const childElem = childNode as DOMElement |
| 1288 | // Capture dirty before rendering — renderNodeToOutput clears the flag |
| 1289 | const wasDirty = childElem.dirty |
| 1290 | const isAbsolute = childElem.style.position === 'absolute' |
| 1291 | renderNodeToOutput(childElem, output, { |
| 1292 | offsetX, |
| 1293 | offsetY, |
| 1294 | prevScreen: hasRemovedChild || seenDirtyChild ? undefined : prevScreen, |
| 1295 | // Short-circuits on seenDirtyClipped (false in the common case) so |
| 1296 | // the opaque/bg reads don't happen per-child per-frame. |
| 1297 | skipSelfBlit: |
| 1298 | seenDirtyClipped && |
| 1299 | isAbsolute && |
| 1300 | !childElem.style.opaque && |
| 1301 | childElem.style.backgroundColor === undefined, |
| 1302 | inheritedBackgroundColor, |
| 1303 | }) |
| 1304 | if (wasDirty && !seenDirtyChild) { |
| 1305 | if (!clipsBothAxes(childElem) || isAbsolute) { |
| 1306 | seenDirtyChild = true |
| 1307 | } else { |
| 1308 | seenDirtyClipped = true |
| 1309 | } |
| 1310 | } |
| 1311 | } |
| 1312 | } |
| 1313 | |
| 1314 | function clipsBothAxes(node: DOMElement): boolean { |
| 1315 | const ox = node.style.overflowX ?? node.style.overflow |
no test coverage detected