native_windows_gui/win32/
plotters_d2d.rs

1/*!
2    Direct2D backend for the plotters control
3*/
4use winapi::shared::windef::HWND;
5use winapi::um::d2d1::*;
6use winapi::um::dwrite::{IDWriteFactory, IDWriteTextFormat, DWriteCreateFactory, DWRITE_FACTORY_TYPE_SHARED};
7use winapi::shared::winerror::{S_OK, D2DERR_RECREATE_TARGET};
8
9use super::base_helper::to_utf16;
10use super::{high_dpi, window_helper};
11use std::{cell::{Ref, RefCell, RefMut}, collections::HashMap, mem, ptr};
12
13use plotters::prelude::DrawingBackend;
14use plotters_backend::{DrawingErrorKind, BackendColor, BackendStyle, BackendTextStyle, BackendCoord};
15
16
17
18#[derive(Hash, Eq, PartialEq, Copy, Clone)]
19struct Color {
20    r: u8,
21    g: u8,
22    b: u8,
23    a: u8,
24}
25
26impl From<&BackendColor> for Color {
27    fn from(c: &BackendColor) -> Self {
28        let (r, g, b) = c.rgb;
29        let a = (c.alpha.clamp(0.0, 1.0) * 255.0) as u8;
30        Color { r, g, b, a }
31    }
32}
33
34#[derive(Hash, Eq, PartialEq, Clone)]
35struct FontFormat {
36    family: String,
37    size: u32,
38    style: u32,
39    is_bold: bool
40}
41
42impl<T: BackendTextStyle> From<&T> for FontFormat {
43
44    fn from(text: &T) -> Self {
45        use plotters_backend::{FontFamily::*, FontStyle::*};
46        use winapi::um::dwrite::{DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STYLE_OBLIQUE, DWRITE_FONT_STYLE_ITALIC};
47
48        let size = (text.size() * 100.0) as u32;
49
50        let family = match text.family() {
51            Serif => { "Georgia" },
52            SansSerif => { "Arial" },
53            Monospace => { "Courier New" },
54            Name(name) => { name }
55        };
56
57        let mut is_bold = false;
58        let style = match text.style() {
59            Normal => DWRITE_FONT_STYLE_NORMAL,
60            Oblique => DWRITE_FONT_STYLE_OBLIQUE,
61            Italic => DWRITE_FONT_STYLE_ITALIC,
62            Bold => {
63                is_bold = true;
64                DWRITE_FONT_STYLE_NORMAL
65            },
66        };
67
68        FontFormat {
69            family: family.to_owned(),
70            size,
71            style,
72            is_bold
73        }
74    }
75}
76
77
78/**
79    Errors that can be returned when using the Plotters control
80*/
81#[derive(Debug, Clone)]
82pub enum PlottersError {
83    RendererInit(String),
84    Uninitialized,
85    Unknown,
86}
87
88impl std::fmt::Display for PlottersError {
89
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        use PlottersError::*;
92        match self {
93            RendererInit(reason) => write!(f, "Plotters inner canvas creation failed: {}", reason),
94            Uninitialized => write!(f, "The plotters canvas is not initialized"),
95            Unknown => write!(f, "An unexpected error occured"),
96        }
97    }
98
99}
100
101impl std::error::Error for PlottersError {
102
103}
104
105struct PixelBitmap {
106    memory: Vec<u8>,
107    size: (u32, u32),
108    bitmap: *mut ID2D1Bitmap
109}
110
111struct Target {
112    render_target: *mut ID2D1HwndRenderTarget,
113    brushes: HashMap<Color, *mut ID2D1SolidColorBrush>,
114
115    // Target to draw pixels if draw_pixel is called
116    pixel_bitmap: Option<PixelBitmap>,
117    write_pixels: bool,
118
119    size: (u32, u32),
120    last_error: i32,
121}
122
123impl Target {
124    fn fetch_brush(&mut self, color: Color) -> *mut ID2D1SolidColorBrush {
125        let render_target = unsafe { &*self.render_target };
126        let brush = self.brushes.entry(color)
127            .or_insert_with(|| {
128                let mut brush = ptr::null_mut();
129                let props  = D2D1_BRUSH_PROPERTIES {
130                    opacity: 1.0,
131                    transform: D2D1_MATRIX_3X2_F {
132                        matrix: [[1.0, 0.0], [0.0, 1.0], [0.0, 0.0]]
133                    }
134                };
135
136                let [r, g, b, a] = [
137                    color.r as f32 / 255.0,
138                    color.g as f32 / 255.0,
139                    color.b as f32 / 255.0,
140                    color.a as f32 / 255.0,
141                ];
142
143                unsafe {
144                    render_target.CreateSolidColorBrush(
145                        &D2D1_COLOR_F { r, g, b, a },
146                        &props,
147                        &mut brush
148                    );
149                }
150
151                brush
152            });
153
154        *brush
155    }
156
157    pub(crate) fn allocate_pixel_bitmap(&mut self, renderer: *mut ID2D1Factory) {
158        use winapi::shared::dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM;
159        use winapi::um::dcommon::{D2D1_PIXEL_FORMAT, D2D1_ALPHA_MODE_PREMULTIPLIED};
160
161        if let Some(bitmap) = self.pixel_bitmap.as_ref() {
162            let old_size = bitmap.size;
163            let new_size = self.size;
164            if old_size == new_size {
165                return;
166            }
167        }
168
169        let (width, height) = (self.size.0 as usize, self.size.1 as usize);
170        let pixel_size = 4;
171
172        let bitmap = unsafe {
173            let mut bitmap = ptr::null_mut();
174
175            let mut dpi_x = 0.0;
176            let mut dpi_y = 0.0;
177            (&*renderer).GetDesktopDpi(&mut dpi_x, &mut dpi_y);
178
179            (&*self.render_target).CreateBitmap(
180                D2D1_SIZE_U { width: width as _, height: height as _ },
181                ptr::null(),
182                0,
183                &D2D1_BITMAP_PROPERTIES {
184                    pixelFormat: D2D1_PIXEL_FORMAT { format: DXGI_FORMAT_R8G8B8A8_UNORM, alphaMode: D2D1_ALPHA_MODE_PREMULTIPLIED },
185                    dpiX: dpi_x,
186                    dpiY: dpi_y,
187                },
188                &mut bitmap,
189            );
190
191            bitmap
192        };
193
194        self.pixel_bitmap = Some(PixelBitmap {
195            memory: vec![0; width*height*pixel_size],
196            size: self.size,
197            bitmap
198        });
199    }
200
201}
202
203impl Drop for Target {
204
205    fn drop(&mut self) {
206        unsafe {
207            for &brush in self.brushes.values() {
208                (&*brush).Release();
209            }
210
211            if !self.render_target.is_null() {
212                (&*self.render_target).Release();
213            }
214        }
215    }
216
217}
218
219/**
220    Direct2D backend for the plotters control
221*/
222pub struct PlottersBackend {
223    renderer: *mut ID2D1Factory,
224    write_factory: *mut IDWriteFactory,
225    text_formats: RefCell<HashMap<FontFormat, *mut IDWriteTextFormat>>,
226    target: RefCell<Target>,
227    simple_stroke_style: *mut ID2D1StrokeStyle,
228}
229
230impl PlottersBackend {
231
232    pub(crate) fn init(handle: HWND) -> Result<PlottersBackend, PlottersError> {
233        unsafe {
234            build_renderer(handle)
235        }
236    }
237
238    pub(crate) fn begin_draw(&self) {
239        unsafe {
240            let target = self.target();
241            (&*target.render_target).BeginDraw();
242        }
243    }
244
245    pub(crate) fn end_draw(&self) {
246        let result = unsafe {
247            let mut target = self.target_mut();
248
249            // Writes the pixel bitmap if needed
250            if target.write_pixels {
251                if let Some(bitmap) = target.pixel_bitmap.as_ref() {
252                    let (width, height) = bitmap.size;
253
254                    let copy_rect = D2D1_RECT_U {
255                        top: 0, left: 0,
256                        bottom: height, right: width,
257                    };
258
259                    let draw_rect = D2D1_RECT_F {
260                        top: 0.0, left: 0.0,
261                        bottom: height as f32, right: width as f32,
262                    };
263
264                    (&*bitmap.bitmap).CopyFromMemory(&copy_rect, bitmap.memory.as_ptr() as _, width*4);
265                    (&*target.render_target).DrawBitmap(
266                        bitmap.bitmap,
267                        &draw_rect,
268                        1.0,
269                        D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
270                        &draw_rect
271                    );
272                }
273
274                target.write_pixels = false;
275            }
276
277            (&*target.render_target).EndDraw(ptr::null_mut(), ptr::null_mut())
278        };
279
280        match result {
281            S_OK => { /* All good */ },
282            e => {
283                self.target_mut().last_error = e;
284            }
285        }
286    }
287
288    pub(crate) fn clear(&self) {
289        unsafe {
290            let target = self.target();
291            (&*target.render_target).Clear(&D2D1_COLOR_F { r: 1.0, g: 1.0, b: 1.0, a: 1.0 });
292        }
293    }
294
295    /// Rebuilds the inner target if needed
296    pub(crate) fn rebuild(&self, handle: HWND) -> Result<(), PlottersError> {
297        let mut target = self.target_mut();
298        let new_size = unsafe { client_size(handle) };
299        if target.size != new_size || target.last_error == D2DERR_RECREATE_TARGET {
300            *target = unsafe { build_render_target(handle, &mut *self.renderer)? };
301        }
302
303
304        target.allocate_pixel_bitmap(self.renderer);
305
306        Ok(())
307    }
308
309    fn target(&self) -> Ref<Target> {
310        self.target.borrow()
311    }
312
313    fn fetch_text_format(&self, mut fmt: FontFormat) -> *mut IDWriteTextFormat {
314        use winapi::um::dwrite::{DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STRETCH_NORMAL};
315
316        let write_factory = unsafe { &*self.write_factory };
317
318        // Setting a font with a size lesser than 100 will segfault direct2D
319        fmt.size = fmt.size.max(100);
320
321        let mut formats = self.text_formats.borrow_mut();
322        let text_format = formats.entry(fmt.clone())
323            .or_insert_with(move || {
324                let mut text_format = ptr::null_mut();
325
326                let font_size = (fmt.size as f32) / 100.0;
327                let family_name = to_utf16(&fmt.family);
328                let locale = unsafe { locale_name() };
329
330                let weight = match fmt.is_bold {
331                    true => DWRITE_FONT_WEIGHT_BOLD,
332                    false => DWRITE_FONT_WEIGHT_NORMAL,
333                };
334
335                unsafe {
336                    write_factory.CreateTextFormat(
337                        family_name.as_ptr(),
338                        ptr::null_mut(),
339                        weight,
340                        fmt.style,
341                        DWRITE_FONT_STRETCH_NORMAL,
342                        font_size,
343                        locale.as_ptr(),
344                        &mut text_format
345                    );
346                }
347
348                text_format
349            });
350
351        *text_format
352    }
353
354    fn target_mut(&self) -> RefMut<Target> {
355        self.target.borrow_mut()
356    }
357
358}
359
360impl Drop for PlottersBackend {
361
362    fn drop(&mut self) {
363        unsafe {
364            let formats = self.text_formats.borrow();
365            for &fmt in formats.values() {
366                (&*fmt).Release();
367            }
368
369            if !self.simple_stroke_style.is_null() {
370                (&*self.simple_stroke_style).Release();
371            }
372
373            if !self.renderer.is_null() {
374                (&*self.renderer).Release();
375            }
376
377            if !self.write_factory.is_null() {
378                (&*self.write_factory).Release();
379            }
380        }
381    }
382
383}
384
385impl<'a> DrawingBackend for &'a PlottersBackend {
386    type ErrorType = PlottersError;
387
388    fn get_size(&self) -> (u32, u32) {
389        let (width, height) = self.target().size;
390        let (width, height) = unsafe { high_dpi::physical_to_logical(width as i32, height as i32) };
391        (width as u32, height as u32)
392    }
393
394    fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
395        Ok(())
396    }
397
398    fn present(&mut self) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
399        Ok(())
400    }
401
402    fn draw_pixel(
403        &mut self,
404        point: (i32, i32),
405        color: BackendColor
406    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
407        let mut target = self.target.borrow_mut();
408
409        // Allocate the pixel bitmap if it was not allocated before
410        target.allocate_pixel_bitmap(self.renderer);
411
412        // Tells the API to write the pixel bitmap on top of the canvas at the end of the drawing
413        target.write_pixels = true;
414
415        // Write the pixel to the bitmap
416        let (x, y) = (point.0 as usize, point.1 as usize);
417        let width = target.size.0 as usize;
418        let pixels = target.pixel_bitmap.as_mut().unwrap();
419        let pixel_offset = ((width * y * 4) + (x * 4)).max(0);
420        pixels.memory[pixel_offset] = color.rgb.0;
421        pixels.memory[pixel_offset+1] = color.rgb.1;
422        pixels.memory[pixel_offset+2] = color.rgb.2;
423        pixels.memory[pixel_offset+3] = 255;
424
425        Ok(())
426    }
427
428    fn draw_line<S: BackendStyle>(
429        &mut self,
430        from: (i32, i32),
431        to: (i32, i32),
432        style: &S
433    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
434        let mut target = self.target_mut();
435        let stroke_width = style.stroke_width() as f32;
436        let brush = target.fetch_brush(Color::from(&style.color()));
437
438        unsafe {
439            let p0 = D2D1_POINT_2F { x: from.0 as f32, y: from.1 as f32 };
440            let p1 = D2D1_POINT_2F { x: to.0 as f32, y: to.1 as f32 };
441            (&*target.render_target).DrawLine(
442                p0,
443                p1,
444                brush as _,
445                stroke_width,
446                self.simple_stroke_style,
447            );
448        }
449
450        Ok(())
451    }
452
453    fn draw_rect<S: BackendStyle>(
454        &mut self,
455        upper_left: (i32, i32),
456        bottom_right: (i32, i32),
457        style: &S,
458        fill: bool
459    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
460        let mut target = self.target_mut();
461        let stroke_width = style.stroke_width() as f32;
462        let brush = target.fetch_brush(Color::from(&style.color()));
463
464        let left = upper_left.0 as f32;
465        let right = bottom_right.0 as f32;
466        let bottom = bottom_right.1 as f32;
467        let top = upper_left.1 as f32;
468
469        unsafe {
470            let rect = D2D1_RECT_F {
471                left,
472                top,
473                right: right.max(left),
474                bottom: bottom.max(top),
475            };
476
477            match fill {
478                true => {
479                    (&*target.render_target).FillRectangle(
480                        &rect,
481                        brush as _
482                    );
483                },
484                false => {
485                    (&*target.render_target).DrawRectangle(
486                        &rect,
487                        brush as _,
488                        stroke_width,
489                        self.simple_stroke_style
490                    )
491                }
492            }
493
494        }
495
496        Ok(())
497    }
498
499    fn draw_path<S: BackendStyle, I: IntoIterator<Item = (i32, i32)>>(
500        &mut self,
501        path: I,
502        style: &S
503    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
504        let mut target = self.target_mut();
505        let stroke_width = style.stroke_width() as f32;
506        let brush = target.fetch_brush(Color::from(&style.color()));
507
508        let mut iter_path = path.into_iter();
509        let (mut last_x, mut last_y) = iter_path.next().unwrap_or((0, 0));
510        for (x, y) in iter_path {
511            let p0 = D2D1_POINT_2F { x: last_x as f32, y: last_y as f32 };
512            let p1 = D2D1_POINT_2F { x: x as f32, y: y as f32 };
513
514            unsafe {
515                (&*target.render_target).DrawLine(
516                    p0,
517                    p1,
518                    brush as _,
519                    stroke_width,
520                    self.simple_stroke_style,
521                );
522            }
523
524            last_x = x;
525            last_y = y;
526        }
527
528        Ok(())
529    }
530
531    fn draw_circle<S: BackendStyle>(
532        &mut self,
533        center: (i32, i32),
534        radius: u32,
535        style: &S,
536        fill: bool
537    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
538        let mut target = self.target_mut();
539        let stroke_width = style.stroke_width() as f32;
540        let brush = target.fetch_brush(Color::from(&style.color()));
541
542        unsafe {
543            let ellipse = D2D1_ELLIPSE {
544                point: D2D1_POINT_2F { x: center.0 as f32, y: center.1 as f32 },
545                radiusX: radius as f32,
546                radiusY: radius as f32,
547            };
548
549            match fill {
550                true => {
551                    (&*target.render_target).FillEllipse(
552                        &ellipse,
553                        brush as _
554                    );
555                },
556                false => {
557                    (&*target.render_target).DrawEllipse(
558                        &ellipse,
559                        brush as _,
560                        stroke_width,
561                        self.simple_stroke_style
562                    )
563                }
564            }
565
566        }
567
568        Ok(())
569    }
570
571    fn fill_polygon<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(
572        &mut self,
573        vert: I,
574        style: &S
575    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
576
577        let mut target = self.target_mut();
578        let brush = target.fetch_brush(Color::from(&style.color()));
579
580        unsafe {
581            let fact = &*self.renderer;
582            let mut path = ptr::null_mut();
583            let mut sink = ptr::null_mut();
584
585
586            fact.CreatePathGeometry(&mut path);
587            (&*path).Open(&mut sink);
588
589            let mut vertex_iter = vert.into_iter();
590            let (px, py) = vertex_iter.next().unwrap_or((0, 0));
591            (&*sink).BeginFigure(D2D1_POINT_2F { x: px as f32, y: py as f32 }, D2D1_FIGURE_BEGIN_FILLED);
592
593            for (px, py) in vertex_iter {
594                (&*sink).AddLine(D2D1_POINT_2F { x: px as f32, y: py as f32 });
595            }
596
597            (&*sink).EndFigure(D2D1_FIGURE_END_CLOSED);
598            (&*sink).Close();
599
600
601            (&*target.render_target).FillGeometry(
602                path as _,
603                brush as _,
604                ptr::null_mut(),
605            );
606
607
608            (&*sink).Release();
609            (&*path).Release();
610        }
611
612        Ok(())
613    }
614
615    fn draw_text<TStyle: BackendTextStyle>(
616        &mut self,
617        text: &str,
618        style: &TStyle,
619        pos: (i32, i32)
620    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
621        use winapi::um::dcommon::DWRITE_MEASURING_MODE_NATURAL;
622        use plotters::style::text_anchor::{HPos, VPos};
623
624        let mut target = self.target_mut();
625        let brush = target.fetch_brush(Color::from(&style.color()));
626
627        let text_format = self.fetch_text_format(FontFormat::from(style));
628        let raw_text = to_utf16(text);
629        let (width, height) = target.size;
630
631        let [min_x, min_y, max_x, max_y] = style
632            .layout_box(text)
633            .map(|((min_x, min_y), (max_x, max_y))| [min_x, min_y, max_x, max_y] )
634            .unwrap_or([0, 0, 0, 0]);
635
636        let text_width = (max_x - min_x) as i32;
637        let text_height = (max_y - min_y) as i32;
638
639        let dx = match style.anchor().h_pos {
640            HPos::Left => 0,
641            HPos::Right => -text_width,
642            HPos::Center => -text_width / 2,
643        };
644        let dy = match style.anchor().v_pos {
645            VPos::Top => 0,
646            VPos::Center => -text_height / 2,
647            VPos::Bottom => -text_height,
648        };
649
650
651        let (x, y) = (pos.0 + dx, pos.1 + dy);
652
653        let layout_rect = D2D1_RECT_F {
654            left: x as f32,
655            top: y as f32,
656            right: width as f32,
657            bottom: height as f32,
658        };
659
660        unsafe {
661            (&*target.render_target).DrawText(
662                raw_text.as_ptr(),
663                (raw_text.len() - 1) as _,
664                text_format,
665                &layout_rect,
666                brush as _,
667                D2D1_DRAW_TEXT_OPTIONS_NONE,
668                DWRITE_MEASURING_MODE_NATURAL,
669            );
670        }
671
672        Ok(())
673    }
674
675    fn estimate_text_size<TStyle: BackendTextStyle>(
676        &self,
677        text: &str,
678        style: &TStyle
679    ) -> Result<(u32, u32), DrawingErrorKind<Self::ErrorType>> {
680        use winapi::um::dwrite::DWRITE_TEXT_METRICS;
681
682        let text_format = self.fetch_text_format(FontFormat::from(style));
683        let text = to_utf16(text);
684
685        let [width, height]: [u32; 2];
686
687        unsafe {
688            let write = &*self.write_factory;
689            let mut layout = ptr::null_mut();
690
691            write.CreateTextLayout (
692                text.as_ptr(),
693                text.len() as _,
694                text_format,
695                1000.0,
696                1000.0,
697                &mut layout,
698            );
699
700            let layout = &*layout;
701            let mut metrics: DWRITE_TEXT_METRICS = mem::zeroed();
702            layout.GetMetrics(&mut metrics);
703
704            width = metrics.width as u32;
705            height = metrics.height as u32;
706
707            layout.Release();
708        }
709
710
711        Ok((width, height))
712    }
713
714    fn blit_bitmap<'b>(
715        &mut self,
716        _pos: (i32, i32),
717        (_iw, _ih): (u32, u32),
718        _src: &'b [u8]
719    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
720        Ok(())
721    }
722
723}
724
725unsafe fn build_render_target(hwnd: HWND, factory: &mut ID2D1Factory) -> Result<Target, PlottersError> {
726    use winapi::shared::dxgiformat::{DXGI_FORMAT_B8G8R8A8_UNORM};
727    use winapi::um::dcommon::{D2D_SIZE_U, D2D1_PIXEL_FORMAT, D2D1_ALPHA_MODE_PREMULTIPLIED};
728
729    let (width, height) = client_size(hwnd);
730    let size = D2D_SIZE_U { width, height };
731
732    let pixel_format = D2D1_PIXEL_FORMAT {
733        format: DXGI_FORMAT_B8G8R8A8_UNORM,
734        alphaMode: D2D1_ALPHA_MODE_PREMULTIPLIED
735    };
736
737    let render_props = D2D1_RENDER_TARGET_PROPERTIES {
738        _type: D2D1_RENDER_TARGET_TYPE_DEFAULT,
739        pixelFormat: pixel_format,
740        dpiX: 0.0, dpiY: 0.0,
741        usage: D2D1_RENDER_TARGET_USAGE_NONE,
742        minLevel: D2D1_FEATURE_LEVEL_DEFAULT
743    };
744
745    let hwnd_render_props = D2D1_HWND_RENDER_TARGET_PROPERTIES {
746        hwnd: hwnd,
747        pixelSize: size,
748        presentOptions: D2D1_PRESENT_OPTIONS_NONE
749    };
750
751    let mut render_target: *mut ID2D1HwndRenderTarget = ptr::null_mut();
752    if factory.CreateHwndRenderTarget(&render_props, &hwnd_render_props, &mut render_target) != S_OK {
753        factory.Release();
754        Err(PlottersError::RendererInit("Failed to create the direct2D render target".into()))
755    } else {
756        Ok(Target {
757            render_target,
758            brushes: Default::default(),
759            pixel_bitmap: None,
760            write_pixels: false,
761            size: (width, height),
762            last_error: S_OK
763        })
764    }
765}
766
767unsafe fn build_static_resources(backend: &mut PlottersBackend) -> Result<(), PlottersError> {
768    let f = &mut *backend.renderer;
769
770    let props = D2D1_STROKE_STYLE_PROPERTIES {
771        startCap: D2D1_CAP_STYLE_ROUND,
772        endCap: D2D1_CAP_STYLE_ROUND,
773        dashCap: D2D1_CAP_STYLE_ROUND,
774        lineJoin: D2D1_LINE_JOIN_MITER,
775        miterLimit: 0.0,
776        dashStyle: D2D1_DASH_STYLE_SOLID,
777        dashOffset: 0.0,
778    };
779
780    f.CreateStrokeStyle(
781        &props,
782        ptr::null(),
783        0,
784        &mut backend.simple_stroke_style
785    );
786
787    Ok(())
788}
789
790unsafe fn client_size(hwnd: HWND) -> (u32, u32) {
791    window_helper::get_window_physical_size(hwnd)
792}
793
794unsafe fn locale_name() -> Vec<u16> {
795    use winapi::um::winnls::GetUserDefaultLocaleName;
796    use winapi::um::winnt::LOCALE_NAME_MAX_LENGTH;
797
798    let mut name_buffer: Vec<u16> = vec![0; LOCALE_NAME_MAX_LENGTH];
799    GetUserDefaultLocaleName(name_buffer.as_mut_ptr(), LOCALE_NAME_MAX_LENGTH as i32);
800
801    name_buffer
802}
803
804unsafe fn build_renderer(handle: HWND) -> Result<PlottersBackend, PlottersError> {
805    use winapi::ctypes::c_void;
806    use winapi::Interface;
807
808    // Build the write factory
809    let mut write_factory: *mut IDWriteFactory = ptr::null_mut();
810    let result = DWriteCreateFactory (
811        DWRITE_FACTORY_TYPE_SHARED,
812        &IDWriteFactory::uuidof(),
813        (&mut write_factory as *mut *mut IDWriteFactory) as _
814    );
815    if result != S_OK {
816        return Err(PlottersError::RendererInit("Failed to create the direct2D factory".into()));
817    }
818
819    // Build the factory
820    let mut renderer: *mut ID2D1Factory = ptr::null_mut();
821    let result = D2D1CreateFactory(
822        D2D1_FACTORY_TYPE_SINGLE_THREADED,
823        &ID2D1Factory::uuidof(),
824        ptr::null(),
825        (&mut renderer as *mut *mut ID2D1Factory) as *mut *mut c_void
826    );
827
828    if result != S_OK {
829        (&*write_factory).Release();
830        return Err(PlottersError::RendererInit("Failed to create the direct2D factory".into()));
831    }
832
833    // Build the render target
834    let target = match build_render_target(handle, &mut *renderer) {
835        Ok(target) => target,
836        e @ Err(_) => {
837            (&*renderer).Release();
838            (&*write_factory).Release();
839            e?
840        }
841    };
842
843    let mut renderer = PlottersBackend {
844        renderer,
845        write_factory,
846        text_formats: RefCell::new(Default::default()),
847        target: RefCell::new(target),
848        simple_stroke_style: ptr::null_mut(),
849    };
850
851    // Build static resources
852    build_static_resources(&mut renderer)?;
853
854    Ok(renderer)
855}