mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 14:31:12 +08:00
1 parent
0139433e25
commit
c74dff1e41
14 files changed
+3625
-31
No files matched your search
@@ -0,0 +1,578 @@
|
||||
// Copyright 2025-2026 肖其顿 (XIAO QI DUN)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ofdgo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// LayerInfo 描述普通页面图层,Order为同类型零基顺序,ObjectCount包含页块中的图元。
|
||||
type LayerInfo struct {
|
||||
ID string
|
||||
Type string
|
||||
DrawParam string
|
||||
Order int
|
||||
ObjectCount int
|
||||
}
|
||||
|
||||
// Layers 按文件顺序返回普通页面图层,省略的类型规范化为Body,不包含模板图层。
|
||||
// 入参: page 零基页面索引
|
||||
// 返回: []LayerInfo 独立图层清单, error 页面读取错误
|
||||
func (e *Editor) Layers(page int) ([]LayerInfo, error) {
|
||||
p, err := e.page(page)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return editorLayerInfos(p), nil
|
||||
}
|
||||
|
||||
// Layers 直接读取普通页面图层,不创建编辑器或分配新标识,返回值不持有页面可变数据。
|
||||
// 入参: page 零基页面索引
|
||||
// 返回: []LayerInfo 按文件顺序排列的图层, error 页面读取错误
|
||||
func (r *Reader) Layers(page int) ([]LayerInfo, error) {
|
||||
p, err := r.PageContentByIndex(page)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return editorLayerInfos(p), nil
|
||||
}
|
||||
|
||||
// editorLayerInfos 将页面图层投影为不共享可变容器的管理清单。
|
||||
// 入参: p 已读取的页面
|
||||
// 返回: []LayerInfo 图层清单
|
||||
func editorLayerInfos(p *PageContent) []LayerInfo {
|
||||
result := make([]LayerInfo, 0, len(p.Content.Layer))
|
||||
orders := make(map[string]int)
|
||||
for _, layer := range p.Content.Layer {
|
||||
kind := editorLayerType(layer.Type)
|
||||
result = append(result, LayerInfo{layer.ID, kind, layer.DrawParam, orders[kind], len(layer.Objects)})
|
||||
orders[kind]++
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// AddLayer 追加空图层并返回新标识,空类型采用Body,空DrawParam表示不设置继承参数。
|
||||
// 入参: page 页面索引, layerType 图层类型, drawParam 绘制参数标识
|
||||
// 返回: string 新图层标识, error 类型、资源或结构错误
|
||||
func (e *Editor) AddLayer(page int, layerType, drawParam string) (string, error) {
|
||||
layerType = editorLayerType(layerType)
|
||||
if !validEditorLayerType(layerType) {
|
||||
return "", fmt.Errorf("invalid layer type %q", layerType)
|
||||
}
|
||||
var id string
|
||||
err := e.editLayerPage(page, func(r *Reader, data []byte, root *editorXML) ([]byte, error) {
|
||||
if err := e.validateLayerDrawParam(page, drawParam); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := e.prepareSourceIDs(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id = e.nextID()
|
||||
attrs := ofdAttrs{{Name: xml.Name{Local: "ID"}, Value: id}, {Name: xml.Name{Local: "Type"}, Value: layerType}}
|
||||
attrs.add("DrawParam", drawParam)
|
||||
content := root.child("Content")
|
||||
fragment, err := root.containerXML("Layer", attrs, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if content != nil {
|
||||
return editorAppendStructure(data, content, fragment), nil
|
||||
}
|
||||
fragment, err = root.containerXML("Content", nil, fragment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
at := root.close
|
||||
if actions := root.child("Actions"); actions != nil {
|
||||
at = actions.start
|
||||
}
|
||||
if root.open == root.end {
|
||||
return editorAppendStructure(data, root, fragment), nil
|
||||
}
|
||||
return editorPatchXML(data, []editorXMLPatch{{at, at, fragment}}), nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// SetLayerType 设置图层类型,不改变图元坐标及绘制参数;同类型顺序由文件位置决定。
|
||||
// 入参: page 页面索引, id 图层标识, layerType 图层类型
|
||||
// 返回: error 标识、类型或结构错误
|
||||
func (e *Editor) SetLayerType(page int, id, layerType string) error {
|
||||
layerType = editorLayerType(layerType)
|
||||
if !validEditorLayerType(layerType) {
|
||||
return fmt.Errorf("invalid layer type %q", layerType)
|
||||
}
|
||||
return e.editLayerPage(page, func(_ *Reader, data []byte, root *editorXML) ([]byte, error) {
|
||||
node, err := editorFindStructureID(root.child("Content"), "Layer", "ID", id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if editorLayerType(node.attr("Type")) == layerType {
|
||||
return data, nil
|
||||
}
|
||||
return editorStructureAttribute(data, node, "Type", layerType)
|
||||
})
|
||||
}
|
||||
|
||||
// SetLayerDrawParam 设置图层绘制参数,空标识清除引用,图元局部覆盖保持不变。
|
||||
// 入参: page 页面索引, id 图层标识, drawParam 绘制参数标识
|
||||
// 返回: error 标识、资源或结构错误
|
||||
func (e *Editor) SetLayerDrawParam(page int, id, drawParam string) error {
|
||||
return e.editLayerPage(page, func(_ *Reader, data []byte, root *editorXML) ([]byte, error) {
|
||||
node, err := editorFindStructureID(root.child("Content"), "Layer", "ID", id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := e.validateLayerDrawParam(page, drawParam); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if node.attr("DrawParam") == drawParam {
|
||||
return data, nil
|
||||
}
|
||||
return editorStructureAttribute(data, node, "DrawParam", drawParam)
|
||||
})
|
||||
}
|
||||
|
||||
// MoveLayer 调整图层在同类型图层中的零基顺序,保留其他类型及扩展节点的位置。
|
||||
// 入参: page 页面索引, id 图层标识, order 同类型目标顺序
|
||||
// 返回: error 标识、顺序或结构错误
|
||||
func (e *Editor) MoveLayer(page int, id string, order int) error {
|
||||
return e.editLayerPage(page, func(_ *Reader, data []byte, root *editorXML) ([]byte, error) {
|
||||
node, err := editorFindStructureID(root.child("Content"), "Layer", "ID", id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var nodes []*editorXML
|
||||
for _, child := range root.child("Content").children {
|
||||
if child.matchesOFD("Layer") && editorLayerType(child.attr("Type")) == editorLayerType(node.attr("Type")) {
|
||||
nodes = append(nodes, child)
|
||||
}
|
||||
}
|
||||
return editorMoveStructure(data, nodes, node, order)
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteLayer 删除空图层,含图元、页块或扩展子元素时拒绝;可先在Transaction中迁移图元。
|
||||
// 入参: page 页面索引, id 图层标识
|
||||
// 返回: error 标识、非空图层或结构错误
|
||||
func (e *Editor) DeleteLayer(page int, id string) error {
|
||||
return e.editLayerPage(page, func(_ *Reader, data []byte, root *editorXML) ([]byte, error) {
|
||||
content := root.child("Content")
|
||||
node, err := editorFindStructureID(content, "Layer", "ID", id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(node.children) != 0 {
|
||||
return nil, fmt.Errorf("layer %q is not empty", id)
|
||||
}
|
||||
if len(content.children) == 1 && len(content.attrs) == 0 {
|
||||
return editorPatchXML(data, []editorXMLPatch{{content.start, content.end, nil}}), nil
|
||||
}
|
||||
if len(editorStructureChildren(content, "Layer")) == 1 {
|
||||
return nil, fmt.Errorf("last layer contains a preserved Content container")
|
||||
}
|
||||
return editorPatchXML(data, []editorXMLPatch{{node.start, node.end, nil}}), nil
|
||||
})
|
||||
}
|
||||
|
||||
// MoveObjectsToLayer 将普通页面选区按原绘制顺序追加到目标层,保持标识、坐标、扩展及有效样式。
|
||||
// 不接受模板或注解标识;页块成员须先通过已有复合编辑接口处理,失败不产生部分移动。
|
||||
// 入参: page 页面索引, ids 不重复的普通图元标识, layerID 目标图层标识
|
||||
// 返回: error 选区、继承参数或结构错误
|
||||
func (e *Editor) MoveObjectsToLayer(page int, ids []string, layerID string) error {
|
||||
return e.editLayerPage(page, func(_ *Reader, data []byte, root *editorXML) ([]byte, error) {
|
||||
target, err := editorFindStructureID(root.child("Content"), "Layer", "ID", layerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wanted := make(map[string]bool)
|
||||
for _, id := range ids {
|
||||
key := editorResourceID(id)
|
||||
if key == "" || wanted[key] {
|
||||
return nil, fmt.Errorf("invalid or duplicate object ID %q", id)
|
||||
}
|
||||
wanted[key] = true
|
||||
}
|
||||
var patches []editorXMLPatch
|
||||
var added []byte
|
||||
layers := editorStructureChildren(root.child("Content"), "Layer")
|
||||
slices.SortStableFunc(layers, func(a, b *editorXML) int { return layerOrder(a.attr("Type")) - layerOrder(b.attr("Type")) })
|
||||
for _, layer := range layers {
|
||||
nodes := make(map[string]*editorXML)
|
||||
if err := editorXMLObjects(layer, nodes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ordered := make([]*editorXML, 0, len(nodes))
|
||||
for _, node := range nodes {
|
||||
ordered = append(ordered, node)
|
||||
}
|
||||
slices.SortFunc(ordered, func(a, b *editorXML) int { return a.start - b.start })
|
||||
for _, node := range ordered {
|
||||
key := editorResourceID(node.attr("ID"))
|
||||
if !wanted[key] {
|
||||
continue
|
||||
}
|
||||
delete(wanted, key)
|
||||
if layer == target {
|
||||
continue
|
||||
}
|
||||
if node.parent != layer {
|
||||
return nil, fmt.Errorf("object %q belongs to a PageBlock", key)
|
||||
}
|
||||
fragment, err := editorXMLStandalone(data[node.start:node.end], node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if layer.attr("DrawParam") != target.attr("DrawParam") {
|
||||
member, err := newEditorCompositeNode(fragment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
member.drawParams = []string{layer.attr("DrawParam")}
|
||||
member.defaults, err = e.editorDrawParam(layer.attr("DrawParam"), make(map[string]bool))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if member.object.Type == "TextObject" || member.object.Type == "ImageObject" {
|
||||
styled, err := e.compositeMemberStyle(member)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := member.update(styled); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := e.isolateCompositeStyle(member); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fragment, _, err = e.writeCompositeNode(member)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
added = append(added, fragment...)
|
||||
patches = append(patches, editorXMLPatch{node.start, node.end, nil})
|
||||
}
|
||||
}
|
||||
if len(wanted) != 0 {
|
||||
return nil, fmt.Errorf("selection contains missing ordinary page objects")
|
||||
}
|
||||
if len(added) == 0 {
|
||||
return data, nil
|
||||
}
|
||||
if target.open == target.end {
|
||||
patches = append(patches, editorXMLContent(data, target, added))
|
||||
} else {
|
||||
patches = append(patches, editorXMLPatch{target.close, target.close, added})
|
||||
}
|
||||
return editorPatchXML(data, patches), nil
|
||||
})
|
||||
}
|
||||
|
||||
// editorLayerType 将标准省略类型规范化,不改变已明确指定的类型。
|
||||
// 入参: value 原类型
|
||||
// 返回: string 有效类型
|
||||
func editorLayerType(value string) string {
|
||||
if value == "" {
|
||||
return "Body"
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// validEditorLayerType 按正文表15校验可管理的图层类型。
|
||||
// 入参: value 类型值
|
||||
// 返回: bool 是否为支持的标准类型
|
||||
func validEditorLayerType(value string) bool {
|
||||
return value == "Body" || value == "Background" || value == "Foreground"
|
||||
}
|
||||
|
||||
// validateLayerDrawParam 在目标页面资源环境中核验完整绘制参数继承链。
|
||||
// 入参: page 页面索引, id 绘制参数标识
|
||||
// 返回: error 页面或资源错误
|
||||
func (e *Editor) validateLayerDrawParam(page int, id string) error {
|
||||
if _, err := e.page(page); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := e.editorDrawParam(id, make(map[string]bool))
|
||||
return err
|
||||
}
|
||||
|
||||
// editLayerPage 在完整包快照上编辑页面原文,事务失败回滚,提交时隔离共享页面及历史版本。
|
||||
// 入参: page 页面索引, edit 页面原文修改回调
|
||||
// 返回: error 读取、修改或提交错误
|
||||
func (e *Editor) editLayerPage(page int, edit func(*Reader, []byte, *editorXML) ([]byte, error)) error {
|
||||
return e.Transaction(func(_ *Editor) error {
|
||||
if _, err := e.page(page); err != nil {
|
||||
return err
|
||||
}
|
||||
r, err := e.Reader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer r.Close()
|
||||
doc, err := r.Doc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := r.ResPath(doc.Pages.Page[page].BaseLoc)
|
||||
data, err := r.readFile(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
root, err := parseEditorXML(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
next, err := edit(r, data, root)
|
||||
if err != nil || bytes.Equal(data, next) {
|
||||
return err
|
||||
}
|
||||
parts := map[string][]byte{name: next}
|
||||
shared := slices.ContainsFunc(doc.CommonData.TemplatePage, func(ref TemplatePage) bool { return r.ResPath(ref.BaseLoc) == name })
|
||||
for i, ref := range doc.Pages.Page {
|
||||
shared = shared || i != page && r.ResPath(ref.BaseLoc) == name
|
||||
}
|
||||
if shared {
|
||||
private := packageAvailableName(r, parts, name)
|
||||
delete(parts, name)
|
||||
parts[private] = next
|
||||
document, err := r.readFile(r.documentRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
entry, err := parseEditorXML(document)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refNode := entry.child("Pages").childAt("Page", page)
|
||||
parts[r.documentRoot], err = editorStructureAttribute(document, refNode, "BaseLoc", "/"+private)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return e.commitLayerTemplateParts(r, parts)
|
||||
})
|
||||
}
|
||||
|
||||
// editorStructureChildren 仅枚举当前标准命名空间中的直接子元素。
|
||||
// 入参: root 容器节点, kind 子元素名称
|
||||
// 返回: []*editorXML 文件顺序节点清单
|
||||
func editorStructureChildren(root *editorXML, kind string) []*editorXML {
|
||||
var nodes []*editorXML
|
||||
if root != nil {
|
||||
for _, node := range root.children {
|
||||
if node.matchesOFD(kind) {
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
// editorFindStructureID 按数值标识查找唯一直接子元素,拒绝缺失及歧义标识。
|
||||
// 入参: root 容器节点, kind 元素名称, attribute 标识属性名, id 标识值
|
||||
// 返回: *editorXML 唯一节点, error 标识错误
|
||||
func editorFindStructureID(root *editorXML, kind, attribute, id string) (*editorXML, error) {
|
||||
var found *editorXML
|
||||
if editorResourceID(id) == "" {
|
||||
return nil, fmt.Errorf("invalid %s ID %q", kind, id)
|
||||
}
|
||||
for _, node := range editorStructureChildren(root, kind) {
|
||||
if sameResourceID(node.attr(attribute), id) {
|
||||
if found != nil {
|
||||
return nil, fmt.Errorf("ambiguous %s ID %q", kind, id)
|
||||
}
|
||||
found = node
|
||||
}
|
||||
}
|
||||
if found == nil {
|
||||
return nil, fmt.Errorf("%s %q not found", kind, id)
|
||||
}
|
||||
return found, nil
|
||||
}
|
||||
|
||||
// editorStructureAttribute 局部替换或删除无命名空间属性,保留扩展及其余原文。
|
||||
// 入参: data 原文, node 目标节点, name 属性名, value 新值,空值删除属性
|
||||
// 返回: []byte 更新后的完整原文, error XML错误
|
||||
func editorStructureAttribute(data []byte, node *editorXML, name, value string) ([]byte, error) {
|
||||
var desired *string
|
||||
if value != "" {
|
||||
desired = &value
|
||||
}
|
||||
patch, err := editorXMLAttributeChange(data, node, name, desired)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return editorPatchXML(data, []editorXMLPatch{patch}), nil
|
||||
}
|
||||
|
||||
// editorAppendStructure 向普通或自闭合容器追加已绑定命名空间的元素。
|
||||
// 入参: data 原文, node 容器节点, fragment 待追加片段
|
||||
// 返回: []byte 更新后的完整原文
|
||||
func editorAppendStructure(data []byte, node *editorXML, fragment []byte) []byte {
|
||||
if node.open == node.end {
|
||||
return editorPatchXML(data, []editorXMLPatch{editorXMLContent(data, node, fragment)})
|
||||
}
|
||||
return editorPatchXML(data, []editorXMLPatch{{node.close, node.close, fragment}})
|
||||
}
|
||||
|
||||
// editorMoveStructure 在指定同类节点位置间移动完整原文,不触及夹杂的扩展元素。
|
||||
// 入参: data 原文, nodes 同类节点, node 被移动节点, order 目标零基顺序
|
||||
// 返回: []byte 更新后的完整原文, error 顺序错误
|
||||
func editorMoveStructure(data []byte, nodes []*editorXML, node *editorXML, order int) ([]byte, error) {
|
||||
if order < 0 || order >= len(nodes) {
|
||||
return nil, fmt.Errorf("order %d out of range", order)
|
||||
}
|
||||
from := slices.Index(nodes, node)
|
||||
if from == order {
|
||||
return data, nil
|
||||
}
|
||||
ordered := slices.Clone(nodes)
|
||||
moveEditorItem(ordered, from, order)
|
||||
patches := make([]editorXMLPatch, len(nodes))
|
||||
for i, old := range nodes {
|
||||
next := ordered[i]
|
||||
patches[i] = editorXMLPatch{old.start, old.end, data[next.start:next.end]}
|
||||
}
|
||||
return editorPatchXML(data, patches), nil
|
||||
}
|
||||
|
||||
// commitLayerTemplateParts 持久化结构与已注册资源,隔离共享文件并恢复未变图元的会话编辑状态。
|
||||
// 入参: reader 当前独立包快照, parts 文件修改集
|
||||
// 返回: error 资源、隔离或提交错误
|
||||
func (e *Editor) commitLayerTemplateParts(reader *Reader, parts map[string][]byte) error {
|
||||
ctx := context.Background()
|
||||
data := parts[reader.documentRoot]
|
||||
var err error
|
||||
if data == nil {
|
||||
data, err = reader.readFile(reader.documentRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
root, err := parseEditorXML(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
common := root.child("CommonData")
|
||||
if common == nil {
|
||||
return fmt.Errorf("document has no CommonData")
|
||||
}
|
||||
var definitions []byte
|
||||
registered := make(map[string]bool)
|
||||
for _, kind := range []string{"PublicRes", "DocumentRes"} {
|
||||
for _, node := range editorStructureChildren(common, kind) {
|
||||
registered[reader.ResPath(editorImportText(data, node))] = true
|
||||
}
|
||||
}
|
||||
var fonts, images []editorResource
|
||||
var spaces []ColorSpace
|
||||
for _, resource := range e.resources {
|
||||
if resource.name != "" {
|
||||
parts[resource.name] = resource.data
|
||||
}
|
||||
if resource.definition() != "" && !registered[resource.name] {
|
||||
definitions = append(definitions, common.textXML("DocumentRes", "/"+resource.name)...)
|
||||
registered[resource.name] = true
|
||||
}
|
||||
if resource.font != nil {
|
||||
fonts = append(fonts, resource)
|
||||
}
|
||||
if resource.image != nil {
|
||||
images = append(images, resource)
|
||||
}
|
||||
if resource.space != nil {
|
||||
spaces = append(spaces, *resource.space)
|
||||
}
|
||||
}
|
||||
if len(fonts)+len(images)+len(spaces) > 0 {
|
||||
encoded, err := e.encodeXML(func(x *ofdXML) { x.resources(fonts, images, spaces) })
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
doc, err := reader.Doc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name, added, err := mergePackageResources(ctx, reader, parts, doc, e.packageDirectory(), encoded)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if added {
|
||||
definitions = append(definitions, common.textXML("DocumentRes", "/"+name)...)
|
||||
}
|
||||
}
|
||||
var patches []editorXMLPatch
|
||||
if maximum := common.child("MaxUnitID"); maximum != nil {
|
||||
value, _ := strconv.Atoi(editorImportText(data, maximum))
|
||||
if e.maxID > value {
|
||||
patches = append(patches, editorXMLPatch{maximum.start, maximum.end, maximum.textXML("MaxUnitID", strconv.Itoa(e.maxID))})
|
||||
}
|
||||
}
|
||||
if len(definitions) > 0 {
|
||||
at := common.close
|
||||
for _, node := range common.children {
|
||||
if node.matchesOFD("TemplatePage") || node.matchesOFD("DefaultCS") {
|
||||
at = node.start
|
||||
break
|
||||
}
|
||||
}
|
||||
patches = append(patches, editorXMLPatch{at, at, definitions})
|
||||
}
|
||||
parts[reader.documentRoot] = editorPatchXML(data, patches)
|
||||
scan := &editorFontDocument{reader: reader, index: reader.DocumentIndex()}
|
||||
if err := scan.apply(ctx, parts); err != nil {
|
||||
return err
|
||||
}
|
||||
previous := e.transactionSnapshot()
|
||||
if err := e.commitResourceSnapshot(ctx, reader); err != nil {
|
||||
return err
|
||||
}
|
||||
for i := range e.pages {
|
||||
oldIndex := slices.IndexFunc(previous.pages, func(p PageContent) bool { return p.ID == e.pages[i].ID })
|
||||
if oldIndex < 0 || len(previous.pages[oldIndex].Content.Layer) == 0 {
|
||||
continue
|
||||
}
|
||||
states := make(map[string]GraphicObject)
|
||||
for _, layer := range previous.pages[oldIndex].Content.Layer {
|
||||
for _, object := range layer.Objects {
|
||||
states[editorObjectID(object)] = object
|
||||
}
|
||||
}
|
||||
page, err := e.page(i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for j := range page.Content.Layer {
|
||||
for k := range page.Content.Layer[j].Objects {
|
||||
object := &page.Content.Layer[j].Objects[k]
|
||||
if old, ok := states[editorObjectID(*object)]; ok {
|
||||
object.state = old.state
|
||||
object.TextObject.layout = old.TextObject.layout
|
||||
object.CompositeGraphicUnit.states = old.CompositeGraphicUnit.states
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user