Skip to content

Conversation

@RobbieTheWagner
Copy link
Member

@RobbieTheWagner RobbieTheWagner commented Jan 15, 2026

Summary by CodeRabbit

  • New Features

    • Enabled Windows HiDPI support for more accurate rendering on high-density displays.
  • Refactor

    • Enhanced DPI-awareness across the magnifier: coordinate handling simplified to logical coordinates, cursor tracking and pixel sampling improved for varied resolutions and scaling.
  • Tests

    • Updated tests to validate DPI-aware coordinate mapping and sampling behavior on high-resolution displays.

✏️ Tip: You can customize this high-level summary in your review settings.

@RobbieTheWagner RobbieTheWagner added the bug Something isn't working label Jan 15, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

Refactors DPI handling by initializing DPI awareness inside WindowsSampler, exposing a dpi_scale, and moving physical↔logical coordinate conversions into the sampler so the main loop operates on logical coordinates only.

Changes

Cohort / File(s) Summary
Windows Sampler Core
electron-app/magnifier/rust-sampler/src/sampler/windows.rs
Initialize DPI awareness via SetProcessDpiAwarenessContext, add public dpi_scale field, compute DPI from GetDeviceCaps, and refactor sampling to convert between logical and physical coordinates (GetPixel/GetCursorPos and BitBlt/GetDIBits paths) with fallback handling.
Main Sampling Loop
electron-app/magnifier/rust-sampler/src/main.rs
Remove dpi_scale parameter from run_sampling_loop, simplify cursor handling to use logical cursor positions directly, and pass logical coordinates to sampler functions.
Dependencies
electron-app/magnifier/rust-sampler/Cargo.toml
Add Win32_UI_HiDpi feature to Windows target Win32 bindings.
Windows Sampler Tests
electron-app/magnifier/rust-sampler/tests/windows_sampler_tests.rs
Update test expectations and mocks for DPI-aware behavior (logical inputs, physical sampling conversion), adjusting coordinates for 200% DPI scenarios.

Sequence Diagram(s)

sequenceDiagram
  participant Main as Main Loop
  participant Sampler as WindowsSampler
  participant WinAPI as Win32 APIs (GDI, DPI)

  Main->>Sampler: initialize WindowsSampler (creates dpi_scale, sets DPI context)
  Main->>Sampler: get_cursor_position() -> logical cursor
  Main->>Sampler: request sample_grid / sample_pixel with logical coords
  Sampler->>WinAPI: convert logical -> physical (multiply by dpi_scale)
  Sampler->>WinAPI: capture pixels (GetPixel / BitBlt + GetDIBits)
  WinAPI-->>Sampler: raw pixel data (physical coords)
  Sampler->>Sampler: convert physical -> logical (divide by dpi_scale) and return PixelData
  Sampler-->>Main: PixelData (contains logical cursor and sampled pixels)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

  • #2471: Modifies DPI-related code paths, including WindowsSampler.dpi_scale and main sampling loop updates.
  • #2462: Alters Windows sampler and Windows build features (adds HiDPI feature) with overlapping sampler changes.
  • #2470: Changes Windows DPI handling and sampling coordinate conversions in the same modules.

Suggested labels

enhancement

Poem

I’m a rabbit with magnifier eyes so bright,
I hop from logical to physical in one light,
I set DPI context with a cheerful nibble,
Scale up, sample on, never a quibble! 🐇🔍

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Make windows sampler DPI aware' directly and clearly describes the main objective of the pull request—implementing DPI awareness in the Windows sampler component.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8eb4ea7 and 47780ef.

📒 Files selected for processing (1)
  • electron-app/magnifier/rust-sampler/tests/windows_sampler_tests.rs
🧰 Additional context used
🧬 Code graph analysis (1)
electron-app/magnifier/rust-sampler/tests/windows_sampler_tests.rs (4)
electron-app/magnifier/rust-sampler/src/types.rs (1)
  • sample_grid (87-105)
electron-app/magnifier/rust-sampler/src/sampler/linux.rs (1)
  • sample_grid (256-277)
