mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 02:19:56 -06:00
Plug-ins: a filter run given more read-only objects than an output lists fails up front
An output lists at most 100,000 objects and must return every read-only object, so an input with more than that many is now an object-budget limit before the plug-in starts.
This commit is contained in:
@@ -703,7 +703,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Run Plug-in",
|
||||
[],
|
||||
None,
|
||||
"{id, params?: {…} (the plug-in's parameters; or give them as top-level keys; missing ones take their defaults, see plugin.info), ids?: [..] (default: the selection), …the plug-in's parameters as top-level keys} run an object filter on the selected paths and compound paths (inside selected groups and layers too; hidden, locked, guide and clipping paths, compound paths that clip a clip group and paths inside a group that clips one are left out): it may change, delete or add objects, as one undo step; the result is selected, except the objects it locked or made guides. A filter whose manifest lists inputs (type, image, symbolInstance; it lists doc.read in permissions, so plugin.install needs grant) is also given the selected objects of those kinds to read, with at most 16 MiB of pixels and 16 MiB of type runs per run (later ones come with pixelsOmitted or truncated); every object counts toward the input's half of the plug-in's memory cap, ids, bounds, transforms and names included, and an object whose fields besides its pixels and runs don't fit fails the run with a memory-budget error naming it and its size (a path or compound path fails it with the memory-budget error for a selection too large to hand over): its output returns each as {id} or exactly as given, or the run is refused and nothing changes. With nothing selected it gets no objects (generators add theirs to the current layer) → {plugin, ids}",
|
||||
"{id, params?: {…} (the plug-in's parameters; or give them as top-level keys; missing ones take their defaults, see plugin.info), ids?: [..] (default: the selection), …the plug-in's parameters as top-level keys} run an object filter on the selected paths and compound paths (inside selected groups and layers too; hidden, locked, guide and clipping paths, compound paths that clip a clip group and paths inside a group that clips one are left out): it may change, delete or add objects, as one undo step; the result is selected, except the objects it locked or made guides. A filter whose manifest lists inputs (type, image, symbolInstance; it lists doc.read in permissions, so plugin.install needs grant) is also given the selected objects of those kinds to read, with at most 16 MiB of pixels and 16 MiB of type runs per run (later ones come with pixelsOmitted or truncated); every object counts toward the input's half of the plug-in's memory cap, ids, bounds, transforms and names included, and an object whose fields besides its pixels and runs don't fit fails the run with a memory-budget error naming it and its size (a path or compound path fails it with the memory-budget error for a selection too large to hand over), and more than 100,000 of these objects fail it with an object-budget error: its output returns each as {id} or exactly as given, or the run is refused and nothing changes. With nothing selected it gets no objects (generators add theirs to the current layer) → {plugin, ids}",
|
||||
has_doc,
|
||||
run
|
||||
),
|
||||
|
||||
@@ -187,8 +187,9 @@ pub fn encode_input(doc: &Document, ids: &[NodeId]) -> Vec<u8> {
|
||||
/// input may be. Every object counts toward `capacity` in order, ids, bounds, transforms and names
|
||||
/// included: pixels or text that don't fit what is left are omitted (`pixelsOmitted`,
|
||||
/// `truncated`), a read-only object whose other fields alone don't fit is an [`Error::Limit`]
|
||||
/// naming it and its size, and a path or compound path that doesn't fit is the limit the runtime
|
||||
/// gives an input past its share. Also returns those objects by id, which the filter
|
||||
/// naming it and its size, a path or compound path that doesn't fit is the limit the runtime gives
|
||||
/// an input past its share, and more than [`MAX_OBJECTS`] read-only objects, more than an output
|
||||
/// may list, is an [`Error::Limit`] too. Also returns those objects by id, which the filter
|
||||
/// must return as they were ([`decode_output_with`]).
|
||||
pub fn encode_input_with(doc: &Document, ids: &[NodeId], kinds: &[InputKind], capacity: usize) -> Result<(Vec<u8>, HashMap<NodeId, Value>)> {
|
||||
encode_input_within(doc, ids, kinds, Allowance { input: capacity.saturating_sub(EMPTY_INPUT.len()), ..Allowance::FULL })
|
||||
@@ -221,6 +222,8 @@ fn encode_input_within(doc: &Document, ids: &[NodeId], kinds: &[InputKind], mut
|
||||
for n in ids.iter().filter_map(|id| doc.node(*id)) {
|
||||
let path;
|
||||
let (o, checked): (&Value, bool) = match input_kind(n).filter(|k| kinds.contains(k)) {
|
||||
// The output must return every read-only object, and lists at most `MAX_OBJECTS`.
|
||||
Some(_) if read_only.len() >= MAX_OBJECTS => return Err(too_many_read_only()),
|
||||
Some(_) => match encode_read_only_within(doc, n, &symbols, &mut left)? {
|
||||
Some(o) => (read_only.entry(n.id).insert_entry(o).into_mut(), true),
|
||||
None => continue,
|
||||
@@ -257,6 +260,11 @@ fn too_large(n: &Node, size: usize, left: usize) -> Error {
|
||||
Error::Limit(format!("memory budget (object {} needs {size} bytes of input, {left} left)", n.id.0))
|
||||
}
|
||||
|
||||
/// The error for an input with more read-only objects than an output may list.
|
||||
fn too_many_read_only() -> Error {
|
||||
Error::Limit(format!("object budget (more than {MAX_OBJECTS} read-only objects)"))
|
||||
}
|
||||
|
||||
/// The kind of read-only object `n` is: type, an image or a symbol instance (`None` for others).
|
||||
pub fn input_kind(n: &Node) -> Option<InputKind> {
|
||||
match &n.kind {
|
||||
|
||||
@@ -556,6 +556,26 @@ fn a_path_past_the_input_capacity_is_the_runtime_limit() {
|
||||
assert_eq!(e.to_string(), "plug-in exceeded its memory budget (the selection is too large to hand over)");
|
||||
}
|
||||
|
||||
/// An output lists at most [`MAX_OBJECTS`] objects and must return every read-only one, so an input
|
||||
/// with more read-only objects than that is a limit; exactly that many are given.
|
||||
#[test]
|
||||
fn more_read_only_objects_than_an_output_lists_is_a_limit() {
|
||||
let (mut d, _, layer, [.., ghost]) = mixed();
|
||||
let mut ids = vec![ghost];
|
||||
for _ in 1..MAX_OBJECTS {
|
||||
let n = Node::new(d.alloc_id(), NodeKind::SymbolInstance { symbol: "Gone".into(), xf: Affine::IDENTITY });
|
||||
ids.push(d.insert(Some(layer), usize::MAX, n).unwrap());
|
||||
}
|
||||
let (_, read_only) = encode_input_with(&d, &ids, &[InputKind::SymbolInstance], usize::MAX).unwrap();
|
||||
assert_eq!(read_only.len(), MAX_OBJECTS);
|
||||
let n = Node::new(d.alloc_id(), NodeKind::SymbolInstance { symbol: "Gone".into(), xf: Affine::IDENTITY });
|
||||
ids.push(d.insert(Some(layer), usize::MAX, n).unwrap());
|
||||
let e = encode_input_with(&d, &ids, &[InputKind::SymbolInstance], usize::MAX).unwrap_err();
|
||||
assert_eq!(e.to_string(), format!("plug-in exceeded its object budget (more than {MAX_OBJECTS} read-only objects)"));
|
||||
// A filter that doesn't list the kind is given none of them.
|
||||
assert!(encode_input_with(&d, &ids, &[], usize::MAX).unwrap().1.is_empty());
|
||||
}
|
||||
|
||||
/// Objects that clip a clip group are left out, and so are those inside a group that clips one;
|
||||
/// those it clips are given. This covers a filter that lists no `inputs` too.
|
||||
#[test]
|
||||
|
||||
@@ -5921,6 +5921,8 @@ digits Malayalam Malaiàlam
|
||||
@msg `inputs` lists `{shown}` twice `inputs` inclou `{shown}` dues vegades
|
||||
@msg `inputs` needs `api` 2 or later `inputs` requereix `api` 2 o posterior
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` requereix el permís `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) pressupost de memòria (l’objecte {_1} necessita {size} bytes d’entrada, en queden {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) pressupost d’objectes (més de {MAX_OBJECTS} objectes de només lectura)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it el permís `{shown}` està reservat per a una API de complements posterior; aquest amfitrió no el concedeix
|
||||
@msg unknown permission `{shown}` permís desconegut `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees «{name}» demana els permisos {asked}: instal·la’l amb un `grant` que els enumeri quan l’usuari hi estigui d’acord
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5908,6 +5908,8 @@ axis Y Axis osa Y
|
||||
@msg `inputs` lists `{shown}` twice `inputs` uvádí `{shown}` dvakrát
|
||||
@msg `inputs` needs `api` 2 or later `inputs` vyžaduje `api` 2 nebo vyšší
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` vyžaduje oprávnění `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) rozpočet paměti (objekt {_1} potřebuje {size} bajtů vstupu, zbývá {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) rozpočet objektů (více než {MAX_OBJECTS} objektů jen pro čtení)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it oprávnění `{shown}` je vyhrazeno pro pozdější API zásuvných modulů; tento hostitel ho neuděluje
|
||||
@msg unknown permission `{shown}` neznámé oprávnění `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees „{name}“ žádá o oprávnění {asked}: nainstalujte ho s `grant`, který je uvádí, jakmile uživatel souhlasí
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5490,6 +5490,8 @@ axis Y Axis Y-Achse
|
||||
@msg `inputs` lists `{shown}` twice `inputs` führt `{shown}` doppelt auf
|
||||
@msg `inputs` needs `api` 2 or later `inputs` erfordert `api` 2 oder höher
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` erfordert die Berechtigung `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) Speicherbudget (Objekt {_1} benötigt {size} Byte Eingabe, {left} verbleiben)
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) Objektbudget (mehr als {MAX_OBJECTS} schreibgeschützte Objekte)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it die Berechtigung `{shown}` ist für eine spätere Plug-in-API reserviert; dieser Host gewährt sie nicht
|
||||
@msg unknown permission `{shown}` unbekannte Berechtigung `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees „{name}“ verlangt die Berechtigungen {asked}: Installieren Sie es mit `grant`, das sie aufführt, sobald der Benutzer zustimmt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5859,6 +5859,8 @@ axis Y Axis Άξονας Y
|
||||
@msg `inputs` lists `{shown}` twice το `inputs` αναφέρει το `{shown}` δύο φορές
|
||||
@msg `inputs` needs `api` 2 or later το `inputs` απαιτεί `api` 2 ή νεότερο
|
||||
@msg `inputs` needs the permission `doc.read` το `inputs` απαιτεί το δικαίωμα `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) προϋπολογισμός μνήμης (το αντικείμενο {_1} χρειάζεται {size} byte εισόδου, απομένουν {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) προϋπολογισμός αντικειμένων (περισσότερα από {MAX_OBJECTS} αντικείμενα μόνο για ανάγνωση)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it το δικαίωμα `{shown}` είναι δεσμευμένο για μεταγενέστερο API προσθέτων· αυτός ο κεντρικός υπολογιστής δεν το παραχωρεί
|
||||
@msg unknown permission `{shown}` άγνωστο δικαίωμα `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees το «{name}» ζητά τα δικαιώματα {asked}: εγκαταστήστε το με ένα `grant` που τα απαριθμεί μόλις συμφωνήσει ο χρήστης
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 168 and column 5.
|
@@ -5849,6 +5849,8 @@ axis Y Axis Eje Y
|
||||
@msg `inputs` lists `{shown}` twice `inputs` incluye `{shown}` dos veces
|
||||
@msg `inputs` needs `api` 2 or later `inputs` requiere `api` 2 o posterior
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` requiere el permiso `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) presupuesto de memoria (el objeto {_1} necesita {size} bytes de entrada, quedan {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) presupuesto de objetos (más de {MAX_OBJECTS} objetos de solo lectura)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it el permiso `{shown}` está reservado para una API de plugins posterior; este host no lo concede
|
||||
@msg unknown permission `{shown}` permiso desconocido `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees “{name}” pide los permisos {asked}: instálalo con un `grant` que los incluya cuando el usuario lo acepte
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5938,6 +5938,8 @@ axis Y Axis Y-akseli
|
||||
@msg `inputs` lists `{shown}` twice `inputs` luettelee kohteen `{shown}` kahdesti
|
||||
@msg `inputs` needs `api` 2 or later `inputs` edellyttää `api`-tasoa 2 tai uudempaa
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` edellyttää käyttöoikeutta `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) muistibudjetti (objekti {_1} tarvitsee {size} tavua syötettä, jäljellä {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) objektibudjetti (yli {MAX_OBJECTS} vain luku -objektia)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it käyttöoikeus `{shown}` on varattu myöhemmälle laajennus-API:lle; tämä isäntä ei myönnä sitä
|
||||
@msg unknown permission `{shown}` tuntematon käyttöoikeus `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees ”{name}” pyytää käyttöoikeuksia {asked}: asenna se `grant`-luettelolla, jossa ne ovat, kun käyttäjä suostuu
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5904,6 +5904,8 @@ axis Y Axis Axe Y
|
||||
@msg `inputs` lists `{shown}` twice `inputs` mentionne `{shown}` deux fois
|
||||
@msg `inputs` needs `api` 2 or later `inputs` nécessite `api` 2 ou plus
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` nécessite l’autorisation `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) budget mémoire (l’objet {_1} nécessite {size} octets d’entrée, il en reste {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) budget d’objets (plus de {MAX_OBJECTS} objets en lecture seule)
|
||||
@msg unknown permission `{shown}` autorisation inconnue `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees « {name} » demande les autorisations {asked} : installez-le avec `grant` qui les liste une fois que l’utilisateur l’accepte
|
||||
@msg “{name}” wasn't granted `{p}`, which its output needs: nothing was changed « {name} » n’a pas reçu `{p}`, dont sa sortie a besoin : rien n’a été modifié
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5268,6 +5268,8 @@
|
||||
@msg `inputs` lists `{shown}` twice `inputs` में `{shown}` दो बार सूचीबद्ध है
|
||||
@msg `inputs` needs `api` 2 or later `inputs` के लिए `api` 2 या बाद का स्तर आवश्यक है
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` के लिए अनुमति `doc.read` आवश्यक है
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) मेमोरी बजट (ऑब्जेक्ट {_1} को इनपुट के {size} बाइट चाहिए, {left} शेष हैं)
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) ऑब्जेक्ट बजट ({MAX_OBJECTS} से अधिक केवल-पठन ऑब्जेक्ट)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it अनुमति `{shown}` बाद के प्लग-इन API के लिए आरक्षित है; यह होस्ट इसे नहीं देता
|
||||
@msg unknown permission `{shown}` अज्ञात अनुमति `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees “{name}” अनुमतियां {asked} मांगता है: उपयोगकर्ता की सहमति मिलने पर इसे उन्हें सूचीबद्ध करने वाले `grant` के साथ इंस्टॉल करें
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5891,6 +5891,8 @@ axis Y Axis Y tengely
|
||||
@msg `inputs` lists `{shown}` twice az `inputs` kétszer sorolja fel ezt: `{shown}`
|
||||
@msg `inputs` needs `api` 2 or later az `inputs` használatához `api` 2 vagy újabb szükséges
|
||||
@msg `inputs` needs the permission `doc.read` az `inputs` használatához a(z) `doc.read` engedély szükséges
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) memóriakeret (a(z) {_1} objektumnak {size} bájt bemenet kell, {left} maradt)
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) objektumkeret (több mint {MAX_OBJECTS} csak olvasható objektum)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it a(z) `{shown}` engedély egy későbbi bővítmény-API számára van fenntartva; ez a gazdaprogram nem adja meg
|
||||
@msg unknown permission `{shown}` ismeretlen engedély: `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees a(z) „{name}” a következő engedélyeket kéri: {asked}; telepítsd egy őket felsoroló `grant` értékkel, ha a felhasználó beleegyezik
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5524,6 +5524,8 @@ axis Y Axis Asse Y
|
||||
@msg `inputs` lists `{shown}` twice `inputs` elenca `{shown}` due volte
|
||||
@msg `inputs` needs `api` 2 or later `inputs` richiede `api` 2 o successivo
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` richiede l’autorizzazione `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) budget di memoria (l’oggetto {_1} richiede {size} byte di input, ne restano {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) budget di oggetti (più di {MAX_OBJECTS} oggetti di sola lettura)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it l’autorizzazione `{shown}` è riservata a un’API dei plug-in successiva; questo host non la concede
|
||||
@msg unknown permission `{shown}` autorizzazione sconosciuta `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees “{name}” chiede le autorizzazioni {asked}: installalo con un `grant` che le elenca quando l’utente acconsente
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5589,6 +5589,8 @@ axis Y Axis Y 軸
|
||||
@msg `inputs` lists `{shown}` twice `inputs` に `{shown}` が 2 回指定されています
|
||||
@msg `inputs` needs `api` 2 or later `inputs` には `api` 2 以上が必要です
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` には権限 `doc.read` が必要です
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) メモリ予算 (オブジェクト {_1} には {size} バイトの入力が必要ですが、残りは {left} です)
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) オブジェクト予算 ({MAX_OBJECTS} 個を超える読み取り専用オブジェクト)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it 権限 `{shown}` は今後のプラグイン API 用に予約されています。このホストはこの権限を付与しません
|
||||
@msg unknown permission `{shown}` 不明な権限 `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees 「{name}」は権限 {asked} を求めています。ユーザーが同意したら、それらを列挙した `grant` を指定してインストールしてください
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5832,6 +5832,8 @@ axis Y Axis Y ღერძი
|
||||
@msg `inputs` lists `{shown}` twice `inputs`-ში `{shown}` ორჯერაა ჩამოთვლილი
|
||||
@msg `inputs` needs `api` 2 or later `inputs`-ს სჭირდება `api` 2 ან უფრო ახალი
|
||||
@msg `inputs` needs the permission `doc.read` `inputs`-ს სჭირდება ნებართვა `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) მეხსიერების ბიუჯეტი (ობიექტს {_1} სჭირდება შეყვანის {size} ბაიტი, დარჩენილია {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) ობიექტების ბიუჯეტი ({MAX_OBJECTS}-ზე მეტი მხოლოდ წასაკითხი ობიექტი)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it ნებართვა `{shown}` დაჯავშნილია პლაგინების მომავალი API-სთვის; ეს ჰოსტი მას არ გასცემს
|
||||
@msg unknown permission `{shown}` უცნობი ნებართვა `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees „{name}“ ითხოვს ნებართვებს {asked}: მომხმარებლის თანხმობის შემდეგ დააყენეთ ის `grant` პარამეტრით, რომელშიც ისინი ჩამოთვლილია
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5485,6 +5485,8 @@ axis Y Axis Y축
|
||||
@msg `inputs` lists `{shown}` twice `inputs`에 `{shown}`이(가) 두 번 나열되어 있습니다
|
||||
@msg `inputs` needs `api` 2 or later `inputs`에는 `api` 2 이상이 필요합니다
|
||||
@msg `inputs` needs the permission `doc.read` `inputs`에는 `doc.read` 권한이 필요합니다
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) 메모리 예산(개체 {_1}에 입력 {size}바이트가 필요하지만 {left}바이트 남음)
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) 개체 예산(읽기 전용 개체 {MAX_OBJECTS}개 초과)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it `{shown}` 권한은 이후 플러그인 API용으로 예약되어 있습니다. 이 호스트는 이 권한을 부여하지 않습니다
|
||||
@msg unknown permission `{shown}` 알 수 없는 권한 `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees “{name}”은(는) {asked} 권한을 요청합니다. 사용자가 동의하면 이를 나열한 `grant`로 설치하세요
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5761,6 +5761,8 @@ axis Y Axis Oś Y
|
||||
@msg `inputs` lists `{shown}` twice `inputs` wymienia `{shown}` dwa razy
|
||||
@msg `inputs` needs `api` 2 or later `inputs` wymaga `api` 2 lub nowszego
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` wymaga uprawnienia `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) budżet pamięci (obiekt {_1} wymaga {size} bajtów danych wejściowych, pozostało {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) budżet obiektów (ponad {MAX_OBJECTS} obiektów tylko do odczytu)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it uprawnienie `{shown}` jest zarezerwowane dla późniejszego API wtyczek; ten host go nie przyznaje
|
||||
@msg unknown permission `{shown}` nieznane uprawnienie `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees „{name}” prosi o uprawnienia {asked}: zainstaluj ją z `grant`, który je wymienia, gdy użytkownik się zgodzi
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5823,6 +5823,8 @@ axis Y Axis Eixo Y
|
||||
@msg `inputs` lists `{shown}` twice `inputs` lista `{shown}` duas vezes
|
||||
@msg `inputs` needs `api` 2 or later `inputs` exige `api` 2 ou posterior
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` exige a permissão `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) orçamento de memória (o objeto {_1} precisa de {size} bytes de entrada, restam {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) orçamento de objetos (mais de {MAX_OBJECTS} objetos somente leitura)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it a permissão `{shown}` está reservada para uma API de plug-in futura; este host não a concede
|
||||
@msg unknown permission `{shown}` permissão desconhecida `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees “{name}” pede as permissões {asked}: instale-o com `grant` listando-as depois que o usuário concordar
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -5519,6 +5519,8 @@ axis Y Axis Ось Y
|
||||
@msg `inputs` lists `{shown}` twice в `inputs` `{shown}` указано дважды
|
||||
@msg `inputs` needs `api` 2 or later для `inputs` нужен `api` 2 или выше
|
||||
@msg `inputs` needs the permission `doc.read` для `inputs` нужно разрешение `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) бюджет памяти (объекту {_1} нужно {size} байт входных данных, осталось {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) бюджет объектов (более {MAX_OBJECTS} объектов только для чтения)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it разрешение `{shown}` зарезервировано для будущего API модулей; этот хост его не выдаёт
|
||||
@msg unknown permission `{shown}` неизвестное разрешение `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees «{name}» запрашивает разрешения {asked}: установите его с `grant`, где они перечислены, когда пользователь согласится
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5931,6 +5931,8 @@ axis Y Axis Y-axel
|
||||
@msg `inputs` lists `{shown}` twice `inputs` anger `{shown}` två gånger
|
||||
@msg `inputs` needs `api` 2 or later `inputs` kräver `api` 2 eller senare
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` kräver behörigheten `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) minnesbudget (objekt {_1} behöver {size} byte indata, {left} återstår)
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) objektbudget (fler än {MAX_OBJECTS} skrivskyddade objekt)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it behörigheten `{shown}` är reserverad för ett senare plugin-API; den här värden beviljar den inte
|
||||
@msg unknown permission `{shown}` okänd behörighet `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees ”{name}” begär behörigheterna {asked}: installera det med en `grant` som listar dem när användaren har godkänt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -5865,6 +5865,8 @@ axis Y Axis Y ekseni
|
||||
@msg `inputs` lists `{shown}` twice `inputs` `{shown}` değerini iki kez listeliyor
|
||||
@msg `inputs` needs `api` 2 or later `inputs` için `api` 2 veya üstü gerekir
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` için `doc.read` izni gerekir
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) bellek bütçesi (nesne {_1} için {size} bayt girdi gerekiyor, {left} kaldı)
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) nesne bütçesi ({MAX_OBJECTS} adetten fazla salt okunur nesne)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it `{shown}` izni sonraki bir eklenti API’si için ayrılmıştır; bu ana bilgisayar bu izni vermez
|
||||
@msg unknown permission `{shown}` bilinmeyen izin `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees “{name}” {asked} izinlerini istiyor: kullanıcı onayladıktan sonra bunları listeleyen bir `grant` ile yükleyin
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -5504,6 +5504,8 @@ axis Y Axis Вісь Y
|
||||
@msg `inputs` lists `{shown}` twice в `inputs` `{shown}` указано двічі
|
||||
@msg `inputs` needs `api` 2 or later для `inputs` потрібен `api` 2 або новіший
|
||||
@msg `inputs` needs the permission `doc.read` для `inputs` потрібен дозвіл `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) бюджет пам’яті (об’єкту {_1} потрібно {size} байтів вхідних даних, залишилося {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) бюджет об’єктів (понад {MAX_OBJECTS} об’єктів лише для читання)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it дозвіл `{shown}` зарезервовано для пізнішого API модулів; цей хост його не надає
|
||||
@msg unknown permission `{shown}` невідомий дозвіл `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees «{name}» запитує дозволи {asked}: установіть його з `grant`, де їх перелічено, коли користувач погодиться
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 182 and column 5.
|
@@ -5505,6 +5505,8 @@ axis Y Axis Trục Y
|
||||
@msg `inputs` lists `{shown}` twice `inputs` liệt kê `{shown}` hai lần
|
||||
@msg `inputs` needs `api` 2 or later `inputs` cần `api` 2 trở lên
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` cần quyền `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) ngân sách bộ nhớ (đối tượng {_1} cần {size} byte đầu vào, còn lại {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) ngân sách đối tượng (hơn {MAX_OBJECTS} đối tượng chỉ đọc)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it quyền `{shown}` được dành cho một API plug-in sau này; máy chủ này không cấp quyền đó
|
||||
@msg unknown permission `{shown}` quyền không xác định `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees “{name}” yêu cầu các quyền {asked}: hãy cài đặt với `grant` liệt kê chúng khi người dùng đồng ý
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 204 and column 5.
|
@@ -5746,6 +5746,8 @@ axis Y Axis Y 轴
|
||||
@msg `inputs` lists `{shown}` twice `inputs` 列出了两次 `{shown}`
|
||||
@msg `inputs` needs `api` 2 or later `inputs` 需要 `api` 2 或更高
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` 需要权限 `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) 内存预算(对象 {_1} 需要 {size} 字节的输入,剩余 {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) 对象预算(超过 {MAX_OBJECTS} 个只读对象)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it 权限 `{shown}` 保留给以后的增效工具 API;此主机不授予该权限
|
||||
@msg unknown permission `{shown}` 未知权限 `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees “{name}”需要权限 {asked}:请在用户同意后使用列出这些权限的 `grant` 安装
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5542,6 +5542,8 @@ axis Y Axis Y 軸
|
||||
@msg `inputs` lists `{shown}` twice `inputs` 列出了兩次 `{shown}`
|
||||
@msg `inputs` needs `api` 2 or later `inputs` 需要 `api` 2 或更高
|
||||
@msg `inputs` needs the permission `doc.read` `inputs` 需要權限 `doc.read`
|
||||
@msg memory budget (object {_1} needs {size} bytes of input, {left} left) 記憶體預算(物件 {_1} 需要 {size} 位元組的輸入,剩餘 {left})
|
||||
@msg object budget (more than {MAX_OBJECTS} read-only objects) 物件預算(超過 {MAX_OBJECTS} 個唯讀物件)
|
||||
@msg permission `{shown}` is reserved for a later plug-in API; this host doesn't grant it 權限 `{shown}` 保留給日後的增效模組 API;此主機不授予該權限
|
||||
@msg unknown permission `{shown}` 未知權限 `{shown}`
|
||||
@msg “{name}” asks for the permissions {asked}: install it with `grant` listing them once the user agrees 「{name}」需要權限 {asked}:請在使用者同意後以列出這些權限的 `grant` 安裝
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
+2
-1
@@ -6480,7 +6480,8 @@ pixels and 16 MiB of type runs over one run (later ones come with `pixelsOmitted
|
||||
toward the input's half of the plug-in's memory cap, ids, bounds, transforms and names included: pixels and runs that
|
||||
don't fit come the same way, and an object whose other fields don't fit makes `plugin.run` return a memory-budget error
|
||||
naming the object and its size, with nothing changed. A path or compound path that doesn't fit makes it return the
|
||||
memory-budget error `the selection is too large to hand over`. Its output returns
|
||||
memory-budget error `the selection is too large to hand over`, and more than 100,000 of these objects make it return
|
||||
an object-budget error. Its output returns
|
||||
each of them as `{"id": …}` or exactly as given, otherwise `plugin.run` returns an error naming the object and the
|
||||
field, and the document and undo history are unchanged. A live-effect plug-in is an effect with
|
||||
id `plugin.<id>`: `effect.apply`, `effect.setParams` and `effect.expandAppearance` work as for built-in effects, and
|
||||
|
||||
+2
-1
@@ -449,7 +449,8 @@ order, with its id, bounds, transform and name. Type whose runs and paragraphs d
|
||||
of these objects don't fit what is left, the run fails before the plug-in starts, naming the object and the bytes it
|
||||
needs: `plug-in exceeded its memory budget (object 17 needs 4200 bytes of input, 1000 left)`. A path or compound path
|
||||
that doesn't fit fails it with `plug-in exceeded its memory budget (the selection is too large to hand over)` before
|
||||
the objects after it are written. An echo of them counts
|
||||
the objects after it are written. An output lists at most 100,000 objects, so a run given more than 100,000 of these
|
||||
objects fails with `plug-in exceeded its object budget (more than 100000 read-only objects)`. An echo of them counts
|
||||
toward the 64 MiB output cap.
|
||||
|
||||
### Parameters
|
||||
|
||||
@@ -1542,7 +1542,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
- **Safe Mode for plug-ins (G17):** `vectorcraft --safe-mode` and `vectorcraft-cli --safe-mode <subcommand>` start without plug-ins. When a launch stopped while a plug-in was loading or drawing its first live effect, the next launch names that plug-in, without saying it caused the stop, and offers Disable and Continue, Start Normally or Start in Safe Mode. Help › Safe Mode lists the disabled plug-ins with Enable on Re-launch, which takes effect at the next launch, and the app bar and the window title show Safe Mode. The help page (https://web.archive.org/web/20210601162814/https://helpx.adobe.com/pdf/illustrator_reference.pdf, pages 65 to 69) describes the same choice between diagnosing and starting normally, a Safe Mode with the problem item off and the rest of the app working, and turning the item back on at the next launch. In Safe Mode no plug-in loads or runs, and a live-effect plug-in draws its object's geometry unchanged while the object keeps the effect, which the Appearance panel marks "(Safe Mode)" with the plug-in's id in its tooltip and `effect.list` marks `skipped`; Expand Appearance refuses such an object. The web build keeps no plug-ins between page loads and has no marker. Each desktop launch with preferences keeps a marker in the `Launch` folder next to them; `vectorcraft-cli` and a desktop launch without preferences keep none, so a stop there leads to no choice at the next launch. Disabled plug-ins are listed in `Plug-ins/disabled.json`. `plugin.safeMode` reports Safe Mode and the disabled plug-ins, and `plugin.setEnabled` changes the list. Regressions: `crates/plugins/src/safe_mode.rs`, `crates/plugins/tests/safe_mode.rs`, `crates/engine/tests/plugin_safe_mode.rs`, `crates/ui-egui/tests/safe_mode.rs`. Scores and hours unchanged.
|
||||
- **Plug-in instruction budget at a bulk memory instruction:** a run that pauses where one slice of its instruction budget ends keeps the instructions the slice still held. A `memory.fill` or `memory.copy` that the slice can't pay for in full runs on the next slice, so a run whose budget covers its work finishes; a run ends with `Limit("instruction budget")` only when the instructions it has left can't pay for the next instruction. Regressions: `crates/plugins/tests/abi.rs`. Scores and hours unchanged.
|
||||
- **Plug-in permissions (G17):** a manifest may list `permissions` (`doc.read`, `doc.write`, `state`, `effect.render`, `export.write`; the first three follow storytold/photocraft#662) and an `api` level; without the list a plug-in gets what its kind implies and installs as before. Install Plug-in… and File › Open show the name, id, version, file SHA-256 and each permission in plain words, with control and bidirectional characters escaped, and install nothing on Cancel; `plugin.install` needs `grant`, and folders install only granted plug-ins. The grant is kept with the module's hash, a module asking for more asks again, and a filter run refuses output its permissions don't allow. Regressions: `crates/plugins/src/permissions.rs`, `crates/plugins/src/manifest.rs`, `crates/engine/src/tests/plugins.rs`, `crates/engine/tests/plugin_fuzz.rs`, `crates/ui-egui/src/tests/plugins.rs`. Scores and hours unchanged.
|
||||
- **Filter plug-ins read type, images and symbol instances (G17, #4333):** a filter at plug-in API level 2 lists `inputs` (`type`, `image`, `symbolInstance`) with `doc.read` in its `permissions`, so installing it asks for approval, and is also given the selected objects of those kinds, read only: type with its runs, character and paragraph attributes (no text past 256 KiB or 4,096 runs or paragraphs, or 16 MiB of runs over the input), images with their size, color mode and, when embedded and at most 1 MiB in base64 (16 MiB over the input), their RGBA pixels (never a linked file's), and symbol instances with their symbol and transform. Every object counts toward the input's half of the memory cap; one whose fields besides its pixels and runs don't fit fails the run naming it and its size, and a path or compound path that doesn't fit fails it too. Its output returns each as `{id}` or exactly as given; any change or omission is refused before the document changes. Filters without `inputs` get the same input as before, except that compound paths that clip a clip group and paths inside a group that clips one are left out for every filter. Regressions: `crates/plugins/src/objects/tests.rs`, `crates/plugins/src/manifest.rs`, `crates/engine/src/tests/plugins.rs`, `crates/engine/tests/plugin_fuzz.rs`. Scores and hours unchanged.
|
||||
- **Filter plug-ins read type, images and symbol instances (G17, #4333):** a filter at plug-in API level 2 lists `inputs` (`type`, `image`, `symbolInstance`) with `doc.read` in its `permissions`, so installing it asks for approval, and is also given the selected objects of those kinds, read only: type with its runs, character and paragraph attributes (no text past 256 KiB or 4,096 runs or paragraphs, or 16 MiB of runs over the input), images with their size, color mode and, when embedded and at most 1 MiB in base64 (16 MiB over the input), their RGBA pixels (never a linked file's), and symbol instances with their symbol and transform. Every object counts toward the input's half of the memory cap; one whose fields besides its pixels and runs don't fit fails the run naming it and its size, a path or compound path that doesn't fit fails it too, and so do more than 100,000 of these objects. Its output returns each as `{id}` or exactly as given; any change or omission is refused before the document changes. Filters without `inputs` get the same input as before, except that compound paths that clip a clip group and paths inside a group that clips one are left out for every filter. Regressions: `crates/plugins/src/objects/tests.rs`, `crates/plugins/src/manifest.rs`, `crates/engine/src/tests/plugins.rs`, `crates/engine/tests/plugin_fuzz.rs`. Scores and hours unchanged.
|
||||
- **Plug-in progress, Cancel and log lines (G17):** at plug-in API level 2 a plug-in with the `progress` permission imports `env.vc_progress`, `env.vc_cancelled` and `env.vc_log`. A heavy filter's and an export's progress windows show its progress as a percentage bar, their Cancel reaches it through `vc_cancelled`, and its log lines go to the app's log with its id, capped per line and per run. Installing checks every import and names the one it refuses. Regressions: `crates/plugins/src/host.rs`, `crates/plugins/tests/abi.rs`, `crates/engine/src/tests/plugins.rs`, `crates/engine/tests/plugin_fuzz.rs`, `crates/ui-egui/src/tests/plugin_runs.rs`. Scores and hours unchanged.
|
||||
- **Plug-in settings and cache (G17, #2191):** at plug-in API level 2 a plug-in with the `settings` permission keeps settings of its own (`env.vc_settings_get`, `_set`, `_delete`) and one with `cache` a cache the user can clear (`env.vc_cache_read`, `_write`, `_clear`), under its id in the `Plug-ins` folder. Keys are plain names, never paths; VectorCraft's own caps refuse a write past 256 settings, 1 MiB of settings or 512 MiB of cache; a damaged settings file is moved aside and the settings start empty. `plugin.clearCache` empties a cache, `plugin.list` and `plugin.info` give `cacheBytes`, replacing a plug-in keeps its storage and `plugin.remove` deletes it. Another module under an id that is installed or has storage installs only with `replace: true`, which the app asks the user for; each storage call counts the whole settings file or cache entry it reads and writes toward the run's 1 GiB. Regressions: `crates/plugins/src/storage.rs`, `crates/plugins/tests/abi.rs`, `crates/engine/src/tests/plugins.rs`, `crates/engine/tests/plugin_fuzz.rs`. Scores and hours unchanged.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user