protected unsafe override void OnMouseMove(Document document, ToolMouseEventArgs e) { ColorBgra old_color; ColorBgra new_color; // This should have been created in OnMouseDown if (stencil is null) { return; } if (mouse_button == MouseButton.Left) { old_color = Palette.PrimaryColor.ToColorBgra(); new_color = Palette.SecondaryColor.ToColorBgra(); } else if (mouse_button == MouseButton.Right) { old_color = Palette.SecondaryColor.ToColorBgra(); new_color = Palette.PrimaryColor.ToColorBgra(); } else { last_point = point_empty; return; } var x = e.Point.X; var y = e.Point.Y; if (last_point.Equals(point_empty)) { last_point = new Point(x, y); } if (document.Workspace.PointInCanvas(e.PointDouble)) { surface_modified = true; } var surf = document.Layers.CurrentUserLayer.Surface; var tmp_layer = document.Layers.ToolLayer.Surface; var roi = CairoExtensions.GetRectangleFromPoints(last_point, new Point(x, y), BrushWidth + 2); roi = workspace.ClampToImageSize(roi); var myTolerance = (int)(Tolerance * 256); tmp_layer.Flush(); var tmp_data_ptr = (ColorBgra *)tmp_layer.DataPtr; var tmp_width = tmp_layer.Width; var surf_data_ptr = (ColorBgra *)surf.DataPtr; var surf_width = surf.Width; // The stencil lets us know if we've already checked this // pixel, providing a nice perf boost // Maybe this should be changed to a BitVector2DSurfaceAdapter? for (var i = roi.X; i <= roi.GetRight(); i++) { for (var j = roi.Y; j <= roi.GetBottom(); j++) { if (stencil[i, j]) { continue; } if (ColorBgra.ColorsWithinTolerance(new_color, surf.GetColorBgraUnchecked(surf_data_ptr, surf_width, i, j), myTolerance)) { *tmp_layer.GetPointAddressUnchecked(tmp_data_ptr, tmp_width, i, j) = AdjustColorDifference(new_color, old_color, surf.GetColorBgraUnchecked(surf_data_ptr, surf_width, i, j)); } stencil[i, j] = true; } } tmp_layer.MarkDirty(); using (var g = document.CreateClippedContext()) { g.Antialias = UseAntialiasing ? Antialias.Subpixel : Antialias.None; g.MoveTo(last_point.X, last_point.Y); g.LineTo(x, y); g.LineWidth = BrushWidth; g.LineJoin = LineJoin.Round; g.LineCap = LineCap.Round; g.SetSource(tmp_layer); g.Stroke(); } document.Workspace.Invalidate(roi); last_point = new Point(x, y); }