electron-app/magnifier/rust-sampler/src/sampler/wayland_portal.rs (1)
  • sample_grid (396-435)
electron-app/magnifier/rust-sampler/src/sampler/macos.rs (1)
  • sample_grid (125-182)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test Rust Sampler (windows-latest)
  • GitHub Check: Tests
🔇 Additional comments (4)
electron-app/magnifier/rust-sampler/tests/windows_sampler_tests.rs (4)

9-31: LGTM!

The MockWindowsSampler struct and constructors correctly model DPI-aware behavior with clear documentation distinguishing physical dimensions and DPI scale factor. The default 1.0 scale for 100% DPI is appropriate.


33-98: LGTM!

The PixelSampler trait implementation correctly models the DPI-aware coordinate flow:

  • sample_pixel accepts logical coordinates and converts to physical internally
  • get_cursor_position returns logical coordinates derived from simulated physical position
  • sample_grid operates in logical space with internal physical conversion

This aligns with the macOS pattern mentioned in the comments and the production behavior described in the summary.


127-135: LGTM!

The cursor position test correctly validates that at 100% DPI (scale 1.0), the physical cursor position (200, 200) equals the logical position (200, 200).


721-767: LGTM!

The remaining tests for multi-monitor simulation, high DPI scaling, rapid sampling, and error messages are straightforward and correctly validate the expected behavior.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
electron-app/magnifier/rust-sampler/tests/windows_sampler_tests.rs (1)

34-53: Mock sample_pixel doesn't match production DPI behavior.

The mock's sample_pixel treats x, y as physical coordinates without conversion, but the production WindowsSampler::sample_pixel (windows.rs lines 61-62) converts logical to physical:

// Production code
let physical_x = (x as f64 * self.dpi_scale) as i32;
let physical_y = (y as f64 * self.dpi_scale) as i32;

This causes the DPI scaling tests (e.g., test_windows_sampler_dpi_150_percent at line 491) to fail because they pass logical coordinates expecting physical-based color results, but the mock doesn't perform the conversion.

