native_windows_gui2/win32/
plotters_d2d.rs

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