| 4046 | } |
| 4047 | |
| 4048 | function _drawRadioGroup(page, field, widget, rect) { |
| 4049 | let selected = null; |
| 4050 | try { |
| 4051 | selected = field.getSelected(); |
| 4052 | } catch { |
| 4053 | selected = null; |
| 4054 | } |
| 4055 | |
| 4056 | if (!selected) return; |
| 4057 | |
| 4058 | let widgetOnValue = null; |
| 4059 | try { |
| 4060 | widgetOnValue = widget.getOnValue?.(); |
| 4061 | } catch { |
| 4062 | /* ignore */ |
| 4063 | } |
| 4064 | |
| 4065 | if (!widgetOnValue) { |
| 4066 | try { |
| 4067 | const ap = widget.dict?.lookupMaybe?.(PDFName.of("AP"), PDFDict); |
| 4068 | const n = ap?.lookupMaybe?.(PDFName.of("N"), PDFDict); |
| 4069 | if (n) { |
| 4070 | const keys = n.keys(); |
| 4071 | for (const k of keys) { |
| 4072 | const name = k?.decodeText?.() ?? k?.encodedName ?? String(k); |
| 4073 | if (name !== "/Off" && name !== "Off") { |
| 4074 | widgetOnValue = name.replace(/^\//, ""); |
| 4075 | break; |
| 4076 | } |
| 4077 | } |
| 4078 | } |
| 4079 | } catch { |
| 4080 | /* ignore */ |
| 4081 | } |
| 4082 | } |
| 4083 | |
| 4084 | const selectedStr = String(selected).replace(/^\//, ""); |
| 4085 | const onStr = String(widgetOnValue ?? "").replace(/^\//, ""); |
| 4086 | |
| 4087 | if (!onStr || selectedStr !== onStr) return; |
| 4088 | |
| 4089 | // Circle outline |
| 4090 | try { |
| 4091 | page.drawEllipse({ |
| 4092 | x: rect.x + rect.width / 2, |
| 4093 | y: rect.y + rect.height / 2, |
| 4094 | xScale: rect.width / 2 - 1, |
| 4095 | yScale: rect.height / 2 - 1, |
| 4096 | borderWidth: 0.8, |
| 4097 | borderColor: rgb(0, 0, 0) |
| 4098 | }); |
| 4099 | } catch { |
| 4100 | /* best effort */ |
| 4101 | } |
| 4102 | |
| 4103 | // Inner filled dot (drawn as a filled ellipse instead of a text glyph |
| 4104 | // so we avoid WinAnsi encoding issues with bullet characters) |
| 4105 | try { |