Proposed fix to align mock with production
 fn sample_pixel(&mut self, x: i32, y: i32) -> Result<Color, String> {
-        // With DPI awareness enabled in the actual implementation:
-        // - x, y are already in physical coordinates (no conversion needed)
-        // - GetPixel expects physical coordinates
-        let physical_x = x;
-        let physical_y = y;
+        // With DPI awareness enabled in the actual implementation:
+        // - x, y are logical coordinates
+        // - Convert to physical coordinates internally (like production)
+        let physical_x = (x as f64 * self.dpi_scale) as i32;
+        let physical_y = (y as f64 * self.dpi_scale) as i32;
🧹 Nitpick comments (1)
electron-app/magnifier/rust-sampler/tests/windows_sampler_tests.rs (1)

326-351: Test test_windows_sampler_grid_pixel_alignment only works at 100% DPI due to mock inconsistency.

This test compares sample_grid results to individual sample_pixel calls, but the mock's inconsistent DPI handling (as noted above) means this test would fail at higher DPI scales. The test only passes because it uses MockWindowsSampler::new(1920, 1080) which defaults to 1.0 DPI scale.

Consider adding a similar test with new_with_dpi to verify alignment at higher DPI scales once the mock is fixed.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 89937e3 and 8eb4ea7.

📒 Files selected for processing (4)
  • electron-app/magnifier/rust-sampler/Cargo.toml
  • electron-app/magnifier/rust-sampler/src/main.rs
  • electron-app/magnifier/rust-sampler/src/sampler/windows.rs
  • electron-app/magnifier/rust-sampler/tests/windows_sampler_tests.rs
🧰 Additional context used
🧬 Code graph analysis (1)
electron-app/magnifier/rust-sampler/tests/windows_sampler_tests.rs (2)
electron-app/magnifier/rust-sampler/src/sampler/windows.rs (1)
  • sample_grid (107-228)
electron-app/magnifier/rust-sampler/src/types.rs (1)
  • sample_grid (87-105)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Tests
  • GitHub Check: Test Rust Sampler (windows-latest)
🔇 Additional comments (9)
electron-app/magnifier/rust-sampler/Cargo.toml (1)

31-37: LGTM!

The Win32_UI_HiDpi feature addition correctly enables access to the DPI awareness APIs (SetProcessDpiAwarenessContext, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) used in the Windows sampler implementation.

electron-app/magnifier/rust-sampler/tests/windows_sampler_tests.rs (1)

677-719: Good test coverage for DPI-aware grid sampling.

This test thoroughly validates the coordinate conversion at 200% DPI by checking center, top-left, and bottom-right pixels against expected physical coordinate-based colors. The calculations in comments (e.g., "virtual (998, 498) → physical (1996, 996)") help document the expected behavior.

electron-app/magnifier/rust-sampler/src/sampler/windows.rs (5)

17-44: DPI awareness initialization looks correct.

Setting DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 before GDI calls is the correct approach. Silently ignoring the error is reasonable since the app will fall back to system DPI awareness if this fails.

One consideration: SetProcessDpiAwarenessContext is a per-process setting and can only be called once successfully. If another part of the Electron app (or a dependency) has already set DPI awareness, this call will fail. The silent ignore handles this gracefully.


55-82: LGTM!

The logical-to-physical coordinate conversion is correctly implemented. The error message preserving original logical coordinates aids debugging.


84-103: LGTM!

The physical-to-logical conversion for cursor position correctly mirrors the inverse of the sampling conversion, ensuring coordinate consistency with Electron's coordinate system.


107-121: Verify intended grid sampling behavior at high DPI.

The current implementation samples grid_size physical pixels centered around the physical cursor position. At 200% DPI, a 9×9 grid samples a 9×9 physical pixel region, which corresponds to roughly 4.5×4.5 logical pixels on screen.

This is likely the correct behavior for a color picker (sampling actual physical pixels), but differs from a "logical pixel" model where you'd capture grid_size * dpi_scale physical pixels to cover grid_size logical pixels.

Please confirm this physical-pixel sampling behavior is intended for the magnifier's use case.


231-268: Fallback implementation is consistent with optimized path.

The sample_grid_fallback correctly mirrors the DPI handling of the optimized sample_grid method, ensuring consistent behavior when BitBlt fails.

electron-app/magnifier/rust-sampler/src/main.rs (2)

98-103: Clean API simplification.

Removing dpi_scale from the sampling loop signature and encapsulating DPI handling within the platform-specific samplers is a good design improvement. This follows the pattern established by macOS and keeps the main loop platform-agnostic.


137-180: LGTM!

The sampling loop now works entirely with logical coordinates, delegating DPI conversion to the platform samplers. The cursor_pos is correctly propagated to sampling functions and stored in PixelData, maintaining consistency with Electron's coordinate system.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
electron-app/magnifier/rust-sampler/tests/windows_sampler_tests.rs (3)

633-641: Misleading comment on coordinate conversion direction.

The comment on line 638 states "Physical coordinate 6000 maps to logical 3000" but the test passes 6000 as a logical coordinate to sample_pixel, which then converts it to physical (6000 × 2.0 = 12000). The test correctly fails because 12000 exceeds the physical bounds, but the comment describes the conversion backwards.

📝 Suggested comment fix
 #[test]
 fn test_windows_sampler_dpi_out_of_bounds() {
     // Test that out-of-bounds checking works with DPI scaling
     let mut sampler = MockWindowsSampler::new_with_dpi(2560, 1440, 2.0);
     
-    // Physical coordinate 6000 maps to logical 3000, which is > 2560
+    // Logical coordinate 6000 maps to physical 12000 (6000 * 2.0), which exceeds physical bounds 2560
     let result = sampler.sample_pixel(6000, 3000);
     assert!(result.is_err(), "Should fail for out-of-bounds coordinates");
 }

698-706: Incorrect modulo arithmetic in comments.

The comments on lines 700-702 have incorrect calculations:

  • 2000 % 256 = 208, not 224
  • 1000 % 256 = 232 ✓ (correct)
  • 3000 % 256 = 184, not 200

The assertions will fail at runtime because the expected values don't match the actual modulo results.

🐛 Proposed fix
     // Center samples at virtual position (1000, 500) -> physical (2000, 1000)
     // Colors are based on physical coordinates
-    let expected_b = (2000 % 256) as u8; // 2000 % 256 = 224
+    let expected_b = (2000 % 256) as u8; // 2000 % 256 = 208
     let expected_g = (1000 % 256) as u8; // 1000 % 256 = 232
-    let expected_r = ((2000 + 1000) % 256) as u8; // 3000 % 256 = 200
+    let expected_r = ((2000 + 1000) % 256) as u8; // 3000 % 256 = 184

710-718: Incorrect modulo arithmetic in edge pixel comments.

Similar issue with the top-left and bottom-right pixel calculations:

  • Line 712: 1996 % 256 = 204, not 220
  • Line 717: 2004 % 256 = 212, not 228

These assertions will fail at runtime.

🐛 Proposed fix
     // Top-left: virtual (998, 498) -> physical (1996, 996)
     let top_left = &grid[0][0];
-    assert_eq!(top_left.b, (1996 % 256) as u8); // 1996 % 256 = 220
+    assert_eq!(top_left.b, (1996 % 256) as u8); // 1996 % 256 = 204
     assert_eq!(top_left.g, (996 % 256) as u8);  // 996 % 256 = 228
 
     // Bottom-right: virtual (1002, 502) -> physical (2004, 1004)
     let bottom_right = &grid[4][4];
-    assert_eq!(bottom_right.b, (2004 % 256) as u8); // 2004 % 256 = 228
+    assert_eq!(bottom_right.b, (2004 % 256) as u8); // 2004 % 256 = 212
     assert_eq!(bottom_right.g, (1004 % 256) as u8); // 1004 % 256 = 236
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8eb4ea7 and 47780ef.

📒 Files selected for processing (1)
  • electron-app/magnifier/rust-sampler/tests/windows_sampler_tests.rs
🧰 Additional context used
🧬 Code graph analysis (1)
electron-app/magnifier/rust-sampler/tests/windows_sampler_tests.rs (4)
electron-app/magnifier/rust-sampler/src/types.rs (1)
  • sample_grid (87-105)
electron-app/magnifier/rust-sampler/src/sampler/linux.rs (1)
  • sample_grid (256-277)
electron-app/magnifier/rust-sampler/src/sampler/wayland_portal.rs (1)
  • sample_grid (396-435)
electron-app/magnifier/rust-sampler/src/sampler/macos.rs (1)
  • sample_grid (125-182)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test Rust Sampler (windows-latest)
  • GitHub Check: Tests
🔇 Additional comments (4)
electron-app/magnifier/rust-sampler/tests/windows_sampler_tests.rs (4)

9-31: LGTM!

The MockWindowsSampler struct and constructors correctly model DPI-aware behavior with clear documentation distinguishing physical dimensions and DPI scale factor. The default 1.0 scale for 100% DPI is appropriate.


33-98: LGTM!

The PixelSampler trait implementation correctly models the DPI-aware coordinate flow:

  • sample_pixel accepts logical coordinates and converts to physical internally
  • get_cursor_position returns logical coordinates derived from simulated physical position
  • sample_grid operates in logical space with internal physical conversion

This aligns with the macOS pattern mentioned in the comments and the production behavior described in the summary.


127-135: LGTM!

The cursor position test correctly validates that at 100% DPI (scale 1.0), the physical cursor position (200, 200) equals the logical position (200, 200).


721-767: LGTM!

The remaining tests for multi-monitor simulation, high DPI scaling, rapid sampling, and error messages are straightforward and correctly validate the expected behavior.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@RobbieTheWagner RobbieTheWagner merged commit faff20e into main Jan 15, 2026
7 checks passed
@RobbieTheWagner RobbieTheWagner deleted the windows-dpi-aware branch January 15, 2026 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants