Skip to main content

ScriptCascade

Struct ScriptCascade 

Source
pub struct ScriptCascade { /* private fields */ }
Available on crate feature 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

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn transcript_text(&self) -> String

The transcript, rendered the way the oracle writes it to stdout.

Source

pub fn stops(&self) -> &[ScriptFailure]

What went wrong, and in which script — the diagnostics a caller reads after a run.

Source

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".

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn drain_border_style_writes(&mut self) -> Vec<(u32, BorderStyle)>

What a script wrote through Field.borderStyle, drained.

Source

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.

Source

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.

Source

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.

Source

pub fn max_calculate_depth(&self) -> u32

How deep a calculation may nest, for a caller building a FieldWrites.

Source

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

Source§

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

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

/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)

/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, )

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>

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>

/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)>

Field.borderStyle writes a script made, drained. Read more
Source§

impl Debug for ScriptCascade

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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 more
Source§

impl<T> Pipe for T
where T: ?Sized,

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows 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
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows 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
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .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
where Self: BorrowMut<B>, B: ?Sized,

Calls .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
where Self: AsRef<R>, R: ?Sized,

Calls .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
where Self: AsMut<R>, R: ?Sized,

Calls .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
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.