기능: hwpx 수식 방출 arm + hp:script 엔티티 해석 (GE-14·GE-15) - #23
Conversation
hwpx writer에 eqed arm이 없어 수식이 generic fallback으로 DROP됐다. hwpx를 편집·변환만 해도 수식이 통째로 사라지는 데이터 손실이었다. - write_equation: run 직속 <hp:equation> + hp:sz/hp:pos/hp:script. 개체 공통 스캐폴드 순서(sz→pos→outMargin)는 write_shape_element·hp:pic과 동일. 부유/인라인 flowWithText·allowOverlap 조합은 gso_pos_xml의 실측 규칙. hwpx 출신(hp:script)·hwp5 출신(EQEDIT, parse_eqed) 모두 IR Equation을 채우므로 한 경로로 방출된다. - resolve_entity: 엔티티 참조 해석을 parse_text와 read_element_text가 공유. read_element_text가 GeneralRef/CData를 무시해 `x < y` 같은 스크립트의 특수문자가 읽기에서 유실되던 결함 해소(writer esc()의 역). - 수식_hwpx_왕복: 인라인/부유 2종 + XML 특수문자 케이스로 왕복 고정. 수식 전용 속성(version·baseLine·baseUnit·font)은 정답지 미확보 표준 추정값이라 한글 실기 확정이 남았다(12-feature-gaps.md GE-14). 외부 기여 PR #7(maenjh)의 진단에서 출발 — 각주/미주는 e433462 실측판으로 선행 해소돼 제외하고, 남은 수식·엔티티만 구현.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7aeec3c1d0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let id = ids.next(); | ||
| let _ = write!( | ||
| out, | ||
| r##"<hp:equation id="{id}" zOrder="0" numberingType="EQUATION" textWrap="{wrap}" textFlow="BOTH_SIDES" lock="0" dropcapstyle="None" version="Equation Version 60" baseLine="85" textColor="#000000" baseUnit="1000" lineMode="0" font="HYhwpEQ"><hp:sz width="{}" widthRelTo="ABSOLUTE" height="{}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="{treat}" affectLSpacing="0" flowWithText="{flow}" allowOverlap="{overlap}" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="{}" horzOffset="{}"/><hp:outMargin left="0" right="0" top="0" bottom="0"/><hp:script>{}</hp:script></hp:equation>"##, |
There was a problem hiding this comment.
Preserve the equation anchor coordinate system
For floating equations sourced with PAPER, PAGE, or COLUMN anchoring, hardcoding vertRelTo="PARA" and horzRelTo="PARA" reinterprets the stored offsets relative to the anchor paragraph. This moves formulas during HWPX round trips and HWP5-to-HWPX conversion even though the numeric x/y values survive; preserve the source relation/alignment fields in the IR or emit the coordinate system represented by Equation::x and y instead.
Useful? React with 👍 / 👎.
| eq.width.max(0), | ||
| eq.height.max(0), |
There was a problem hiding this comment.
Synthesize dimensions for zero-sized equations
When an Equation has width or height 0, these expressions emit an absolute zero-sized hp:sz. Zero is the model's documented sentinel meaning that the renderer should estimate the extent, and it can occur in synthesized or JSON-edited IR, so the resulting HWPX formula has no usable layout box. Derive positive dimensions from the script/typesetter, as the renderer does, rather than serializing the sentinel.
Useful? React with 👍 / 👎.
적대적 점검(자체) 결과 반영. - count_shape_tags에 <hp:equation> 추가 + equation arm에 shape_break!/카운트. 다른 개체 arm은 run당 12개에서 run을 가르는데(한글 ~21개 한도, 실기 확정) 수식만 빠져 있었다. 한글 한도가 수식까지 포함하는지는 미확정이나, 과다 계상은 run이 더 일찍 갈라질 뿐이고 과소 계상은 개체 유실이라 안전한 쪽을 택한다. - tools/gen_effects_cases.py L1_수식: JSON IR에 eqed 컨트롤을 심어 hwpx로 방출하고 재읽기로 스크립트 원문(특수문자 포함) 3종을 단언 + validate. 실기 파일 생성 경로가 이제 재현 가능하다. - 실기검증-체크리스트에 L 시리즈 추가 — 정답지 미확보 상태라 판정 기준을 "열리는가"가 아니라 "수식이 조판돼 보이는가"로 두고, 증상별로 어느 속성이 틀렸는지 회수한다.
한컴 공식 OWPML 모델(hancom-io/hwpx-owpml-model) 대조로 확인한 결함들. 1. lineMode="0"은 스키마 밖 값이었다. enumdef.h g_EquationLineList는 LINE|CHAR 열거이고 기본값은 CHAR다(EquationType.cpp). 합성 경로를 CHAR로 고쳤다. 2. hwpx 출신 수식의 비기본 속성이 왕복에서 전부 기본값으로 재작성됐다(zOrder· textWrap·lock·baseLine·글자색·baseUnit·수식 글꼴·PAGE 기준 배치·outMargin). Equation에 raw_attrs·raw_props를 두고 원문 pass-through(secpr_raw_children과 같은 규약). writer는 원문이 있으면 그대로 되쓰고 없으면 표준값을 합성한다. 3. hwp5 출신 부유 수식의 배치가 PARA/PARA·zOrder 0 상수로 뭉개졌다. eqed의 data는 gso 공통 헤더라 parse_gso_header + gso_pos_xml을 그대로 쓴다(그림 GE-9와 동형). 4. GE-16 attr() 엔티티 미해석 → 이중 이스케이프. 책갈피·필드·스타일 이름과 수식 script 속성 전부에 영향. 읽는 즉시 unescape(해석 불가 참조는 원문 유지). 5. GE-17 esc()가 XML 비문자(U+FFFE·U+FFFF)를 흘려 well-formed하지 않은 패키지를 만들 수 있었다. C0와 동일하게 제거. 테스트 3종 추가: 수식_속성_원문_보존(비기본 속성 11종 + 합성 lineMode), 수식_hwp5출신_배치_복원(gso 헤더 → PAGE/오프셋/z-order), 속성값_엔티티_해석, esc_금지문자_제거. 게이트 통과(fmt/clippy/test), L1 실기 케이스 재생성 확인.
적대적 점검(codex) 결과 반영
반증 실패(= 안 깨짐)로 판정된 것: arm 순서·가드에 hwp5 회귀 입력 없음, ExtCtrl wchar 폭 정합, 음수 pos 오프셋 대칭, 미해결로 남긴 것(문서화): 검증
|
hwpx writer에
eqedarm이 없어 수식이 generic fallback으로 DROP됐다. hwpx를 편집·변환만 해도 수식이 통째로 사라지는 데이터 손실이다.변경
write_equation— run 직속<hp:equation>+hp:sz/hp:pos/hp:script방출. 개체 공통 스캐폴드 순서(sz→pos→outMargin)는write_shape_element·hp:pic과 동일하고, 부유/인라인의flowWithText·allowOverlap조합은gso_pos_xml의 실측 규칙을 따른다. hwpx 출신(hp:script)·hwp5 출신(EQEDIT,parse_eqed) 모두 IREquation을 채우므로 한 경로로 방출된다 — hwp→hwpx 수식 변환도 함께 열린다.resolve_entity— 엔티티 참조 해석을parse_text와read_element_text가 공유.read_element_text가GeneralRef/CData를 무시해x < y같은 스크립트의 특수문자가 읽기에서 유실되던 결함 해소(writeresc()의 역).수식_hwpx_왕복— 인라인/부유 2종 + XML 특수문자 케이스.docs/design/12-feature-gaps.mdGE-14·GE-15 등재(해소 표기).검증
scripts/check.sh통과 (fmt + clippy -D warnings + test 전체).equation.is_some()가드로 기존 DROP fallback 앞에만 들어간다.남은 것 (머지 전 확인)
수식 전용 속성(
version="Equation Version 60"·baseLine="85"·baseUnit="1000"·font="HYhwpEQ")은 정답지 미확보 상태의 표준 추정값이다 — 로컬 코퍼스에 수식 든 hwpx가 없다. 한글 실기에서 수식이 깨져 보이면 정품 저장본의<hp:equation>속성으로 교체해야 한다.외부 기여 #7(@maenjh)의 진단에서 출발했다. 각주/미주는
e433462실측판으로 선행 해소돼 제외하고, 남은 수식 방출 + 엔티티 해석만 구현했다.