1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "renderer/win32/text_renderer.h"
31
32 #define _ATL_NO_AUTOMATIC_NAMESPACE
33 #define _WTL_NO_AUTOMATIC_NAMESPACE
34 #include <atlbase.h>
35 #include <atlcom.h>
36 #include <objbase.h>
37 #include <d2d1.h>
38 #include <dwrite.h>
39
40 #include <memory>
41
42 #include "base/logging.h"
43 #include "base/system_util.h"
44 #include "protocol/renderer_style.pb.h"
45 #include "renderer/renderer_style_handler.h"
46
47 namespace mozc {
48 namespace renderer {
49 namespace win32 {
50
51 using ATL::CComPtr;
52 using WTL::CDC;
53 using WTL::CDCHandle;
54 using WTL::CFont;
55 using WTL::CFontHandle;
56 using WTL::CLogFont;
57 using WTL::CPoint;
58 using WTL::CRect;
59 using WTL::CSize;
60 using ::mozc::renderer::RendererStyle;
61 using ::mozc::renderer::RendererStyleHandler;
62
63 namespace {
64
ToCRect(const Rect & rect)65 WTL::CRect ToCRect(const Rect &rect) {
66 return WTL::CRect(rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
67 }
68
GetTextColor(TextRenderer::FONT_TYPE type)69 COLORREF GetTextColor(TextRenderer::FONT_TYPE type) {
70 switch (type) {
71 case TextRenderer::FONTSET_SHORTCUT:
72 return RGB(0x61, 0x61, 0x61);
73 case TextRenderer::FONTSET_CANDIDATE:
74 return RGB(0x00, 0x00, 0x00);
75 case TextRenderer::FONTSET_DESCRIPTION:
76 return RGB(0x88, 0x88, 0x88);
77 case TextRenderer::FONTSET_FOOTER_INDEX:
78 return RGB(0x4c, 0x4c, 0x4c);
79 case TextRenderer::FONTSET_FOOTER_LABEL:
80 return RGB(0x4c, 0x4c, 0x4c);
81 case TextRenderer::FONTSET_FOOTER_SUBLABEL:
82 return RGB(0xA7, 0xA7, 0xA7);
83 }
84
85 // TODO(horo): Not only infolist fonts but also candidate fonts
86 // should be created from RendererStyle
87 RendererStyle style;
88 RendererStyleHandler::GetRendererStyle(&style);
89 const auto &infostyle = style.infolist_style();
90 switch (type) {
91 case TextRenderer::FONTSET_INFOLIST_CAPTION:
92 return RGB(infostyle.caption_style().foreground_color().r(),
93 infostyle.caption_style().foreground_color().g(),
94 infostyle.caption_style().foreground_color().b());
95 case TextRenderer::FONTSET_INFOLIST_TITLE:
96 return RGB(infostyle.title_style().foreground_color().r(),
97 infostyle.title_style().foreground_color().g(),
98 infostyle.title_style().foreground_color().b());
99 case TextRenderer::FONTSET_INFOLIST_DESCRIPTION:
100 return RGB(infostyle.description_style().foreground_color().r(),
101 infostyle.description_style().foreground_color().g(),
102 infostyle.description_style().foreground_color().b());
103 }
104
105 LOG(DFATAL) << "Unknown type: " << type;
106 return RGB(0, 0, 0);
107 }
108
GetLogFont(TextRenderer::FONT_TYPE type)109 CLogFont GetLogFont(TextRenderer::FONT_TYPE type) {
110 switch (type) {
111 case TextRenderer::FONTSET_SHORTCUT: {
112 CLogFont font;
113 font.SetMessageBoxFont();
114 font.MakeLarger(3);
115 font.lfWeight = FW_BOLD;
116 return font;
117 }
118 case TextRenderer::FONTSET_CANDIDATE: {
119 CLogFont font;
120 font.SetMessageBoxFont();
121 font.MakeLarger(3);
122 font.lfWeight = FW_NORMAL;
123 return font;
124 }
125 case TextRenderer::FONTSET_DESCRIPTION:
126 case TextRenderer::FONTSET_FOOTER_INDEX:
127 case TextRenderer::FONTSET_FOOTER_LABEL:
128 case TextRenderer::FONTSET_FOOTER_SUBLABEL: {
129 CLogFont font;
130 font.SetMessageBoxFont();
131 font.lfWeight = FW_NORMAL;
132 return font;
133 }
134 }
135
136 // TODO(horo): Not only infolist fonts but also candidate fonts
137 // should be created from RendererStyle
138 RendererStyle style;
139 RendererStyleHandler::GetRendererStyle(&style);
140 const auto &infostyle = style.infolist_style();
141 switch (type) {
142 case TextRenderer::FONTSET_INFOLIST_CAPTION: {
143 CLogFont font;
144 font.SetMessageBoxFont();
145 font.lfHeight = -infostyle.caption_style().font_size();
146 return font;
147 }
148 case TextRenderer::FONTSET_INFOLIST_TITLE: {
149 CLogFont font;
150 font.SetMessageBoxFont();
151 font.lfHeight = -infostyle.title_style().font_size();
152 return font;
153 }
154 case TextRenderer::FONTSET_INFOLIST_DESCRIPTION: {
155 CLogFont font;
156 font.SetMessageBoxFont();
157 font.lfHeight = -infostyle.description_style().font_size();
158 return font;
159 }
160 }
161
162 LOG(DFATAL) << "Unknown type: " << type;
163 CLogFont font;
164 font.SetMessageBoxFont();
165 return font;
166 }
167
GetGdiDrawTextStyle(TextRenderer::FONT_TYPE type)168 DWORD GetGdiDrawTextStyle(TextRenderer::FONT_TYPE type) {
169 switch (type) {
170 case TextRenderer::FONTSET_CANDIDATE:
171 return DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX;
172 case TextRenderer::FONTSET_DESCRIPTION:
173 return DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX;
174 case TextRenderer::FONTSET_FOOTER_INDEX:
175 return DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX;
176 case TextRenderer::FONTSET_FOOTER_LABEL:
177 return DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX;
178 case TextRenderer::FONTSET_FOOTER_SUBLABEL:
179 return DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX;
180 case TextRenderer::FONTSET_SHORTCUT:
181 return DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX;
182 case TextRenderer::FONTSET_INFOLIST_CAPTION:
183 return DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX;
184 case TextRenderer::FONTSET_INFOLIST_TITLE:
185 return DT_LEFT | DT_SINGLELINE | DT_WORDBREAK | DT_EDITCONTROL |
186 DT_NOPREFIX;
187 case TextRenderer::FONTSET_INFOLIST_DESCRIPTION:
188 return DT_LEFT | DT_WORDBREAK | DT_EDITCONTROL | DT_NOPREFIX;
189 default:
190 LOG(DFATAL) << "Unknown type: " << type;
191 return 0;
192 }
193 }
194
195 class GdiTextRenderer : public TextRenderer {
196 public:
GdiTextRenderer()197 GdiTextRenderer()
198 : render_info_(new RenderInfo[SIZE_OF_FONT_TYPE]) {
199 mem_dc_.CreateCompatibleDC();
200 OnThemeChanged();
201 }
202
~GdiTextRenderer()203 virtual ~GdiTextRenderer() {
204 }
205
206 private:
207 // TextRenderer overrides:
OnThemeChanged()208 virtual void OnThemeChanged() {
209 // delete old fonts
210 for (size_t i = 0; i < SIZE_OF_FONT_TYPE; ++i) {
211 if (!render_info_[i].font.IsNull()) {
212 render_info_[i].font.DeleteObject();
213 }
214 }
215
216 for (size_t i = 0; i < SIZE_OF_FONT_TYPE; ++i) {
217 const auto font_type = static_cast<FONT_TYPE>(i);
218 const auto &log_font = GetLogFont(font_type);
219 render_info_[i].style = GetGdiDrawTextStyle(font_type);
220 render_info_[i].font.CreateFontIndirectW(&log_font);
221 render_info_[i].color = GetTextColor(font_type);
222 }
223 }
224
MeasureString(FONT_TYPE font_type,const std::wstring & str) const225 virtual Size MeasureString(FONT_TYPE font_type,
226 const std::wstring &str) const {
227 const auto previous_font = mem_dc_.SelectFont(render_info_[font_type].font);
228 CRect rect;
229 mem_dc_.DrawTextW(str.c_str(), str.length(), &rect,
230 DT_NOPREFIX | DT_LEFT | DT_SINGLELINE | DT_CALCRECT);
231 mem_dc_.SelectFont(previous_font);
232 return Size(rect.Width(), rect.Height());
233 }
234
MeasureStringMultiLine(FONT_TYPE font_type,const std::wstring & str,const int width) const235 virtual Size MeasureStringMultiLine(
236 FONT_TYPE font_type, const std::wstring &str, const int width) const {
237 const auto previous_font = mem_dc_.SelectFont(render_info_[font_type].font);
238 CRect rect(0, 0, width, 0);
239 mem_dc_.DrawTextW(str.c_str(), str.length(), &rect,
240 DT_NOPREFIX | DT_LEFT | DT_WORDBREAK | DT_CALCRECT);
241 mem_dc_.SelectFont(previous_font);
242 return Size(rect.Width(), rect.Height());
243 }
244
RenderText(CDCHandle dc,const std::wstring & text,const Rect & rect,FONT_TYPE font_type) const245 virtual void RenderText(CDCHandle dc,
246 const std::wstring &text,
247 const Rect &rect,
248 FONT_TYPE font_type) const {
249 std::vector<TextRenderingInfo> infolist;
250 infolist.push_back(TextRenderingInfo(text, rect));
251 RenderTextList(dc, infolist, font_type);
252 }
253
RenderTextList(CDCHandle dc,const std::vector<TextRenderingInfo> & display_list,FONT_TYPE font_type) const254 virtual void RenderTextList(
255 CDCHandle dc,
256 const std::vector<TextRenderingInfo> &display_list,
257 FONT_TYPE font_type) const {
258 const auto &render_info = render_info_[font_type];
259 const auto old_font = dc.SelectFont(render_info.font);
260 const auto previous_color = dc.SetTextColor(render_info.color);
261 for (auto it = display_list.begin(); it != display_list.end(); ++it) {
262 const auto &info = *it;
263 CRect rect(info.rect.Left(), info.rect.Top(),
264 info.rect.Right(), info.rect.Bottom());
265 const auto &text = info.text;
266 dc.DrawTextW(text.data(), text.size(), &rect, render_info.style);
267 }
268 dc.SetTextColor(previous_color);
269 dc.SelectFont(old_font);
270 }
271
272 struct RenderInfo {
RenderInfomozc::renderer::win32::__anon9e3abba90111::GdiTextRenderer::RenderInfo273 RenderInfo() : color(0), style(0) {}
274 COLORREF color;
275 DWORD style;
276 CFont font;
277 };
278 std::unique_ptr<RenderInfo[]> render_info_;
279 mutable CDC mem_dc_;
280
281 DISALLOW_COPY_AND_ASSIGN(GdiTextRenderer);
282 };
283
284 class DirectWriteTextRenderer : public TextRenderer {
285 public:
Create()286 static DirectWriteTextRenderer *Create() {
287 HRESULT hr = S_OK;
288 CComPtr<ID2D1Factory> d2d_factory;
289 hr = ::D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
290 __uuidof(ID2D1Factory),
291 nullptr,
292 reinterpret_cast<void **>(&d2d_factory));
293 if (FAILED(hr)) {
294 return nullptr;
295 }
296 CComPtr<IDWriteFactory> dwrite_factory;
297 hr = ::DWriteCreateFactory(
298 DWRITE_FACTORY_TYPE_SHARED,
299 __uuidof(IDWriteFactory),
300 reinterpret_cast<IUnknown **>(&dwrite_factory));
301 if (FAILED(hr)) {
302 return nullptr;
303 }
304 CComPtr<IDWriteGdiInterop> interop;
305 hr = dwrite_factory->GetGdiInterop(&interop);
306 if (FAILED(hr)) {
307 return nullptr;
308 }
309 return new DirectWriteTextRenderer(d2d_factory, dwrite_factory, interop);
310 }
~DirectWriteTextRenderer()311 virtual ~DirectWriteTextRenderer() {
312 }
313
314 private:
DirectWriteTextRenderer(ID2D1Factory * d2d2_factory,IDWriteFactory * dwrite_factory,IDWriteGdiInterop * dwrite_interop)315 DirectWriteTextRenderer(
316 ID2D1Factory *d2d2_factory,
317 IDWriteFactory *dwrite_factory,
318 IDWriteGdiInterop *dwrite_interop)
319 : d2d2_factory_(d2d2_factory),
320 dwrite_factory_(dwrite_factory),
321 dwrite_interop_(dwrite_interop) {
322 OnThemeChanged();
323 }
324
325 // TextRenderer overrides:
OnThemeChanged()326 virtual void OnThemeChanged() {
327 // delete old fonts
328 render_info_.clear();
329 render_info_.resize(SIZE_OF_FONT_TYPE);
330
331 for (size_t i = 0; i < SIZE_OF_FONT_TYPE; ++i) {
332 const auto font_type = static_cast<FONT_TYPE>(i);
333 const auto &log_font = GetLogFont(font_type);
334 render_info_[i].color = GetTextColor(font_type);
335 render_info_[i].format = CreateFormat(log_font);
336 render_info_[i].format_to_render = CreateFormat(log_font);
337 const auto style = GetGdiDrawTextStyle(font_type);
338 const auto render_font = render_info_[i].format_to_render;
339 if ((style & DT_VCENTER) == DT_VCENTER) {
340 render_font->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
341 }
342 if ((style & DT_LEFT) == DT_LEFT) {
343 render_font->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
344 }
345 if ((style & DT_CENTER) == DT_CENTER) {
346 render_font->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
347 }
348 if ((style & DT_LEFT) == DT_RIGHT) {
349 render_font->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING);
350 }
351 }
352 }
353
354 // Retrieves the bounding box for a given string.
MeasureString(FONT_TYPE font_type,const std::wstring & str) const355 virtual Size MeasureString(FONT_TYPE font_type,
356 const std::wstring &str) const {
357 return MeasureStringImpl(font_type, str, 0, false);
358 }
359
MeasureStringMultiLine(FONT_TYPE font_type,const std::wstring & str,const int width) const360 virtual Size MeasureStringMultiLine(FONT_TYPE font_type,
361 const std::wstring &str,
362 const int width) const {
363 return MeasureStringImpl(font_type, str, width, true);
364 }
365
RenderText(CDCHandle dc,const std::wstring & text,const Rect & rect,FONT_TYPE font_type) const366 virtual void RenderText(CDCHandle dc, const std::wstring &text,
367 const Rect &rect, FONT_TYPE font_type) const {
368 std::vector<TextRenderingInfo> infolist;
369 infolist.push_back(TextRenderingInfo(text, rect));
370 RenderTextList(dc, infolist, font_type);
371 }
372
RenderTextList(CDCHandle dc,const std::vector<TextRenderingInfo> & display_list,FONT_TYPE font_type) const373 virtual void RenderTextList(
374 CDCHandle dc,
375 const std::vector<TextRenderingInfo> &display_list,
376 FONT_TYPE font_type) const {
377 const size_t kMaxTrial = 3;
378 size_t trial = 0;
379 while (true) {
380 CreateRenderTargetIfNecessary();
381 if (dc_render_target_ == nullptr) {
382 // This is not a recoverable error.
383 return;
384 }
385 const HRESULT hr = RenderTextListImpl(dc, display_list, font_type);
386 if (hr == D2DERR_RECREATE_TARGET && trial < kMaxTrial) {
387 // This is a recoverable error just by recreating the render target.
388 dc_render_target_.Release();
389 ++trial;
390 continue;
391 }
392 // For other error codes (including S_OK and S_FALSE), or if we exceed the
393 // maximum number of trials, we simply accept the result here.
394 return;
395 }
396 }
397
RenderTextListImpl(CDCHandle dc,const std::vector<TextRenderingInfo> & display_list,FONT_TYPE font_type) const398 HRESULT RenderTextListImpl(CDCHandle dc,
399 const std::vector<TextRenderingInfo> &display_list,
400 FONT_TYPE font_type) const {
401 CRect total_rect;
402 for (const auto &item : display_list) {
403 const auto &item_rect = ToCRect(item.rect);
404 total_rect.right = std::max(total_rect.right, item_rect.right);
405 total_rect.bottom = std::max(total_rect.bottom, item_rect.bottom);
406 }
407 HRESULT hr = S_OK;
408 hr = dc_render_target_->BindDC(dc, &total_rect);
409 if (FAILED(hr)) {
410 return hr;
411 }
412 CComPtr<ID2D1SolidColorBrush> brush;
413 hr = dc_render_target_->CreateSolidColorBrush(
414 ToD2DColor(render_info_[font_type].color),
415 &brush);
416 if (FAILED(hr)) {
417 return hr;
418 }
419 D2D1_DRAW_TEXT_OPTIONS option = D2D1_DRAW_TEXT_OPTIONS_NONE;
420 if (SystemUtil::IsWindows8_1OrLater()) {
421 option |= D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT;
422 }
423 dc_render_target_->BeginDraw();
424 dc_render_target_->SetTransform(D2D1::Matrix3x2F::Identity());
425 for (size_t i = 0; i < display_list.size(); ++i) {
426 const auto &item = display_list[i];
427 const D2D1_RECT_F render_rect = {
428 static_cast<float>(item.rect.Left()),
429 static_cast<float>(item.rect.Top()),
430 static_cast<float>(item.rect.Right()),
431 static_cast<float>(item.rect.Bottom()),
432 };
433 dc_render_target_->DrawText(item.text.data(),
434 item.text.size(),
435 render_info_[font_type].format_to_render,
436 render_rect,
437 brush,
438 option);
439 }
440 return dc_render_target_->EndDraw();
441 }
442
MeasureStringImpl(FONT_TYPE font_type,const std::wstring & str,const int width,bool use_width) const443 Size MeasureStringImpl(FONT_TYPE font_type, const std::wstring &str,
444 const int width, bool use_width) const {
445 HRESULT hr = S_OK;
446 const FLOAT kLayoutLimit = 100000.0f;
447 CComPtr<IDWriteTextLayout> layout;
448 hr = dwrite_factory_->CreateTextLayout(str.data(),
449 str.size(),
450 render_info_[font_type].format,
451 (use_width ? width : kLayoutLimit),
452 kLayoutLimit,
453 &layout);
454 if (FAILED(hr)) {
455 return Size();
456 }
457 DWRITE_TEXT_METRICS metrix = {};
458 hr = layout->GetMetrics(&metrix);
459 if (FAILED(hr)) {
460 return Size();
461 }
462 return Size(ceilf(metrix.widthIncludingTrailingWhitespace),
463 ceilf(metrix.height));
464 }
465
ToD2DColor(COLORREF color_ref)466 static D2D1_COLOR_F ToD2DColor(COLORREF color_ref) {
467 D2D1_COLOR_F color;
468 color.a = 1.0;
469 color.r = GetRValue(color_ref) / 255.0f;
470 color.g = GetGValue(color_ref) / 255.0f;
471 color.b = GetBValue(color_ref) / 255.0f;
472 return color;
473 }
474
CreateFormat(CLogFont logfont)475 CComPtr<IDWriteTextFormat> CreateFormat(CLogFont logfont) {
476 HRESULT hr = S_OK;
477 CComPtr<IDWriteFont> font;
478 hr = dwrite_interop_->CreateFontFromLOGFONT(&logfont, &font);
479 if (FAILED(hr)) {
480 return nullptr;
481 }
482 CComPtr<IDWriteFontFamily> font_family;
483 hr = font->GetFontFamily(&font_family);
484 if (FAILED(hr)) {
485 return nullptr;
486 }
487 CComPtr<IDWriteLocalizedStrings> localized_family_names;
488 hr = font_family->GetFamilyNames(&localized_family_names);
489 if (FAILED(hr)) {
490 return nullptr;
491 }
492 UINT32 length = 0;
493 hr = localized_family_names->GetStringLength(0, &length);
494 if (FAILED(hr)) {
495 return nullptr;
496 }
497 length += 1; // for NUL.
498 std::unique_ptr<wchar_t[]> family_name(new wchar_t[length]);
499 hr = localized_family_names->GetString(0, family_name.get(), length);
500 if (FAILED(hr)) {
501 return nullptr;
502 }
503 auto font_size = logfont.lfHeight;
504 if (font_size < 0) {
505 font_size = -font_size;
506 } else {
507 DWRITE_FONT_METRICS font_metrix = {};
508 font->GetMetrics(&font_metrix);
509 const auto cell_height =
510 static_cast<float>(font_metrix.ascent + font_metrix.descent) /
511 font_metrix.designUnitsPerEm;
512 font_size /= cell_height;
513 }
514
515 wchar_t locale_name[LOCALE_NAME_MAX_LENGTH] = {};
516 if (::GetUserDefaultLocaleName(locale_name, arraysize(locale_name))
517 == 0) {
518 return nullptr;
519 }
520
521 CComPtr<IDWriteTextFormat> format;
522 hr = dwrite_factory_->CreateTextFormat(family_name.get(),
523 nullptr,
524 font->GetWeight(),
525 font->GetStyle(),
526 font->GetStretch(),
527 font_size,
528 locale_name,
529 &format);
530 return format;
531 }
532
CreateRenderTargetIfNecessary() const533 void CreateRenderTargetIfNecessary() const {
534 if (dc_render_target_) {
535 return;
536 }
537 const auto property = D2D1::RenderTargetProperties(
538 D2D1_RENDER_TARGET_TYPE_DEFAULT,
539 D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
540 0,
541 0,
542 D2D1_RENDER_TARGET_USAGE_NONE,
543 D2D1_FEATURE_LEVEL_DEFAULT);
544 d2d2_factory_->CreateDCRenderTarget(&property, &dc_render_target_);
545 }
546
547 struct RenderInfo {
RenderInfomozc::renderer::win32::__anon9e3abba90111::DirectWriteTextRenderer::RenderInfo548 RenderInfo() : color(0) {}
549 COLORREF color;
550 CComPtr<IDWriteTextFormat> format;
551 CComPtr<IDWriteTextFormat> format_to_render;
552 };
553
554 CComPtr<ID2D1Factory> d2d2_factory_;
555 CComPtr<IDWriteFactory> dwrite_factory_;
556 mutable CComPtr<ID2D1DCRenderTarget> dc_render_target_;
557 CComPtr<IDWriteGdiInterop> dwrite_interop_;
558 std::vector<RenderInfo> render_info_;
559
560 DISALLOW_COPY_AND_ASSIGN(DirectWriteTextRenderer);
561 };
562
563 } // namespace
564
~TextRenderer()565 TextRenderer::~TextRenderer() {
566 }
567
568 // static
Create()569 TextRenderer *TextRenderer::Create() {
570 // In some environments, DirectWrite cannot render characters in the
571 // candidate window or even worse may cause crash. As a workaround,
572 // we try to use DirectWrite only on Windows 8.1 and later.
573 // TODO(yukawa): Reactivate the following code for older OSes when
574 // the root cause of b/23803925 is identified.
575 if (SystemUtil::IsWindows8_1OrLater()) {
576 auto *dwrite_text_renderer = DirectWriteTextRenderer::Create();
577 if (dwrite_text_renderer != nullptr) {
578 return dwrite_text_renderer;
579 }
580 }
581 return new GdiTextRenderer();
582 }
583
584 } // namespace win32
585 } // namespace renderer
586 } // namespace mozc
587