Donner SVG 0.8.0
0.8.0 ยท ebf353960.8.0 main
SVG editor and embeddable C⁠+⁠+⁠20 engine.
Loading...
Searching...
No Matches
donner::editor::AsyncSVGDocument Class Reference

Wraps an svg::SVGDocument and the editor's per-frame command queue. More...

#include "donner/editor/AsyncSVGDocument.h"

Classes

struct  FlushResult
 Outcome of applying queued document mutations. More...

Public Types

enum class  ReplaceKind : uint8_t {
  FullReplace ,
  Structural
}
 Outcome of setDocumentMaybeStructural. FullReplace means the new doc differs structurally from the current one (or there was no current one) and every consumer of the old entity space must treat their state as invalid - identical to setDocument's contract. Structural means the new doc has the same XML shape and element ids, and the entity remap carried via the next RenderRequest lets downstream consumers (the compositor) preserve their caches.

Public Member Functions

 AsyncSVGDocument (const AsyncSVGDocument &)=delete
AsyncSVGDocument & operator= (const AsyncSVGDocument &)=delete
 AsyncSVGDocument (AsyncSVGDocument &&)=delete
AsyncSVGDocument & operator= (AsyncSVGDocument &&)=delete
void setDocument (svg::SVGDocument document)
 Replace the inner document. Clears any pending commands - they would reference now-invalid entities. Bumps the frame version.
bool usesEditorParserForSourceRecovery () const
 Whether this document was loaded or fully reparsed with the editor's established policy.
std::optional< EditorCommand::SourceRecoveryState > sourceRecoveryState () const
 Current source-pane recovery identity, available only while the original policy is intact.
ReplaceKind setDocumentMaybeStructural (svg::SVGDocument newDocument)
 Like setDocument, but builds a structural entity remap against the current document first. If the remap is non-empty (trees match by tag name + id at every step), the replacement is tagged as Structural - the next RenderRequest carries the remap so the compositor can call remapAfterStructuralReplace instead of resetAllLayers(documentReplaced=true), preserving cached layer bitmaps and segments across the swap. The current editor canvas size is also carried forward for structural replacements so the next render does not dirty every cache with a redundant resize. If the trees differ (user edited the source pane to change shape, etc.) the remap is empty and we fall back to the standard setDocument path.
std::unordered_map< Entity, Entity > consumePendingStructuralRemap ()
 Take ownership of the pending structural remap produced by the most recent setDocumentMaybeStructural(Structural) call. Returns an empty map if the last replacement was a FullReplace or nothing has been replaced since the last consumption. Called by RenderCoordinator when assembling the next RenderRequest.
bool hasDocument () const
 Whether a document has been loaded yet.
svg::SVGDocument & document ()
 Direct access to the inner document. UI thread only. The render thread should hold the snapshot returned by acquireRenderSnapshot() instead.
const svg::SVGDocument & document () const
 Return the current parsed SVG document under the caller's document-access policy.
void applyMutation (EditorCommand command)
 Push a command onto the per-frame queue. UI thread only.
xml::ApplySourceEditResult applySourceEdit (const xml::XMLEditIntent &intent)
 Apply an incremental source edit directly to the current document.
CommandQueue & queue ()
 Direct access to the command queue. Tools push via applyMutation; this accessor exists for tests and for the main loop's flushFrame.
bool hasPendingMutations () const
 Whether any document mutations are queued for the next frame flush.
bool flushFrame ()
 Drain and apply any pending commands. Called once per frame at the start of the main loop. Returns true if any commands were applied (so the caller can decide whether to re-render).
const FlushResult & lastFlushResult () const
 Metadata from the most recent flushFrame() call.
bool hasUnmirroredSourceDeltas () const
 True while flushed source deltas wait for the source pane to mirror them.
std::optional< std::vector< xml::XMLSourceDelta > > takeUnmirroredSourceDeltas ()
 Take the source deltas flushed since the previous call, in application order.
std::uint64_t nonTransformRevision () const
 Advances on every change that can alter a clip guide without changing the selected element's transform. Unlike lastFlushResult(), survives no-op frame flushes.
std::uint64_t documentGeneration () const
 Generation counter bumped only when setDocument replaces the inner SVGDocument (e.g. ReplaceDocumentCommand on source-pane edits). The inner document's storage address is stable across a replacement (the optional lives inside this object), so pointer-identity is NOT a reliable "is this the same document" check - consumers that cache per-document state (like the compositor's activeHints_ backing an entity space) need this counter to know when to tear that state down.
std::uint64_t currentFrameVersion () const
 Monotonic frame version counter. Bumped on every state change visible to the renderer (mutation flush or document replacement). The render thread polls this to detect updates without locking the document.
bool refreshFontResources ()
 Adopt font resolutions while the renderer and preview worker are idle. The frame version advances, but document generation, authored source, and undo history do not change.
bool setAnimationTime (double seconds)
 Advance playback without changing source, document identity, or the command queue.
bool restartAnimations ()
 Start a fresh animation session without source edits; retry when document access is busy.
bool dispatchMouseEvent (svg::EventType type, const svg::SVGElement &target)
 Deliver a preview mouse event without an authored edit. Busy access is retried by the caller.
std::uint64_t fontResourceRevision () const
 Frame-boundary font adoption identity, distinct from the manager's individual face counter.
