1use 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#[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 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
219pub 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 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(©_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 => { },
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 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 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 target.allocate_pixel_bitmap(self.renderer);
411
412 target.write_pixels = true;
414
415 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 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 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 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(&mut renderer)?;
853
854 Ok(renderer)
855}