1use 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#[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 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
223pub 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 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 ©_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 => { }
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 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 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 target.allocate_pixel_bitmap(self.renderer);
422
423 target.write_pixels = true;
425
426 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 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 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 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(&mut renderer)?;
883
884 Ok(renderer)
885}