2 #include "wxWinTranslations.h"
3 #include <wx/fontdlg.h>
4 #include <wx/fontenum.h>
5 #include <wx/textfile.h>
6 #include <wx/graphics.h>
8 #include "PathHelpers.h"
12 #define COLOR_ATTRIBUTES ( FOREGROUND_INTENSITY | BACKGROUND_INTENSITY | \
13 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | \
14 BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE )
19 # define DEFAULT_FONT_SIZE 20
21 # define DEFAULT_FONT_SIZE 16
24 /////////////////////////////////////////////////////////////////////////////////
25 static const char *g_known_good_fonts
[] = { "Ubuntu", "Terminus", "DejaVu",
26 "Liberation", "Droid", "Monospace", "PT Mono", "Menlo",
30 class FixedFontLookup
: wxFontEnumerator
32 wxString _any
, _known_good
;
33 virtual bool OnFacename(const wxString
&face_name
)
36 for (const char **p
= g_known_good_fonts
; *p
; ++p
) {
37 if (face_name
.find(*p
)!=wxString::npos
) {
38 _known_good
= face_name
;
42 /* unfortunatelly following code gives nothing interesting
43 wxFont f(wxFontInfo(DEFAULT_FONT_SIZE).Underlined().FaceName(face_name));
45 fprintf(stderr, "FONT family %u encoding %u face_name='%ls' \n",
46 (unsigned int)f.GetFamily(), (unsigned int)f.GetEncoding(), static_cast<const wchar_t*>(face_name.wc_str()));
48 fprintf(stderr, "BAD FONT: face_name='%ls'\n", static_cast<const wchar_t*>(face_name.wc_str()));
58 EnumerateFacenames(wxFONTENCODING_SYSTEM
, true);
59 fprintf(stderr
, "FixedFontLookup: _any='%ls' _known_good='%ls'\n",
60 static_cast<const wchar_t*>(_any
.wc_str()),
61 static_cast<const wchar_t*>(_known_good
.wc_str()));
62 return _known_good
.IsEmpty() ? _any
: _known_good
;
66 static bool LoadFontFromSettings(wxFont
& font
)
68 const std::string
&path
= InMyConfig("font");
69 wxTextFile
file(path
);
70 if (file
.Exists() && file
.Open()) {
71 for (wxString str
= file
.GetFirstLine(); !file
.Eof(); str
= file
.GetNextLine()) {
72 font
.SetNativeFontInfo(str
);
74 printf("LoadFontFromSettings: used %ls\n",
75 static_cast<const wchar_t*>(str
.wc_str()));
84 static bool ChooseFontAndSaveToSettings(wxWindow
*parent
, wxFont
& font
)
86 font
= wxGetFontFromUser(parent
, font
);
88 const std::string
&path
= InMyConfig("font");
93 file
.InsertLine(font
.GetNativeFontInfoDesc(), 0);
101 static void InitializeFont(wxWindow
*parent
, wxFont
& font
)
103 if (LoadFontFromSettings(font
))
109 wxString fixed_font
= ffl
.Query();
110 if (!fixed_font
.empty()) {
111 font
= wxFont(DEFAULT_FONT_SIZE
, wxFONTFAMILY_DEFAULT
, wxFONTSTYLE_NORMAL
, wxFONTWEIGHT_NORMAL
, false, fixed_font
);
113 if (fixed_font
.empty() || !font
.IsOk())
114 font
= wxFont(wxSystemSettings::GetFont(wxSYS_ANSI_FIXED_FONT
));
115 #if defined(__WXOSX__) && !wxCHECK_VERSION(3, 1, 0)
116 return;//older (not sure what exactly version) wxwidgets crashes in wxGetFontFromUser under OSX, this allows at least to start
118 if (ChooseFontAndSaveToSettings(parent
, font
))
124 ConsolePaintContext::ConsolePaintContext(wxWindow
*window
) :
125 _window(window
), _font_width(12), _font_height(16), _font_descent(0), _font_thickness(2),
126 _buffered_paint(false), _sharp(false)
128 _char_fit_cache
.checked
.resize(0xffff);
129 _char_fit_cache
.result
.resize(0xffff);
131 _window
->SetBackgroundColour(*wxBLACK
);
133 InitializeFont(_window
, font
);
139 class FontSizeInspector
144 int _max_width
, _prev_width
;
145 int _max_height
, _prev_height
;
147 bool _unstable_size
, _fractional_size
;
149 void InspectChar(const wchar_t c
)
151 wchar_t wz
[2] = { c
, 0};
152 wxCoord width
= 0, height
= 0, descent
= 0;
153 _dc
.GetTextExtent(wz
, &width
, &height
, &descent
);
155 if (_max_width
< width
) _max_width
= width
;
156 if (_max_height
< height
) _max_height
= height
;
157 if (_max_descent
< descent
) _max_descent
= descent
;
159 if ( _prev_width
!= width
) {
161 _unstable_size
= true;
164 if ( _prev_height
!= height
) {
165 if (_prev_height
!=-1) _unstable_size
= true;
166 _prev_height
= height
;
170 void DetectFractionalSize(const wchar_t *chars
)
172 // If font is non-monospaced there is no sense to detect if widths are fractional
173 if (_unstable_size
) return;
174 _fractional_size
= _dc
.GetTextExtent(chars
).GetWidth() != (int)(_max_width
* wcslen(chars
));
178 FontSizeInspector(wxFont
& font
)
179 : _bitmap(48, 48, wxBITMAP_SCREEN_DEPTH
),
180 _max_width(4), _prev_width(-1),
181 _max_height(6), _prev_height(-1),
182 _unstable_size(false), _fractional_size(false)
184 _dc
.SelectObject(_bitmap
);
188 void InspectChars(const wchar_t *chars
)
190 for(const wchar_t *s
= chars
; *s
; ++s
)
192 #if defined(__WXOSX__)
193 // There are font rendering artifacts on MacOS if buffering is enabled and font size differs from 10, 15, 20;
194 // E.g. if font size = 13, one char in a string has width 9px (GetTextExtent returns 9), but total string width
195 // is less than N*9px, because internally one char could have fractional width.
196 // We need to disable buffering for certain font sizes as done for non-monospaced ("unstable size") fonts.
197 DetectFractionalSize(chars
);
201 bool IsUnstableSize() const { return _unstable_size
; }
202 bool IsFractionalSize() const { return _fractional_size
; }
203 int GetMaxWidth() const { return _max_width
; }
204 int GetMaxHeight() const { return _max_height
; }
205 int GetMaxDescent() const { return _max_descent
; }
210 void ConsolePaintContext::SetFont(wxFont font
)
212 FontSizeInspector
fsi(font
);
213 fsi
.InspectChars(L
" 1234567890-=!@#$%^&*()_+qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP{}ASDFGHJKL:\"ZXCVBNM<>?");
214 //fsi.InspectChars(L"QWERTYUIOPASDFGHJKL");
216 bool is_unstable
= fsi
.IsUnstableSize();
217 bool is_fractional
= fsi
.IsFractionalSize();
218 _font_width
= fsi
.GetMaxWidth();
219 _font_height
= fsi
.GetMaxHeight();
220 _font_descent
= fsi
.GetMaxDescent();
221 //font_height+= _font_height/4;
223 _font_thickness
= (_font_width
> 8) ? _font_width
/ 8 : 1;
224 switch (font
.GetWeight()) {
225 case wxFONTWEIGHT_LIGHT
:
226 if (_font_thickness
> 1) {
231 case wxFONTWEIGHT_BOLD
:
235 case wxFONTWEIGHT_NORMAL
:
240 fprintf(stderr
, "Font %u x %u . %u: '%ls' - %s\n", _font_width
, _font_height
, _font_thickness
,
241 static_cast<const wchar_t*>(font
.GetFaceName().wc_str()),
242 font
.IsFixedWidth() ?
244 "monospaced unstable" :
246 "monospaced stable (fractional)" :
247 "monospaced stable (integer)")) :
252 _custom_draw_enabled
= stat(InMyConfig("nocustomdraw").c_str(), &s
) != 0;
253 _buffered_paint
= false;
255 if (font
.IsFixedWidth() && !is_unstable
&& !is_fractional
) {
256 if (stat(InMyConfig("nobuffering").c_str(), &s
) != 0)
257 _buffered_paint
= true;
261 _fonts
.push_back(font
);
264 void ConsolePaintContext::ShowFontDialog()
267 if (!_fonts
.empty()) {
268 font
= _fonts
.front();
269 if (!ChooseFontAndSaveToSettings(_window
, font
))
273 InitializeFont(_window
, font
);
278 uint8_t ConsolePaintContext::CharFitTest(wxPaintDC
&dc
, const wchar_t *wcz
)
281 const bool cacheable
= (size_t(wcz
[0]) <= _char_fit_cache
.checked
.size() && wcz
[1] == 0);
282 if (cacheable
&& _char_fit_cache
.checked
[ size_t(wcz
[0]) - 1 ]) {
283 return _char_fit_cache
.result
[ size_t(wcz
[0]) - 1 ];
286 uint8_t font_index
= 0;
288 wxCoord w
, h
= _font_height
, d
= _font_descent
;
289 dc
.GetTextExtent(_cft_tmp
, &w
, &h
, &d
);
290 for (uint8_t try_index
= 1; try_index
!= 0xff && (unsigned)h
> _font_height
+ std::max(0, int(d
) - int(_font_descent
)); ++try_index
) {
292 if (try_index
>= _fonts
.size()) {
293 wxFont smallest
= _fonts
.back();
294 wxSize px_size
= smallest
.GetPixelSize();
295 if (px_size
.GetHeight() <= 4) {
298 px_size
.SetHeight(px_size
.GetHeight() - 1);
300 smallest
.SetPixelSize(px_size
);
301 _fonts
.emplace_back(smallest
);
303 assert(try_index
< _fonts
.size());
304 dc
.SetFont(_fonts
[try_index
]);
305 dc
.GetTextExtent(_cft_tmp
, &w
, &h
, &d
);
306 font_index
= try_index
;
308 if (font_index
!= 0) {
309 // fprintf(stderr, "Changed[%d] point size = %u -> %u for '%ls'\n",
310 // font_index, _fonts[0].GetPointSize(), _fonts[font_index].GetPointSize(), wcz);
315 _char_fit_cache
.result
[ size_t(wcz
[0]) - 1 ] = font_index
;
316 _char_fit_cache
.checked
[ size_t(wcz
[0]) - 1 ] = true;
327 void ConsolePaintContext::ApplyFont(wxPaintDC
&dc
, uint8_t index
)
329 if (index
< _fonts
.size())
330 dc
.SetFont(_fonts
[index
]);
333 void ConsolePaintContext::OnPaint(SMALL_RECT
*qedit
)
335 wxPaintDC
dc(_window
);
336 #if wxUSE_GRAPHICS_CONTEXT
337 wxGraphicsContext
* gctx
= dc
.GetGraphicsContext();
340 gctx
->SetInterpolationQuality(wxINTERPOLATION_FAST
);
341 gctx
->SetAntialiasMode(wxANTIALIAS_NONE
);
343 gctx
->SetInterpolationQuality(wxINTERPOLATION_DEFAULT
);
344 gctx
->SetAntialiasMode(wxANTIALIAS_DEFAULT
);
348 unsigned int cw
, ch
; g_winport_con_out
->GetSize(cw
, ch
);
349 if (cw
> MAXSHORT
) cw
= MAXSHORT
;
350 if (ch
> MAXSHORT
) ch
= MAXSHORT
;
352 wxRegion rgn
= _window
->GetUpdateRegion();
353 wxRect box
= rgn
.GetBox();
354 SMALL_RECT area
= {SHORT(box
.GetLeft() / _font_width
), SHORT(box
.GetTop() / _font_height
),
355 SHORT(box
.GetRight() / _font_width
), SHORT(box
.GetBottom() / _font_height
)};
357 if (area
.Left
< 0 ) area
.Left
= 0;
358 if (area
.Top
< 0 ) area
.Top
= 0;
359 if ((unsigned)area
.Right
>= cw
) area
.Right
= cw
- 1;
360 if ((unsigned)area
.Bottom
>= ch
) area
.Bottom
= ch
- 1;
361 if (area
.Right
< area
.Left
|| area
.Bottom
< area
.Top
) return;
367 _cursor_props
.Update();
369 ConsolePainter
painter(this, dc
, _buffer
, _cursor_props
);
370 for (unsigned int cy
= (unsigned)area
.Top
; cy
<= (unsigned)area
.Bottom
; ++cy
) {
371 wxRegionContain lc
= rgn
.Contains(0, cy
* _font_height
, cw
* _font_width
, _font_height
);
373 if (lc
== wxOutRegion
) {
377 const CHAR_INFO
*line
;
379 // dont keep console output locked for a long time to avoid output slowdown
380 IConsoleOutput::DirectLineAccess
dla(g_winport_con_out
, cy
);
382 unsigned int cur_cw
= line
? dla
.Width() : 0;
384 memcpy(&_line
[0], line
, cur_cw
* sizeof(*line
));
385 memset(&_line
[cur_cw
], 0, (cw
- cur_cw
) * sizeof(*line
));
387 memcpy(&_line
[0], line
, cw
* sizeof(*line
));
392 painter
.LineBegin(cy
);
393 wchar_t tmp_wcz
[2] = {0, 0};
394 DWORD64 attributes
= line
->Attributes
;
395 const unsigned int cx_begin
= (area
.Left
> 0 && !line
[area
.Left
].Char
.UnicodeChar
) ? area
.Left
- 1 : area
.Left
;
396 const unsigned int cx_end
= std::min(cw
, (unsigned)area
.Right
+ 1);
397 for (unsigned int cx
= cx_begin
; cx
< cx_end
; ++cx
) {
398 if (!line
[cx
].Char
.UnicodeChar
) {
399 painter
.LineFlush(cx
+ 1);
403 if (UNLIKELY(CI_USING_COMPOSITE_CHAR(line
[cx
]))) {
404 pwcz
= WINPORT(CompositeCharLookup
)(line
[cx
].Char
.UnicodeChar
);
406 tmp_wcz
[0] = line
[cx
].Char
.UnicodeChar
? wchar_t(line
[cx
].Char
.UnicodeChar
) : L
' ';
410 attributes
= line
[cx
].Attributes
;
411 if (qedit
&& cx
>= (unsigned)qedit
->Left
&& cx
<= (unsigned)qedit
->Right
412 && cy
>= (unsigned)qedit
->Top
&& cy
<= (unsigned)qedit
->Bottom
) {
413 attributes
^= COLOR_ATTRIBUTES
;
414 if (attributes
& FOREGROUND_TRUECOLOR
) {
415 attributes
^= 0x000000ffffff0000;
417 if (attributes
& BACKGROUND_TRUECOLOR
) {
418 attributes
^= 0xffffff0000000000;
421 const int nx
= (cx
+ 1 < cw
&& !line
[cx
+ 1].Char
.UnicodeChar
) ? 2 : 1;
422 painter
.NextChar(cx
, attributes
, pwcz
, nx
);
424 painter
.LineFlush(area
.Right
+ 1);
429 void ConsolePaintContext::RefreshArea( const SMALL_RECT
&area
)
432 rc
.SetLeft(((int)area
.Left
) * _font_width
);
433 rc
.SetRight(((int)area
.Right
) * _font_width
+ _font_width
- 1);
434 rc
.SetTop(((int)area
.Top
) * _font_height
);
435 rc
.SetBottom(((int)area
.Bottom
) * _font_height
+ _font_height
- 1);
436 _window
->Refresh(false, &rc
);
440 void ConsolePaintContext::BlinkCursor()
442 if (_cursor_props
.Blink()) {
444 _cursor_props
.pos
.X
, _cursor_props
.pos
.Y
,
445 _cursor_props
.pos
.X
, _cursor_props
.pos
.Y
448 if (g_winport_con_out
->Read(ci
, _cursor_props
.pos
)) {
449 if (!ci
.Char
.UnicodeChar
&& area
.Left
> 0) {
451 } else if (CI_FULL_WIDTH_CHAR(ci
)) {
459 void ConsolePaintContext::SetSharp(bool sharp
)
461 if (_sharp
!= sharp
) {
467 bool ConsolePaintContext::IsSharpSupported()
469 #if wxUSE_GRAPHICS_CONTEXT
476 wxBrush
&ConsolePaintContext::GetBrush(const WinPortRGB
&clr
)
478 auto it
= _color2brush
.find(clr
);
479 if (it
!= _color2brush
.end()) {
483 return _color2brush
.emplace(clr
, wxColour(clr
.r
, clr
.g
, clr
.b
)).first
->second
;
486 /////////////////////////////
488 bool CursorProps::Blink()
490 bool prev_blink_state
= blink_state
;
491 blink_state
= !blink_state
;
493 return (blink_state
!= prev_blink_state
);
496 void CursorProps::Update()
498 pos
= g_winport_con_out
->GetCursor(height
, visible
);
499 if (prev_pos
.X
!= pos
.X
|| prev_pos
.Y
!= pos
.Y
) {
505 //////////////////////
507 ConsolePainter::ConsolePainter(ConsolePaintContext
*context
, wxPaintDC
&dc
, wxString
&buffer
, CursorProps
&cursor_props
) :
508 _context(context
), _dc(dc
), _buffer(buffer
), _cursor_props(cursor_props
),
509 _start_cx((unsigned int)-1), _start_back_cx((unsigned int)-1), _prev_fit_font_index(0), _prev_underlined(false)
511 _dc
.SetPen(context
->GetTransparentPen());
512 _dc
.SetBackgroundMode(wxPENSTYLE_TRANSPARENT
);
517 void ConsolePainter::SetFillColor(const WinPortRGB
&clr
)
519 if (_brush_clr
.Change(clr
)) {
520 wxBrush
&brush
= _context
->GetBrush(clr
);
522 _dc
.SetBackground(brush
);
526 void ConsolePainter::PrepareBackground(unsigned int cx
, const WinPortRGB
&clr
, unsigned int nx
)
528 const bool cursor_here
= (_cursor_props
.visible
&& _cursor_props
.blink_state
529 && cx
== (unsigned int)_cursor_props
.pos
.X
530 && _start_cy
== (unsigned int)_cursor_props
.pos
.Y
);
532 if (!cursor_here
&& _start_back_cx
!= (unsigned int)-1 && _clr_back
== clr
)
535 FlushBackground(cx
+ nx
- 1);
543 _start_back_cx
= (unsigned int)-1;
545 const unsigned int x
= cx
* _context
->FontWidth();
546 unsigned int h
= (_context
->FontHeight() * _cursor_props
.height
) / 100;
548 unsigned int fill_height
= _context
->FontHeight() - h
;
549 if (fill_height
> _context
->FontHeight()) fill_height
= _context
->FontHeight();
550 WinPortRGB
clr_xored(clr
.r
^ 0xff, clr
.g
^ 0xff, clr
.b
^ 0xff);
551 SetFillColor(clr_xored
);
552 _dc
.DrawRectangle(x
, _start_y
+ fill_height
, _context
->FontWidth() * nx
, h
);
556 _dc
.DrawRectangle(x
, _start_y
, _context
->FontWidth() * nx
, fill_height
);
561 void ConsolePainter::FlushBackground(unsigned int cx_end
)
563 if (_start_back_cx
!= ((unsigned int)-1)) {
564 SetFillColor(_clr_back
);
565 _dc
.DrawRectangle(_start_back_cx
* _context
->FontWidth(), _start_y
,
566 (cx_end
- _start_back_cx
) * _context
->FontWidth(), _context
->FontHeight());
567 _start_back_cx
= ((unsigned int)-1);
571 void ConsolePainter::FlushText(unsigned int cx_end
)
573 if (!_buffer
.empty()) {
574 _dc
.SetTextForeground(wxColour(_clr_text
.r
, _clr_text
.g
, _clr_text
.b
));
575 _dc
.DrawText(_buffer
, _start_cx
* _context
->FontWidth(), _start_y
);
578 FlushUnderline(cx_end
);
579 _start_cx
= (unsigned int)-1;
580 _prev_fit_font_index
= 0;
583 void ConsolePainter::FlushUnderline(unsigned int cx_end
)
585 if (_prev_underlined
) {
586 _dc
.SetPen(wxColour(_clr_text
.r
, _clr_text
.g
, _clr_text
.b
));
587 _dc
.DrawLine(_start_cx
* _context
->FontWidth(), _start_y
+ _context
->FontHeight() - 1,
588 cx_end
* _context
->FontWidth(), _start_y
+ _context
->FontHeight() - 1);
589 _dc
.SetPen(_context
->GetTransparentPen());
590 _prev_underlined
= false;
594 static inline unsigned char CalcFadeColor(unsigned char bg
, unsigned char fg
)
596 unsigned short out
= fg
;
600 return (out
> 0xff) ? 0xff : (unsigned char)out
;
603 static inline unsigned char CalcExtraFadeColor(unsigned char bg
, unsigned char fg
)
605 unsigned short out
= bg
;
608 return (out
> 0xff) ? 0xff : (unsigned char)out
;
611 // #define DEBUG_FADED_EDGES
613 struct WXCustomDrawCharPainter
: WXCustomDrawChar::Painter
615 ConsolePainter
&_painter
;
616 const WinPortRGB
&_clr_text
;
617 const WinPortRGB
&_clr_back
;
619 inline WXCustomDrawCharPainter(ConsolePainter
&painter
, const WinPortRGB
&clr_text
, const WinPortRGB
&clr_back
)
620 : _painter(painter
), _clr_text(clr_text
), _clr_back(clr_back
)
622 fw
= (wxCoord
)_painter
._context
->FontWidth();
623 fh
= (wxCoord
)_painter
._context
->FontHeight(),
624 thickness
= (wxCoord
)_painter
._context
->FontThickness();
625 _painter
.SetFillColor(clr_text
);
628 inline bool MayDrawFadedEdgesImpl()
630 return (fw
> 7 && fh
> 7 && !_painter
._context
->IsSharp());
633 inline void SetColorFadedImpl()
635 #ifndef DEBUG_FADED_EDGES
636 WinPortRGB
clr_fade(CalcFadeColor(_clr_back
.r
, _clr_text
.r
),
637 CalcFadeColor(_clr_back
.g
, _clr_text
.g
), CalcFadeColor(_clr_back
.b
, _clr_text
.b
));
639 WinPortRGB
clr_fade(0xff, 0, 0);
641 _painter
.SetFillColor(clr_fade
);
644 inline void SetColorExtraFadedImpl()
646 #ifndef DEBUG_FADED_EDGES
647 WinPortRGB
clr_fade(CalcExtraFadeColor(_clr_back
.r
, _clr_text
.r
),
648 CalcExtraFadeColor(_clr_back
.g
, _clr_text
.g
), CalcExtraFadeColor(_clr_back
.b
, _clr_text
.b
));
650 WinPortRGB
clr_fade(0, 0xff, 0);
652 _painter
.SetFillColor(clr_fade
);
656 inline void FillRectangleImpl(wxCoord left
, wxCoord top
, wxCoord right
, wxCoord bottom
)
658 _painter
._dc
.DrawRectangle(left
, top
, right
+ 1 - left
, bottom
+ 1 - top
);
662 // this code little bit wacky just to avoid virtual methods overhead
663 bool WXCustomDrawChar::Painter::MayDrawFadedEdges()
665 return ((WXCustomDrawCharPainter
*)this)->MayDrawFadedEdgesImpl();
668 void WXCustomDrawChar::Painter::SetColorFaded()
670 ((WXCustomDrawCharPainter
*)this)->SetColorFadedImpl();
673 void WXCustomDrawChar::Painter::SetColorExtraFaded()
675 ((WXCustomDrawCharPainter
*)this)->SetColorExtraFadedImpl();
678 void WXCustomDrawChar::Painter::FillRectangle(wxCoord left
, wxCoord top
, wxCoord right
, wxCoord bottom
)
680 ((WXCustomDrawCharPainter
*)this)->FillRectangleImpl(left
, top
, right
, bottom
);
683 void WXCustomDrawChar::Painter::FillPixel(wxCoord left
, wxCoord top
)
685 ((WXCustomDrawCharPainter
*)this)->FillRectangleImpl(left
, top
, left
, top
);
689 void ConsolePainter::NextChar(unsigned int cx
, DWORD64 attributes
, const wchar_t *wcz
, unsigned int nx
)
691 WXCustomDrawChar::DrawT custom_draw
= nullptr;
693 if (!wcz
[0] || (!wcz
[1] && (wcz
[0] == L
' ' || !WCHAR_IS_VALID(wcz
[0]) || (_context
->IsCustomDrawEnabled()
694 && (custom_draw
= WXCustomDrawChar::Get(wcz
[0])) != nullptr)))) {
695 if (!_buffer
.empty())
696 FlushBackground(cx
+ nx
- 1);
697 FlushText(cx
+ nx
- 1);
700 const WinPortRGB
&clr_back
= ConsoleBackground2RGB(attributes
);
701 PrepareBackground(cx
, clr_back
, nx
);
703 if (!wcz
[0] || (!wcz
[1] && (wcz
[0] == L
' ' || !WCHAR_IS_VALID(wcz
[0])))) {
707 const WinPortRGB
&clr_text
= ConsoleForeground2RGB(attributes
);
710 FlushBackground(cx
+ nx
);
711 WXCustomDrawCharPainter
cdp(*this, clr_text
, clr_back
);
712 custom_draw(cdp
, _start_y
, cx
);
714 _start_cx
= (unsigned int)-1;
715 _prev_fit_font_index
= 0;
719 uint8_t fit_font_index
= _context
->CharFitTest(_dc
, wcz
);
720 const bool underlined
= (attributes
& COMMON_LVB_UNDERSCORE
) != 0;
722 if (fit_font_index
== _prev_fit_font_index
&& _prev_underlined
== underlined
723 && _start_cx
!= (unsigned int)-1 && _clr_text
== clr_text
&& _context
->IsPaintBuffered()) {
728 FlushBackground(cx
+ nx
);
731 _prev_fit_font_index
= fit_font_index
;
732 _prev_underlined
= underlined
;
736 _clr_text
= clr_text
;
738 if (fit_font_index
!= 0 && fit_font_index
!= 0xff) {
739 _context
->ApplyFont(_dc
, fit_font_index
);
741 _context
->ApplyFont(_dc
);