pub struct ScriptCascade { /* private fields */ }javascript only.Expand description
A boa-backed Cascade.
Built over one realm, which the whole session shares — because a document’s
scripts share a global and expect to, and because building a realm per
event would lose it.
Implementations§
Source§impl ScriptCascade
impl ScriptCascade
Sourcepub fn new(config: &ScriptConfig) -> Result<ScriptCascade, BuildError>
pub fn new(config: &ScriptConfig) -> Result<ScriptCascade, BuildError>
Builds a session with its own realm.
§Errors
Only if boa cannot build a context at all, which no input can cause.
Sourcepub fn transcript(&self) -> Vec<TranscriptLine>
pub fn transcript(&self) -> Vec<TranscriptLine>
Everything a script asked the host to do, in order.
The value the goldens are scored against. See
transcript::render for the bytes.
Sourcepub fn timers(&self) -> Vec<(String, i32)>
pub fn timers(&self) -> Vec<(String, i32)>
The timers this session currently has armed, as
(script, interval_ms).
A value the host reads rather than a process-wide registry — and a live one: a timer a script has cancelled, and a one-shot that has already fired, are gone from it.
Sourcepub fn advance_time(&mut self, elapsed: Duration) -> usize
pub fn advance_time(&mut self, elapsed: Duration) -> usize
Tells the session that elapsed passed, and runs whatever came due.
This library never reads a clock. A host with an event loop calls
this from its own timer; a test calls it with a number. Nothing here
starts a thread, and a session nobody advances fires nothing however
long it lives — which is what makes a document’s app.setInterval
inert in a renderer that only draws pages.
Answers how many timer scripts ran. Two rules a caller is likely to be surprised by: a timer fires at most once per call, however large the increment — so advancing five seconds in one step fires a one-second interval once, not five times — and a timer is re-armed before its script runs, so a script cancelling its own timer cancels the next firing rather than this one.
A script a timer runs is an ordinary script: it may throw, and its
failure is recorded on stops like any other.
Sourcepub fn fail_next_timer(&mut self)
pub fn fail_next_timer(&mut self)
Makes the next timer a script arms fail to arm.
A host that cannot give out another timer, which upstream models with
SetFailNextTimer — the script still gets a timer object back, its id
is the invalid 0, and nothing ever fires. Exported because it is the
only way to reach the branch a crash regression pins.
Sourcepub fn record_named_action(&mut self, name: impl Into<String>)
pub fn record_named_action(&mut self, name: impl Into<String>)
Records a named viewer action — /S /Named — on the transcript.
An action the document asks for that runs no JavaScript at all:
Print, NextPage, SaveAs and the rest. It reaches the host
through CPDFSDK_FormFillEnvironment::ExecuteNamedAction, exactly as
an alert does — nothing is performed here either, and a host reads the
request back off transcript and decides.
Recorded by the caller rather than found here, for the same reason
every /AA script is: reading an action dictionary needs a document,
and this type holds none.
Sourcepub fn transcript_text(&self) -> String
pub fn transcript_text(&self) -> String
The transcript, rendered the way the oracle writes it to stdout.
Sourcepub fn stops(&self) -> &[ScriptFailure]
pub fn stops(&self) -> &[ScriptFailure]
What went wrong, and in which script — the diagnostics a caller reads after a run.
Sourcepub fn run(&mut self, source: &str, whence: &str) -> bool
pub fn run(&mut self, source: &str, whence: &str) -> bool
Runs one script, recording anything it asked for and anything that stopped it.
The bool is the answer, not a failed mutation: true means the
script completed, false means a reason was recorded on
stops. Never panics and never propagates an engine
error to the caller. A script is untrusted input: a parse failure, a
thrown exception and an exhausted limit are the three ordinary
outcomes, and all three answer false here with a recorded reason.
whence names the script for the diagnostic — a field name, or
"/OpenAction".
Sourcepub fn last_stop_was_a_limit(&self) -> bool
pub fn last_stop_was_a_limit(&self) -> bool
Whether the last thing that stopped a script was a limit rather than the script’s own logic.
The distinction a caller cares about: a script that threw said something about the document, and one that ran out of budget said nothing at all.
Sourcepub fn format_on_load(&mut self, field: &FieldRef) -> bool
pub fn format_on_load(&mut self, field: &FieldRef) -> bool
Runs a field’s /AA /F the way loading its page does, discarding the
display string.
§Why a page load runs a formatter at all
Reading a page builds every widget on it, and building a text field or
a combo box runs its format script so the stored value can be drawn
as a formatted one. The script’s answer reaches the appearance and
never /V, and for a text field upstream then drops it — only a combo
box regenerates from it. What is not dropped is everything the
script asked the host to do on its way there, which is why a document
whose only script is a formatter still prints alerts on open.
The bool is whether the script completed.
Sourcepub fn set_field(
&mut self,
index: u32,
name: impl Into<String>,
value: impl Into<String>,
actions: FieldActions,
)
pub fn set_field( &mut self, index: u32, name: impl Into<String>, value: impl Into<String>, actions: FieldActions, )
Installs one field’s scripts, its name and its current value.
The caller reads /AA and hands it over, because reading it needs a
document and this type deliberately holds none.
Sourcepub fn set_document(&mut self, document: DocumentModel)
pub fn set_document(&mut self, document: DocumentModel)
Installs what the Doc object answers from.
The document half of the same bargain set_field
struck: this type holds no PDF, so the caller reads one and hands over
a value. model::read is that reader for a pdfrum catalog, and a
host with its own document type writes its own.
Without this the object model is still bound — getField exists
and is callable — and answers as an empty document would: no pages, no
fields, and undefined from getField. That is the honest answer for
a realm nobody told about a document, and it is why an unbound name is
never what a script meets.
Sourcepub fn drain_field_writes(&mut self) -> Vec<(u32, String)>
pub fn drain_field_writes(&mut self) -> Vec<(u32, String)>
What a script wrote through Field.value or Doc.resetForm, drained.
A value the caller reads back, not a write this type performed: applying it from inside a native function would re-enter the cascade the script is already inside. The caller spends these through the ordinary commit path, so the appearance regenerates the way any other value change does.
Each entry is a /Fields position and the value the script set — the
same shape FieldWrites carries, and the same index space.
Sourcepub fn drain_border_style_writes(&mut self) -> Vec<(u32, BorderStyle)>
pub fn drain_border_style_writes(&mut self) -> Vec<(u32, BorderStyle)>
What a script wrote through Field.borderStyle, drained.
Sourcepub fn field_value(&self, index: u32) -> Option<String>
pub fn field_value(&self, index: u32) -> Option<String>
The value the object model currently holds for a field.
What a script last set through Field.value, or what the caller
installed. The caller reads this when applying a write it drained, so
the model and the session agree.
Sourcepub fn set_field_value(&mut self, index: u32, value: impl Into<String>)
pub fn set_field_value(&mut self, index: u32, value: impl Into<String>)
Tells the object model a field’s value changed outside a script.
A user typing into a field must be visible to the next script that
reads getField(name).value, and this crate holds no document to
re-read — so the caller says so, exactly as it says what the value was
at install time.
Sourcepub fn set_calculation_order(&mut self, order: Vec<u32>)
pub fn set_calculation_order(&mut self, order: Vec<u32>)
Installs the /CO calculation order — the field indices a calculation
sweep visits, in the order it visits them.
An empty order means no calculation runs, which is the answer for a
document with no /CO array and is not a fallback to “every field”;
see pdfrum_doc’s Form::calculation_order.
Sourcepub fn max_calculate_depth(&self) -> u32
pub fn max_calculate_depth(&self) -> u32
How deep a calculation may nest, for a caller building a
FieldWrites.
Sourcepub fn drain_diagnostics(
&mut self,
diags: &mut Diagnostics,
) -> Vec<ScriptFailure>
pub fn drain_diagnostics( &mut self, diags: &mut Diagnostics, ) -> Vec<ScriptFailure>
Records this session’s stops as diagnostics on the caller’s sink, and hands back what each of them said.
Kept separate from ScriptCascade::run so a caller decides when
diagnostics are drained, and so the cascade methods — whose signatures
take no Diagnostics — can still be honest about what happened.
§Why it returns the failures rather than only recording them
Diagnostic is a kind, a severity and a
byte offset — a bounded sink a hostile file must not be able to grow —
so it can say that a script threw but not which one or what it
said. The kind goes on the sink and the detail comes back here.
The session is drained: a second call answers nothing.
Trait Implementations§
Source§impl Cascade for ScriptCascade
impl Cascade for ScriptCascade
Source§fn keystroke(&mut self, field: &FieldRef, change: Keystroke) -> KeystrokeOutcome
fn keystroke(&mut self, field: &FieldRef, change: Keystroke) -> KeystrokeOutcome
The keystroke hook: /AA /K with willCommit false.
The script may rewrite event.change and move the selection, and
what it left is what gets applied — only the change and the two
selection indices are read back. A write to event.value on this path
compiles, does not throw, and is discarded.
Source§fn keystroke_commit(&mut self, field: &FieldRef, value: &str) -> bool
fn keystroke_commit(&mut self, field: &FieldRef, value: &str) -> bool
The same /AA /K with a commit imminent, which is the only thing that
differs: willCommit is true and event.value is the whole value
rather than the text before an insertion.
Source§fn validate(&mut self, field: &FieldRef, value: &str) -> bool
fn validate(&mut self, field: &FieldRef, value: &str) -> bool
/AA /V. event.rc is the whole answer; a write to event.value is
discarded exactly as on the keystroke path.
Source§fn calculate(&mut self, writes: &mut FieldWrites, trigger: &FieldRef)
fn calculate(&mut self, writes: &mut FieldWrites, trigger: &FieldRef)
/AA /C, over the whole calculation order.
One call runs the entire sweep: /CO is walked and each field
written in turn. The three-way gate is normative — a calculated value
is written only if the script did not throw, and event.rc is
still truthy, and the string actually changed.
The busy_ guard is FieldWrites’s depth budget, whose default is
1 because upstream permits no nesting at all.
Source§fn pointer(
&mut self,
field: &FieldRef,
trigger: PointerTrigger,
held: Modifiers,
)
fn pointer( &mut self, field: &FieldRef, trigger: PointerTrigger, held: Modifiers, )
One of the six pointer and focus /AA entries.
The trigger decides which script and which event.name; the two
modifier flags are all the event object exposes of what was held.
Source§fn take_focus_request(&mut self) -> Option<u32>
fn take_focus_request(&mut self) -> Option<u32>
The field the last Field.setFocus() named, drained.
CJS_Field::setFocus reaches CPDFSDK_FormFillEnvironment::SetFocusAnnot,
which kills the outgoing widget’s focus — firing its /AA /Bl — and
then gives the keyboard to the incoming one, firing its /AA /Fo.
Neither half can run from inside the native function without
re-entering the routing the script is already inside, so the request
is recorded here and the caller spends it.
The last call wins. The slot holds one field, so a script calling
setFocus twice moves the keyboard once, to the second field — which
is upstream’s shape, where each call overwrites focus_annot_ and only
the final one survives the script.
Source§fn format(&mut self, field: &FieldRef, value: &str) -> Option<String>
fn format(&mut self, field: &FieldRef, value: &str) -> Option<String>
/AA /F.
The write reaches the appearance only, never /V. event.value
is bound to a local string; what the script leaves there is drawn,
and re-running with no formatter reverts the appearance to the raw
value.
Format also hard-codes willCommit = true and leaves rc unbound,
so a Format script’s event.rc writes reach nothing.
Source§fn drain_border_style_writes(&mut self) -> Vec<(u32, BorderStyle)>
fn drain_border_style_writes(&mut self) -> Vec<(u32, BorderStyle)>
Field.borderStyle writes a script made, drained. Read moreAuto Trait Implementations§
impl !RefUnwindSafe for ScriptCascade
impl !Send for ScriptCascade
impl !Sync for ScriptCascade
impl !UnwindSafe for ScriptCascade
impl Freeze for ScriptCascade
impl Unpin for ScriptCascade
impl UnsafeUnpin for ScriptCascade
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.