Skip to content

Commit 81d0b8b

Browse files
authored
Fix the Eyedropper tool on web with Vello and on desktop with SVG (#3886)
1 parent 116a410 commit 81d0b8b

File tree

5 files changed

+42
-28
lines changed

5 files changed

+42
-28
lines changed

editor/src/messages/portfolio/portfolio_message_handler.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,7 +1191,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
11911191
Ok(message) => responses.add_front(message),
11921192
}
11931193
}
1194-
#[cfg(not(target_family = "wasm"))]
11951194
PortfolioMessage::SubmitEyedropperPreviewRender => {
11961195
use crate::consts::EYEDROPPER_PREVIEW_AREA_RESOLUTION;
11971196

@@ -1223,10 +1222,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
12231222
Ok(message) => responses.add_front(message),
12241223
}
12251224
}
1226-
#[cfg(target_family = "wasm")]
1227-
PortfolioMessage::SubmitEyedropperPreviewRender => {
1228-
// TODO: Currently for Wasm, this is implemented through SVG rendering but the Eyedropper tool doesn't work at all when Vello is enabled as the renderer
1229-
}
12301225
PortfolioMessage::ToggleFocusDocument => {
12311226
self.focus_document = !self.focus_document;
12321227
responses.add(MenuBarMessage::SendLayout);

editor/src/messages/tool/tool_messages/eyedropper_tool.rs

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::tool_prelude::*;
22
use crate::messages::frontend::utility_types::EyedropperPreviewImage;
33
use crate::messages::tool::utility_types::DocumentToolData;
4+
use graphene_std::vector::style::RenderMode;
45

56
#[derive(Default, ExtractField)]
67
pub struct EyedropperTool {
@@ -108,14 +109,19 @@ impl Fsm for EyedropperToolFsmState {
108109

109110
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionMessageContext, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
110111
let ToolActionMessageContext {
111-
global_tool_data, input, viewport, ..
112+
document,
113+
global_tool_data,
114+
input,
115+
viewport,
116+
..
112117
} = tool_action_data;
118+
let render_mode = document.render_mode;
113119

114120
let ToolMessage::Eyedropper(event) = event else { return self };
115121
match (self, event) {
116122
// Ready -> Sampling
117123
(EyedropperToolFsmState::Ready, mouse_down) if matches!(mouse_down, EyedropperToolMessage::SamplePrimaryColorBegin | EyedropperToolMessage::SampleSecondaryColorBegin) => {
118-
update_cursor_preview(responses, tool_data, input, global_tool_data, None);
124+
update_cursor_preview(responses, tool_data, input, global_tool_data, None, render_mode);
119125

120126
if mouse_down == EyedropperToolMessage::SamplePrimaryColorBegin {
121127
EyedropperToolFsmState::SamplingPrimary
@@ -127,7 +133,7 @@ impl Fsm for EyedropperToolFsmState {
127133
(EyedropperToolFsmState::SamplingPrimary | EyedropperToolFsmState::SamplingSecondary, EyedropperToolMessage::PointerMove) => {
128134
let mouse_position = viewport.logical(input.mouse.position);
129135
if viewport.is_in_bounds(mouse_position + viewport.offset()) {
130-
update_cursor_preview(responses, tool_data, input, global_tool_data, None);
136+
update_cursor_preview(responses, tool_data, input, global_tool_data, None, render_mode);
131137
} else {
132138
disable_cursor_preview(responses, tool_data);
133139
}
@@ -141,7 +147,7 @@ impl Fsm for EyedropperToolFsmState {
141147
EyedropperToolFsmState::SamplingSecondary => PrimarySecondary::Secondary,
142148
_ => unreachable!(),
143149
};
144-
update_cursor_preview(responses, tool_data, input, global_tool_data, Some(set_color_choice));
150+
update_cursor_preview(responses, tool_data, input, global_tool_data, Some(set_color_choice), render_mode);
145151
disable_cursor_preview(responses, tool_data);
146152

147153
EyedropperToolFsmState::Ready
@@ -192,31 +198,29 @@ fn disable_cursor_preview(responses: &mut VecDeque<Message>, tool_data: &mut Eye
192198
});
193199
}
194200

195-
#[cfg(not(target_family = "wasm"))]
196-
fn update_cursor_preview(
197-
responses: &mut VecDeque<Message>,
198-
tool_data: &mut EyedropperToolData,
199-
_input: &InputPreprocessorMessageHandler,
200-
_global_tool_data: &DocumentToolData,
201-
set_color_choice: Option<PrimarySecondary>,
202-
) {
203-
tool_data.preview = true;
204-
tool_data.color_choice = set_color_choice;
205-
responses.add(PortfolioMessage::SubmitEyedropperPreviewRender);
206-
}
207-
208-
#[cfg(target_family = "wasm")]
209201
fn update_cursor_preview(
210202
responses: &mut VecDeque<Message>,
211203
tool_data: &mut EyedropperToolData,
212204
input: &InputPreprocessorMessageHandler,
213205
global_tool_data: &DocumentToolData,
214206
set_color_choice: Option<PrimarySecondary>,
207+
render_mode: RenderMode,
215208
) {
216209
tool_data.preview = true;
217-
tool_data.color_choice = set_color_choice.clone();
210+
tool_data.color_choice = set_color_choice;
218211

219-
update_cursor_preview_common(responses, None, input, global_tool_data, set_color_choice);
212+
// On web, SVG Preview mode uses the frontend's SVG rasterization to sample pixels directly
213+
#[cfg(target_family = "wasm")]
214+
if render_mode == RenderMode::SvgPreview {
215+
update_cursor_preview_common(responses, None, input, global_tool_data, set_color_choice);
216+
return;
217+
}
218+
219+
let _ = (&input, &global_tool_data, &render_mode);
220+
221+
// For Vello-rendered modes (Normal, Outline, and Pixel Preview), submit a backend render request
222+
// which will return a zoomed-in pixel preview image via the EyedropperToolMessage::PreviewImage path
223+
responses.add(PortfolioMessage::SubmitEyedropperPreviewRender);
220224
}
221225

222226
fn update_cursor_preview_common(

editor/src/node_graph_executor.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ impl NodeGraphExecutor {
185185
}
186186

187187
#[allow(clippy::too_many_arguments)]
188-
#[cfg(not(target_family = "wasm"))]
189188
pub(crate) fn submit_eyedropper_preview(
190189
&mut self,
191190
document: &DocumentMessageHandler,
@@ -201,13 +200,25 @@ impl NodeGraphExecutor {
201200
resolution: viewport_resolution,
202201
..Default::default()
203202
};
203+
204+
// TODO: On desktop, SVG Preview mode cannot work with the Eyedropper tool until <https://github.com/GraphiteEditor/Graphite/issues/3796> is implemented.
205+
// TODO: So for now, we fall back to the Eyedropper using Normal mode (Vello) rendering, which looks similar enough to SVG Preview.
206+
#[cfg(not(target_family = "wasm"))]
207+
let render_mode = match document.render_mode {
208+
graphene_std::vector::style::RenderMode::SvgPreview => graphene_std::vector::style::RenderMode::Normal,
209+
other => other,
210+
};
211+
// On web, SVG Preview is handled by the frontend's SVG rasterization path instead, producing the correct result, so we keep it enabled.
212+
#[cfg(target_family = "wasm")]
213+
let render_mode = document.render_mode;
214+
204215
let render_config = RenderConfig {
205216
viewport,
206217
scale: viewport_scale,
207218
time,
208219
pointer,
209220
export_format: graphene_std::application_io::ExportFormat::Raster,
210-
render_mode: document.render_mode,
221+
render_mode,
211222
hide_artboards: false,
212223
for_export: false,
213224
for_eyedropper: true,

editor/src/node_graph_executor/runtime.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,10 @@ impl NodeRuntime {
309309
self.sender.send_eyedropper_preview(raster_cpu);
310310
continue;
311311
}
312+
// Eyedropper render that didn't produce a texture (e.g., SVG fallback when GPU is unavailable); discard it
313+
_ if render_config.for_eyedropper => {
314+
continue;
315+
}
312316
#[cfg(all(target_family = "wasm", feature = "gpu"))]
313317
Ok(TaggedValue::RenderOutput(RenderOutput {
314318
data: RenderOutputType::Texture(image_texture),

frontend/src/components/panels/Document.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@
237237
const outsideArtboards = `<rect x="0" y="0" width="100%" height="100%" fill="${outsideArtboardsColor}" />`;
238238
239239
const svg = `
240-
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">${outsideArtboards}${artworkSvg}</svg>
240+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:graphite="https://graphite.art" width="${width}" height="${height}">${outsideArtboards}${artworkSvg}</svg>
241241
`.trim();
242242
243243
if (!rasterizedCanvas) {

0 commit comments

Comments
 (0)