{"record":{"id":"36391a8f5373667f","repo":"GraphiteEditor/Graphite","slug":"transform-should-be-able-to-be-reset-to-be-able-to","errorCode":null,"errorMessage":"transform should be able to be reset to be able to account for DPI","messagePattern":"transform should be able to be reset to be able to account for DPI","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"editor/src/messages/portfolio/document/overlays/utility_types_web.rs","lineNumber":620,"sourceCode":"\t\t\tself.draw_triangle(mid + edge * (3. + SKEW_TRIANGLE_OFFSET), edge, SKEW_TRIANGLE_SIZE, None, None);\n\t\t}\n\t}\n\n\t/// Transforms the canvas context to adjust for DPI scaling\n\t///\n\t/// Overwrites all existing tranforms. This operation can be reversed with [`Self::reset_transform`].\n\tfn start_dpi_aware_transform(&self) {\n\t\tlet [a, b, c, d, e, f] = DAffine2::from_scale(DVec2::splat(self.viewport.scale())).to_cols_array();\n\t\tself.render_context\n\t\t\t.set_transform(a, b, c, d, e, f)\n\t\t\t.expect(\"transform should be able to be set to be able to account for DPI\");\n\t}\n\n\t/// Un-transforms the Canvas context to adjust for DPI scaling\n\t///\n\t/// Warning: this function doesn't only reset the DPI scaling adjustment, it resets the entire transform.\n\tfn end_dpi_aware_transform(&self) {\n\t\tself.render_context.reset_transform().expect(\"transform should be able to be reset to be able to account for DPI\");\n\t}\n\n\tpub fn square(&mut self, position: DVec2, size: Option<f64>, color_fill: Option<&str>, color_stroke: Option<&str>) {\n\t\tlet size = size.unwrap_or(MANIPULATOR_GROUP_MARKER_SIZE);\n\t\tlet color_fill = color_fill.unwrap_or(COLOR_OVERLAY_WHITE);\n\t\tlet color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE);\n\n\t\tlet position = self.snap_to_physical_pixel_center(position);\n\t\tlet corner = position - DVec2::splat(size) / 2.;\n\n\t\tself.start_dpi_aware_transform();\n\n\t\tself.render_context.begin_path();\n\t\tself.render_context.rect(corner.x, corner.y, size, size);\n\t\tself.render_context.set_fill_style_str(color_fill);\n\t\tself.render_context.set_stroke_style_str(color_stroke);\n\t\tself.render_context.set_line_width(1.);\n\t\tself.render_context.fill();","sourceCodeStart":602,"sourceCodeEnd":638,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/editor/src/messages/portfolio/document/overlays/utility_types_web.rs#L602-L638","documentation":"end_dpi_aware_transform calls ctx.reset_transform(). Per the HTML spec resetTransform() is equivalent to setTransform(1, 0, 0, 1, 0, 0), and the identity matrix is always invertible, so on a live 2D context this call effectively cannot throw; web_sys still types it as Result and the .expect is purely defensive. If it ever fires it indicates an invalid or lost context rather than a geometry bug.","triggerScenarios":"Practically unreachable on a valid context. Conceivable only with an already-invalid context (lost after a GPU reset or detached canvas) or an engine-level failure inside resetTransform.","commonSituations":"Appearing in crash reports almost always as a secondary effect of a corrupted render context or a stale cached context after the canvas element was replaced — not as an independent defect.","solutions":["Treat it as defensive: if observed, check canvas/context health and look for an earlier root-cause panic (e.g., a set_transform NaN failure in the same frame).","Degrade to a logged .ok() so a context anomaly cannot abort the overlay pass.","Ensure the context cache is invalidated when the underlying canvas element is recreated."],"exampleFix":"// before\nself.render_context.reset_transform().expect(\"transform should be able to be reset to be able to account for DPI\");\n\n// after — resetTransform() applies the identity matrix and cannot fail on a live context\nif let Err(err) = self.render_context.reset_transform() {\n\tlog::warn!(\"Failed to reset canvas transform: {:?}\", err);\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(err) = self.render_context.reset_transform() {\n\tlog::warn!(\"failed to reset canvas transform (context may be invalid): {:?}\", err);\n}","preventionTips":["Treat a resetTransform failure as a signal the context is invalid — re-query the canvas rather than reusing the cached context","Invalidate context caches when the canvas element is recreated","Keep reset/set transform pairs balanced so stale transforms never accumulate"],"tags":["wasm","canvas-2d","overlay","dpi","defensive-assert"],"backgroundTag":"canvas-2d-transform-non-invertible","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}