mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-10 10:20:32 -06:00
Merge upstream/main into main preserving custom features
- Resolve all 13 merge conflicts between upstream/main and main - Preserve full image editing suite: OBB, crop, proportional resize, arrange, and context menu actions - Preserve text editing formatting tools: bullet/numbered lists, subscript/superscript, and line spacing - Cleanly integrate upstream's canvas modularization, font updates, and styling changes - Refactor arrange_image and run_edit_page_image helpers to satisfy clippy cognitive complexity limits - All engine, edit, and UI integration test suites passing cleanly
This commit is contained in:
@@ -1,4 +1,12 @@
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
use super::check_refresh_panic;
|
||||
use super::{
|
||||
Arc, DocId, Document, Edit, EditCtx, EditError, Label, MAX_UNDO, ObjectKind, OnceLock, RenderPool, SaveOptions, Scope, Session,
|
||||
XFA_REMOVED_PREFIX, XFA_SCRIPTS_OFF, check_permission, comment_list, display_bytes, display_config, guard, info_fields, inspect, js, keys_after,
|
||||
note_warnings, render_threads, run_edit, scan_colours, scope_of, shown_under_redactions, signatures_of, sync_xfa_state, undrawn_notices,
|
||||
uses_scripts, write_incremental, xfa, xfa_sync_datasets,
|
||||
};
|
||||
use crate::{EditNotice, MarkKind};
|
||||
|
||||
impl Session {
|
||||
/// Apply an edit. On success the previous state is undoable and the view data is refreshed.
|
||||
@@ -159,13 +167,7 @@ impl Session {
|
||||
if signed && ((rewrites(&next) && !rewrites(&editor.cos)) || (next.is_modified() && next.revisions().is_empty())) {
|
||||
return Err(EditError::SignedRewrite(edit.label().to_string()));
|
||||
}
|
||||
// What this edit drew with `?` (a value or comment text its font can't draw, stored as
|
||||
// typed): reported, never silent (AGENTS.md §4).
|
||||
let notices = if matches!(scope_of(&edit), Scope::Form | Scope::Comments | Scope::Full) {
|
||||
guard(|| undrawn_notices(&editor.cos, &next)).unwrap_or_default()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let notices = edit_notices(&edit, &editor.cos, &next);
|
||||
let previous = std::mem::replace(&mut editor.cos, next);
|
||||
let keys = keys_after(&edit).unwrap_or_else(|| editor.keys.clone());
|
||||
let previous_keys = std::mem::replace(&mut editor.keys, keys);
|
||||
@@ -373,7 +375,7 @@ impl Session {
|
||||
let signatures = if doc.signatures.is_empty() { Vec::new() } else { signatures_of(&editor.cos, &bytes, &doc.trust, &doc.sig_cache) };
|
||||
doc.display = display_bytes(Some(editor), &bytes);
|
||||
doc.signatures = Arc::new(signatures);
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), doc.config.clone());
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), display_config(&doc.config));
|
||||
doc.bytes = bytes;
|
||||
Ok(())
|
||||
}
|
||||
@@ -431,7 +433,7 @@ impl Session {
|
||||
let signatures = if doc.signatures.is_empty() { Vec::new() } else { signatures_of(&editor.cos, &bytes, &doc.trust, &doc.sig_cache) };
|
||||
doc.display = display_bytes(Some(editor), &bytes);
|
||||
doc.signatures = Arc::new(signatures);
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), doc.config.clone());
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), display_config(&doc.config));
|
||||
doc.bytes = bytes;
|
||||
doc.fonts_stale = true;
|
||||
Ok(())
|
||||
@@ -458,7 +460,7 @@ impl Session {
|
||||
/// After a refresh failed: draw the display bytes it left (the original, once released),
|
||||
/// so the page still shows a document.
|
||||
pub(super) fn show_released(doc: &mut Document) {
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), doc.config.clone());
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), display_config(&doc.config));
|
||||
}
|
||||
|
||||
/// Rebuild working bytes, inspection and renderer from the current edit state.
|
||||
@@ -515,8 +517,26 @@ impl Session {
|
||||
let signatures = signatures_of(&editor.cos, &bytes, &doc.trust, &doc.sig_cache);
|
||||
doc.display = display_bytes(Some(editor), &bytes);
|
||||
doc.signatures = Arc::new(signatures);
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), doc.config.clone());
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), display_config(&doc.config));
|
||||
doc.bytes = bytes;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// What `edit`, taking `prev` to `next`, wants said: never silent (AGENTS.md §4).
|
||||
fn edit_notices(edit: &Edit, prev: &pdfcraft_cos::Document, next: &pdfcraft_cos::Document) -> Vec<EditNotice> {
|
||||
// What it drew with `?` (a value or comment text its font can't draw, stored as typed).
|
||||
let mut notices: Vec<EditNotice> = if matches!(scope_of(edit), Scope::Form | Scope::Comments | Scope::Full) {
|
||||
guard(|| undrawn_notices(prev, next)).unwrap_or_default().into_iter().map(EditNotice::Undrawn).collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
// Pages whose own white backdrop Remove background couldn't turn back on.
|
||||
if matches!(edit, Edit::RemoveMarks { kind: MarkKind::Background }) {
|
||||
let pages = guard(|| pdfcraft_edit::backdrops_left_off(next)).unwrap_or_default();
|
||||
if !pages.is_empty() {
|
||||
notices.push(EditNotice::BackdropsLeftOff { pages });
|
||||
}
|
||||
}
|
||||
notices
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
use super::*;
|
||||
use super::{
|
||||
Arc, CombineSource, Combined, DataFormat, DocId, EditError, Hidden, ImageResolution, LOW_RESOLUTION_PRINT_DPI, OptimizeReport, SaveOptions,
|
||||
Session, SourceKind, SplitPart, decode_text, guard, open_source, open_source_with, optimize, print, print_raster, set_default_layer_state,
|
||||
source_kind, writable, write_full,
|
||||
};
|
||||
|
||||
impl Session {
|
||||
/// The page count of another PDF (Replace Pages, Insert Pages dialogs).
|
||||
@@ -64,10 +68,12 @@ impl Session {
|
||||
if pdf { Ok(bytes.clone()) } else { self.convert_to_pdf(name, bytes).map(|(_, pdf)| pdf) }
|
||||
}
|
||||
|
||||
/// Reduce File Size: Acrobat's defaults (images above 225 ppi to 150 ppi, JPEG medium
|
||||
/// quality; thumbnails dropped), identical resources merged, unused objects dropped, objects
|
||||
/// packed into compressed object streams. Returns the bytes and how many objects were
|
||||
/// merged. The open document is not changed (Acrobat saves the reduced copy as a new file).
|
||||
/// Reduce File Size: Acrobat's defaults (colour and grey images above 225 ppi to 150 ppi,
|
||||
/// JPEG medium quality; black-and-white averaged down to 300 ppi above 450 ppi, and stored as
|
||||
/// CCITT Group 4 whenever smaller; thumbnails dropped), identical resources merged, unused
|
||||
/// objects dropped, objects packed into compressed object streams. Returns the bytes and how
|
||||
/// many objects were merged. The open document is not changed (Acrobat saves the reduced copy
|
||||
/// as a new file).
|
||||
pub fn reduced_bytes(&self, id: DocId) -> Result<(Arc<Vec<u8>>, usize), EditError> {
|
||||
let (bytes, report) = self.optimized_bytes(id, &optimize::Settings::default(), &[])?;
|
||||
Ok((bytes, report.merged))
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use super::*;
|
||||
use super::{
|
||||
Arc, DocId, EditError, Keys, OpenError, RecoverySnapshot, RenderPool, SaveOptions, Session, SignOptions, TrustStore, display_bytes,
|
||||
display_config, guard, render_threads, signatures_of, writable, write_full, write_incremental, xfa_sync_datasets,
|
||||
};
|
||||
|
||||
impl Session {
|
||||
/// The bytes to write for Save: an incremental update of the file as opened/last saved,
|
||||
@@ -167,7 +170,7 @@ impl Session {
|
||||
{
|
||||
doc.config.reading_colors = old.config.reading_colors;
|
||||
doc.config.hide_comments = old.config.hide_comments;
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), doc.config.clone());
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), display_config(&doc.config));
|
||||
}
|
||||
// Caches keyed by the edit generation (edit lines, images, measurements) must see a new
|
||||
// one; there is nothing new to autosave.
|
||||
@@ -246,7 +249,7 @@ impl Session {
|
||||
let signatures = if doc.signatures.is_empty() { Vec::new() } else { signatures_of(&editor.cos, &doc.bytes, &doc.trust, &doc.sig_cache) };
|
||||
doc.display = display_bytes(Some(editor), &doc.bytes);
|
||||
doc.signatures = Arc::new(signatures);
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), doc.config.clone());
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), display_config(&doc.config));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use super::*;
|
||||
use super::{
|
||||
Arc, BookmarkPage, BookmarkRow, DocId, Document, EditError, LayerOp, OpenError, ReadingColors, RenderConfig, RenderPool, Session, SummarySort,
|
||||
apply_layer_state, comment_summary, display_config, local_utc_offset, outline_rows, parse_ymd, render_threads, use_layer_choices,
|
||||
};
|
||||
|
||||
impl Session {
|
||||
pub fn new() -> Self {
|
||||
@@ -243,7 +246,7 @@ impl Session {
|
||||
return false;
|
||||
}
|
||||
doc.config.hide_comments = hide;
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), doc.config.clone());
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), display_config(&doc.config));
|
||||
doc.generation += 1;
|
||||
true
|
||||
}
|
||||
@@ -256,7 +259,7 @@ impl Session {
|
||||
return false;
|
||||
}
|
||||
doc.config.reading_colors = colors;
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), doc.config.clone());
|
||||
doc.renderer = RenderPool::new(doc.display.clone(), render_threads(), display_config(&doc.config));
|
||||
doc.generation += 1;
|
||||
true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user