(bytes: Uint8Array)
| 127 | } |
| 128 | |
| 129 | function parseFrame(bytes: Uint8Array): ParsedFrame { |
| 130 | const stringsById = new Map<number, Uint8Array>(); |
| 131 | const textRunBlobsByIndex: TextRunBlob[] = []; |
| 132 | const drawTexts: DrawTextCommand[] = []; |
| 133 | const drawTextRuns: DrawTextRunCommand[] = []; |
| 134 | const pushClips: PushClipCommand[] = []; |
| 135 | let popClipCount = 0; |
| 136 | |
| 137 | for (const cmd of parseCommandHeaders(bytes)) { |
| 138 | const off = cmd.offset; |
| 139 | if (cmd.opcode === OP_DEF_STRING) { |
| 140 | if (cmd.size < 16) continue; |
| 141 | const stringId = u32(bytes, off + 8); |
| 142 | const byteLen = u32(bytes, off + 12); |
| 143 | const dataStart = off + 16; |
| 144 | const dataEnd = dataStart + byteLen; |
| 145 | if (dataEnd <= off + cmd.size) { |
| 146 | stringsById.set(stringId, Uint8Array.from(bytes.subarray(dataStart, dataEnd))); |
| 147 | } |
| 148 | continue; |
| 149 | } |
| 150 | if (cmd.opcode === OP_FREE_STRING) { |
| 151 | if (cmd.size >= 12) stringsById.delete(u32(bytes, off + 8)); |
| 152 | continue; |
| 153 | } |
| 154 | if (cmd.opcode === OP_DEF_BLOB) { |
| 155 | if (cmd.size < 16) continue; |
| 156 | const blobId = u32(bytes, off + 8); |
| 157 | const byteLen = u32(bytes, off + 12); |
| 158 | const dataStart = off + 16; |
| 159 | const dataEnd = dataStart + byteLen; |
| 160 | if (blobId > 0 && dataEnd <= off + cmd.size) { |
| 161 | const blob = Uint8Array.from(bytes.subarray(dataStart, dataEnd)); |
| 162 | textRunBlobsByIndex[blobId - 1] = decodeTextRunBlob(blob, stringsById); |
| 163 | } |
| 164 | continue; |
| 165 | } |
| 166 | if (cmd.opcode === OP_FREE_BLOB) { |
| 167 | const blobId = u32(bytes, off + 8); |
| 168 | if (blobId > 0) |
| 169 | textRunBlobsByIndex[blobId - 1] = Object.freeze({ segments: Object.freeze([]) }); |
| 170 | continue; |
| 171 | } |
| 172 | |
| 173 | if (cmd.opcode === OP_DRAW_TEXT) { |
| 174 | assert.ok(cmd.size >= 48, "DRAW_TEXT command size"); |
| 175 | const stringId = u32(bytes, off + 16); |
| 176 | const byteOff = u32(bytes, off + 20); |
| 177 | const byteLen = u32(bytes, off + 24); |
| 178 | drawTexts.push({ |
| 179 | x: i32(bytes, off + 8), |
| 180 | y: i32(bytes, off + 12), |
| 181 | stringIndex: stringId > 0 ? stringId - 1 : -1, |
| 182 | byteOff, |
| 183 | byteLen, |
| 184 | text: decodeStringSlice(stringsById, stringId, byteOff, byteLen), |
| 185 | fg: u32(bytes, off + 28), |
| 186 | bg: u32(bytes, off + 32), |
no test coverage detected