Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions editor/src/messages/portfolio/portfolio_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1191,7 +1191,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
Ok(message) => responses.add_front(message),
}
}
#[cfg(not(target_family = "wasm"))]
PortfolioMessage::SubmitEyedropperPreviewRender => {
use crate::consts::EYEDROPPER_PREVIEW_AREA_RESOLUTION;

Expand Down Expand Up @@ -1223,10 +1222,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
Ok(message) => responses.add_front(message),
}
}
#[cfg(target_family = "wasm")]
PortfolioMessage::SubmitEyedropperPreviewRender => {
// 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
}
PortfolioMessage::ToggleFocusDocument => {
self.focus_document = !self.focus_document;
responses.add(MenuBarMessage::SendLayout);
Expand Down
44 changes: 24 additions & 20 deletions editor/src/messages/tool/tool_messages/eyedropper_tool.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::tool_prelude::*;
use crate::messages::frontend::utility_types::EyedropperPreviewImage;
use crate::messages::tool::utility_types::DocumentToolData;
use graphene_std::vector::style::RenderMode;

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

fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionMessageContext, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
let ToolActionMessageContext {
global_tool_data, input, viewport, ..
document,
global_tool_data,
input,
viewport,
..
} = tool_action_data;
let render_mode = document.render_mode;

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

if mouse_down == EyedropperToolMessage::SamplePrimaryColorBegin {
EyedropperToolFsmState::SamplingPrimary
Expand All @@ -127,7 +133,7 @@ impl Fsm for EyedropperToolFsmState {
(EyedropperToolFsmState::SamplingPrimary | EyedropperToolFsmState::SamplingSecondary, EyedropperToolMessage::PointerMove) => {
let mouse_position = viewport.logical(input.mouse.position);
if viewport.is_in_bounds(mouse_position + viewport.offset()) {
update_cursor_preview(responses, tool_data, input, global_tool_data, None);
update_cursor_preview(responses, tool_data, input, global_tool_data, None, render_mode);
} else {
disable_cursor_preview(responses, tool_data);
}
Expand All @@ -141,7 +147,7 @@ impl Fsm for EyedropperToolFsmState {
EyedropperToolFsmState::SamplingSecondary => PrimarySecondary::Secondary,
_ => unreachable!(),
};
update_cursor_preview(responses, tool_data, input, global_tool_data, Some(set_color_choice));
update_cursor_preview(responses, tool_data, input, global_tool_data, Some(set_color_choice), render_mode);
disable_cursor_preview(responses, tool_data);

EyedropperToolFsmState::Ready
Expand Down Expand Up @@ -192,31 +198,29 @@ fn disable_cursor_preview(responses: &mut VecDeque<Message>, tool_data: &mut Eye
});
}

#[cfg(not(target_family = "wasm"))]
fn update_cursor_preview(
responses: &mut VecDeque<Message>,
tool_data: &mut EyedropperToolData,
_input: &InputPreprocessorMessageHandler,
_global_tool_data: &DocumentToolData,
set_color_choice: Option<PrimarySecondary>,
) {
tool_data.preview = true;
tool_data.color_choice = set_color_choice;
responses.add(PortfolioMessage::SubmitEyedropperPreviewRender);
}

#[cfg(target_family = "wasm")]
fn update_cursor_preview(
responses: &mut VecDeque<Message>,
tool_data: &mut EyedropperToolData,
input: &InputPreprocessorMessageHandler,
global_tool_data: &DocumentToolData,
set_color_choice: Option<PrimarySecondary>,
render_mode: RenderMode,
) {
tool_data.preview = true;
tool_data.color_choice = set_color_choice.clone();
tool_data.color_choice = set_color_choice;

update_cursor_preview_common(responses, None, input, global_tool_data, set_color_choice);
// On web, SVG Preview mode uses the frontend's SVG rasterization to sample pixels directly
#[cfg(target_family = "wasm")]
if render_mode == RenderMode::SvgPreview {
update_cursor_preview_common(responses, None, input, global_tool_data, set_color_choice);
return;
}

let _ = (&input, &global_tool_data, &render_mode);

// For Vello-rendered modes (Normal, Outline, and Pixel Preview), submit a backend render request
// which will return a zoomed-in pixel preview image via the EyedropperToolMessage::PreviewImage path
responses.add(PortfolioMessage::SubmitEyedropperPreviewRender);
}

fn update_cursor_preview_common(
Expand Down
15 changes: 13 additions & 2 deletions editor/src/node_graph_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ impl NodeGraphExecutor {
}

#[allow(clippy::too_many_arguments)]
#[cfg(not(target_family = "wasm"))]
pub(crate) fn submit_eyedropper_preview(
&mut self,
document: &DocumentMessageHandler,
Expand All @@ -201,13 +200,25 @@ impl NodeGraphExecutor {
resolution: viewport_resolution,
..Default::default()
};

// TODO: On desktop, SVG Preview mode cannot work with the Eyedropper tool until <https://github.com/GraphiteEditor/Graphite/issues/3796> is implemented.
// TODO: So for now, we fall back to the Eyedropper using Normal mode (Vello) rendering, which looks similar enough to SVG Preview.
#[cfg(not(target_family = "wasm"))]
let render_mode = match document.render_mode {
graphene_std::vector::style::RenderMode::SvgPreview => graphene_std::vector::style::RenderMode::Normal,
other => other,
};
// On web, SVG Preview is handled by the frontend's SVG rasterization path instead, producing the correct result, so we keep it enabled.
#[cfg(target_family = "wasm")]
let render_mode = document.render_mode;
Comment on lines +204 to +213
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This logic for determining the render_mode can be made more concise by using an if expression with cfg!. This avoids separate #[cfg] attributes and repeated let bindings.

Suggested change
// TODO: On desktop, SVG Preview mode cannot work with the Eyedropper tool until <https://github.com/GraphiteEditor/Graphite/issues/3796> is implemented.
// TODO: So for now, we fall back to the Eyedropper using Normal mode (Vello) rendering, which looks similar enough to SVG Preview.
#[cfg(not(target_family = "wasm"))]
let render_mode = match document.render_mode {
graphene_std::vector::style::RenderMode::SvgPreview => graphene_std::vector::style::RenderMode::Normal,
other => other,
};
// On web, SVG Preview is handled by the frontend's SVG rasterization path instead, producing the correct result, so we keep it enabled.
#[cfg(target_family = "wasm")]
let render_mode = document.render_mode;
// TODO: On desktop, SVG Preview mode cannot work with the Eyedropper tool until <https://github.com/GraphiteEditor/Graphite/issues/3796> is implemented.
// TODO: So for now, we fall back to the Eyedropper using Normal mode (Vello) rendering, which looks similar enough to SVG Preview.
// On web, SVG Preview is handled by the frontend's SVG rasterization path instead, producing the correct result, so we keep it enabled.
let render_mode = if cfg!(not(target_family = "wasm")) && document.render_mode == graphene_std::vector::style::RenderMode::SvgPreview {
graphene_std::vector::style::RenderMode::Normal
} else {
document.render_mode
};


let render_config = RenderConfig {
viewport,
scale: viewport_scale,
time,
pointer,
export_format: graphene_std::application_io::ExportFormat::Raster,
render_mode: document.render_mode,
render_mode,
hide_artboards: false,
for_export: false,
for_eyedropper: true,
Expand Down
4 changes: 4 additions & 0 deletions editor/src/node_graph_executor/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,10 @@ impl NodeRuntime {
self.sender.send_eyedropper_preview(raster_cpu);
continue;
}
// Eyedropper render that didn't produce a texture (e.g., SVG fallback when GPU is unavailable); discard it
_ if render_config.for_eyedropper => {
continue;
}
#[cfg(all(target_family = "wasm", feature = "gpu"))]
Ok(TaggedValue::RenderOutput(RenderOutput {
data: RenderOutputType::Texture(image_texture),
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/panels/Document.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@
const outsideArtboards = `<rect x="0" y="0" width="100%" height="100%" fill="${outsideArtboardsColor}" />`;

const svg = `
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">${outsideArtboards}${artworkSvg}</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:graphite="https://graphite.art" width="${width}" height="${height}">${outsideArtboards}${artworkSvg}</svg>
`.trim();

if (!rasterizedCanvas) {
Expand Down
Loading