bool loadFromString (std::string_view svgBytes)
 Test hook: re-parse svgBytes into a fresh document via SVGParser. On failure the existing document is left intact and lastParseError() returns the parser's diagnostic, so the caller can surface a line and reason in a text editor.
const std::optional< ParseDiagnostic > & lastParseError () const
 The diagnostic from the most recent failed loadFromString / ReplaceDocumentCommand. Cleared on every successful parse - so has_value() is the live "is the source pane currently invalid?" signal.
const std::vector< ParseDiagnostic > & parseDiagnostics () const
 All warnings and the fatal error, if any, published by the most recent parse operation.
std::uint64_t parseDiagnosticsRevision () const
 Monotonic revision for parseDiagnostics.

Static Public Attributes

static constexpr std::size_t kMaxUnmirroredSourceDeltas = 4096
 Most flushed source deltas kept for takeUnmirroredSourceDeltas() before they are dropped.

Detailed Description

Wraps an svg::SVGDocument and the editor's per-frame command queue.

Lifetime: owned by EditorApp (one per editor session). All public methods must be called from the UI thread; the only thread-safe operation is currentFrameVersion() which the render thread can poll.


Class Documentation

◆ donner::editor::AsyncSVGDocument::FlushResult

struct donner::editor::AsyncSVGDocument::FlushResult

Outcome of applying queued document mutations.

Class Members
bool appliedCommands = false
vector< Entity > cacheInvalidatedElements Entities whose existing rendered pixels may have changed because of an incremental command.
bool hadPriorAppliedCommandsOnRollback = false A prior command in this flush still changed source before that rollback.
bool onlyTransformCommands = false True only when every applied command changed an element transform. An overlay guide captured before a drag may be safely projected through these version advances without rereading clip resources; any other edit invalidates that immutable guide cache.
bool preserveUndoOnReparse = false
bool removedElements = false True when at least one flushed command removed an element from the live document.
bool replacedDocument = false
bool rolledBackReplacementBatch = false A failed replacement batch restored its exact pre-command source.
vector< XMLSourceDelta > sourceDeltas

Member Function Documentation

◆ applySourceEdit()

xml::ApplySourceEditResult donner::editor::AsyncSVGDocument::applySourceEdit ( const xml::XMLEditIntent & intent)

Apply an incremental source edit directly to the current document.

Unlike EditorCommand::Kind::ReplaceDocument, this preserves document identity and routes the edit through donner/base/xml so the XML source store owns both source bytes and emitted SVG mutations.

Parameters
intentSource edit request.

◆ dispatchMouseEvent()

bool donner::editor::AsyncSVGDocument::dispatchMouseEvent ( svg::EventType type,
const svg::SVGElement & target )

Deliver a preview mouse event without an authored edit. Busy access is retried by the caller.

Parameters
typeMouse event to deliver.
targetHit element in the current document.
Returns
True when an animation interval changed.

◆ documentGeneration()

std::uint64_t donner::editor::AsyncSVGDocument::documentGeneration ( ) const
inlinenodiscard

Generation counter bumped only when setDocument replaces the inner SVGDocument (e.g. ReplaceDocumentCommand on source-pane edits). The inner document's storage address is stable across a replacement (the optional lives inside this object), so pointer-identity is NOT a reliable "is this the same document" check - consumers that cache per-document state (like the compositor's activeHints_ backing an entity space) need this counter to know when to tear that state down.

Distinct from frameVersion_: the frame counter bumps on every mutation (including every drag frame's SetTransformCommand), which would be catastrophic to treat as a document replacement.

◆ flushFrame()

bool donner::editor::AsyncSVGDocument::flushFrame ( )

Drain and apply any pending commands. Called once per frame at the start of the main loop. Returns true if any commands were applied (so the caller can decide whether to re-render).

Bumps the frame version when commands are applied OR when the document itself was replaced via setDocument since the last flush.

◆ loadFromString()

bool donner::editor::AsyncSVGDocument::loadFromString ( std::string_view svgBytes)
nodiscard

Test hook: re-parse svgBytes into a fresh document via SVGParser. On failure the existing document is left intact and lastParseError() returns the parser's diagnostic, so the caller can surface a line and reason in a text editor.

Parameters
svgBytesSVG source bytes to parse.
Returns
True when the source parsed and replaced the document.

◆ setAnimationTime()

bool donner::editor::AsyncSVGDocument::setAnimationTime ( double seconds)

Advance playback without changing source, document identity, or the command queue.

Returns false when document access is busy or the time is unchanged.

Parameters
secondsFinite document time in seconds.

◆ takeUnmirroredSourceDeltas()

std::optional< std::vector< xml::XMLSourceDelta > > donner::editor::AsyncSVGDocument::takeUnmirroredSourceDeltas ( )
inlinenodiscard

Take the source deltas flushed since the previous call, in application order.

Every flushFrame() resets lastFlushResult(), including a no-op flush, so a tool that flushes its own edit and is followed by any other flush would otherwise lose the deltas before the source pane mirrors them. These accumulate until taken. Replacing the document discards them, because they describe source that no longer exists.

Hosts without a source pane never take them, so at most kMaxUnmirroredSourceDeltas are kept. Past that the list is dropped and this returns std::nullopt once: the caller must mirror the whole source instead.


The documentation for this class was generated from the following file: