4#include "Stroika/Frameworks/StroikaPreComp.h"
13#include "Stroika/Foundation/Execution/Throw.h"
21using namespace Stroika::Frameworks;
22using namespace Stroika::Frameworks::Led;
24#if qStroika_Foundation_Common_Platform_Windows
32#if qStroika_Foundation_Common_Platform_Windows
34#define qUseUniscribeToImage qUniscribeAvailableWithSDK
35#define qUseFakeTTGetWPlacementToImage 1
36#define qUseGetCharPlacementToImage 1
39#if qUseUniscribeToImage
46#ifndef qDebugFontDetails
47#define qDebugFontDetails qStroika_Foundation_Debug_AssertionsChecked&& qStroika_FeatureSupported_XWindows
51#if qUniscribeAvailableWithSDK
52#define qTryScriptToCPX 0
55#ifndef qTryToOptimizeLongUNISCRIBEScriptOutCalls
56#define qTryToOptimizeLongUNISCRIBEScriptOutCalls 1
61#if qStroika_Foundation_Common_Platform_Windows
66#ifndef qUseDIBSectionForOffscreenBitmap
67#define qUseDIBSectionForOffscreenBitmap 1
71#if qStroika_Foundation_Common_Platform_Windows
72inline bool operator== (PALETTEENTRY lhs, COLORREF rhs)
74 return RGB (lhs.peRed, lhs.peGreen, lhs.peBlue) == rhs;
78#if !qHaveWindowsDIBDefined
84#if qStroika_Foundation_Common_Platform_Windows
86const bool kRunning32BitGDI =
true;
88const bool kRunning32BitGDI = ((::GetVersion () & 0x80000000) == 0);
92#if qStroika_Foundation_Common_Platform_Windows
93inline void Win32_GetTextExtentExPoint (HDC hdc,
const Led_tChar* str,
size_t nChars,
int maxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize)
95 Require (nChars <
static_cast<size_t> (numeric_limits<int>::max ()));
96 Verify (::GetTextExtentExPointW (hdc, str,
static_cast<int> (nChars), maxExtent, lpnFit, alpDx, lpSize));
98inline void Win32_GetTextExtentPoint (HDC hdc,
const Led_tChar* str,
int nChars, LPSIZE lpSize)
100 Verify (::GetTextExtentPointW (hdc, str, nChars, lpSize));
102inline void Win32_TextOut (HDC hdc,
int xStart,
int yStart,
const Led_tChar* str,
int nChars)
104 Verify (::TextOutW (hdc, xStart, yStart, str, nChars));
108#if qStroika_Foundation_Common_Platform_Windows && qUseUniscribeToImage
110const size_t kMaxUNISCRIBECharacters = 30000;
118 : fDLL (::LoadLibrary (_T (
"Usp10.dll")))
119 , fScriptItemize (nullptr)
120 , fScriptShape (nullptr)
121 , fScriptPlace (nullptr)
122 , fScriptStringAnalyse (nullptr)
123 , fScriptStringOut (nullptr)
124 , fScriptStringFree (nullptr)
125 , fScriptStringGetLogicalWidths (nullptr)
126 , fScriptString_pcOutChars (nullptr)
127 , fScriptString_pSize (nullptr)
128 , fScriptStringCPtoX (nullptr)
130 if (fDLL !=
nullptr) {
131 fScriptItemize = (HRESULT (WINAPI*) (
const WCHAR*, int, int,
const SCRIPT_CONTROL*,
const SCRIPT_STATE*, SCRIPT_ITEM*,
int*)) (
132 ::GetProcAddress (fDLL,
"ScriptItemize"));
133 fScriptShape = (HRESULT (WINAPI*) (HDC, SCRIPT_CACHE*,
const WCHAR*, int, int, SCRIPT_ANALYSIS*, WORD*, WORD*, SCRIPT_VISATTR*,
134 int*)) (::GetProcAddress (fDLL,
"ScriptShape"));
135 fScriptPlace = (HRESULT (WINAPI*) (HDC, SCRIPT_CACHE*,
const WORD*, int,
const SCRIPT_VISATTR*, SCRIPT_ANALYSIS*,
int*,
136 GOFFSET*, ABC*)) (::GetProcAddress (fDLL,
"ScriptPlace"));
137 fScriptStringAnalyse =
138 (HRESULT (WINAPI*) (HDC,
const void*, int, int, int, DWORD, int, SCRIPT_CONTROL*, SCRIPT_STATE*,
const int*, SCRIPT_TABDEF*,
139 const BYTE*, SCRIPT_STRING_ANALYSIS*)) (::GetProcAddress (fDLL,
"ScriptStringAnalyse"));
140 fScriptStringOut = (HRESULT (WINAPI*) (SCRIPT_STRING_ANALYSIS, int, int, UINT,
const RECT*, int, int, BOOL)) (
141 ::GetProcAddress (fDLL,
"ScriptStringOut"));
142 fScriptStringFree = (HRESULT (WINAPI*) (SCRIPT_STRING_ANALYSIS*)) (::GetProcAddress (fDLL,
"ScriptStringFree"));
143 fScriptStringGetLogicalWidths =
144 (HRESULT (WINAPI*) (SCRIPT_STRING_ANALYSIS,
int*)) (::GetProcAddress (fDLL,
"ScriptStringGetLogicalWidths"));
145 fScriptString_pcOutChars = (
const int*(WINAPI*)(SCRIPT_STRING_ANALYSIS)) (::GetProcAddress (fDLL,
"ScriptString_pcOutChars"));
146 fScriptString_pSize = (
const SIZE*(WINAPI*)(SCRIPT_STRING_ANALYSIS)) (::GetProcAddress (fDLL,
"ScriptString_pSize"));
148 (HRESULT (WINAPI*) (SCRIPT_STRING_ANALYSIS, int, BOOL,
int*)) (::GetProcAddress (fDLL,
"ScriptStringCPtoX"));
153 if (fDLL !=
nullptr) {
154 Verify (::FreeLibrary (fDLL));
158 nonvirtual
bool IsAvail ()
const
160 return fDLL !=
nullptr;
163 HRESULT WINAPI ScriptItemize (
const WCHAR* pwcInChars,
int cInChars,
int cMaxItems,
const SCRIPT_CONTROL* psControl,
164 const SCRIPT_STATE* psState, SCRIPT_ITEM* pItems,
int* pcItems)
166 if (fScriptItemize ==
nullptr) {
169 return (*fScriptItemize) (pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, pcItems);
172 HRESULT WINAPI ScriptShape (HDC hdc, SCRIPT_CACHE* psc,
const WCHAR* pwcChars,
int cChars,
int cMaxGlyphs, SCRIPT_ANALYSIS* psa,
173 WORD* pwOutGlyphs, WORD* pwLogClust, SCRIPT_VISATTR* psva,
int* pcGlyphs)
175 if (fScriptShape ==
nullptr) {
178 return (*fScriptShape) (hdc, psc, pwcChars, cChars, cMaxGlyphs, psa, pwOutGlyphs, pwLogClust, psva, pcGlyphs);
181 HRESULT WINAPI ScriptPlace (HDC hdc, SCRIPT_CACHE* psc,
const WORD* pwGlyphs,
int cGlyphs,
const SCRIPT_VISATTR* psva,
182 SCRIPT_ANALYSIS* psa,
int* piAdvance, GOFFSET* pGoffset, ABC* pABC)
184 if (fScriptPlace ==
nullptr) {
187 return (*fScriptPlace) (hdc, psc, pwGlyphs, cGlyphs, psva, psa, piAdvance, pGoffset, pABC);
190 HRESULT WINAPI ScriptStringAnalyse (HDC hdc,
const void* pString,
int cString,
int cGlyphs,
int iCharset, DWORD dwFlags,
int iReqWidth,
191 SCRIPT_CONTROL* psControl, SCRIPT_STATE* psState,
const int* piDx, SCRIPT_TABDEF* pTabdef,
192 const BYTE* pbInClass, SCRIPT_STRING_ANALYSIS* pssa)
194 if (fScriptStringAnalyse ==
nullptr) {
197 return (*fScriptStringAnalyse) (hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth, psControl, psState, piDx, pTabdef, pbInClass, pssa);
200 HRESULT WINAPI ScriptStringOut (SCRIPT_STRING_ANALYSIS ssa,
int iX,
int iY, UINT uOptions,
const RECT* prc,
int iMinSel,
int iMaxSel, BOOL fDisabled)
202 if (fScriptStringOut ==
nullptr) {
205 return (*fScriptStringOut) (ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
208 HRESULT WINAPI ScriptStringFree (SCRIPT_STRING_ANALYSIS* pssa)
210 if (fScriptStringFree ==
nullptr) {
213 return (*fScriptStringFree) (pssa);
216 HRESULT WINAPI ScriptStringGetLogicalWidths (SCRIPT_STRING_ANALYSIS ssa,
int* piDx)
218 if (fScriptStringGetLogicalWidths ==
nullptr) {
221 return (*fScriptStringGetLogicalWidths) (ssa, piDx);
224 const int* WINAPI ScriptString_pcOutChars (SCRIPT_STRING_ANALYSIS ssa)
226 if (fScriptString_pcOutChars ==
nullptr) {
229 return (*fScriptString_pcOutChars) (ssa);
232 const SIZE* WINAPI ScriptString_pSize (SCRIPT_STRING_ANALYSIS ssa)
234 if (fScriptString_pSize ==
nullptr) {
237 return (*fScriptString_pSize) (ssa);
240 HRESULT WINAPI ScriptStringCPtoX (SCRIPT_STRING_ANALYSIS ssa,
int icp, BOOL fTrailing,
int* pX)
242 if (fScriptStringCPtoX ==
nullptr) {
245 return (*fScriptStringCPtoX) (ssa, icp, fTrailing, pX);
249 HRESULT (WINAPI* fScriptItemize)
250 (
const WCHAR*, int, int,
const SCRIPT_CONTROL*,
const SCRIPT_STATE*, SCRIPT_ITEM*,
int*);
251 HRESULT (WINAPI* fScriptShape)
252 (HDC, SCRIPT_CACHE*,
const WCHAR*, int, int, SCRIPT_ANALYSIS*, WORD*, WORD*, SCRIPT_VISATTR*,
int*);
253 HRESULT (WINAPI* fScriptPlace)
254 (HDC, SCRIPT_CACHE*,
const WORD*, int,
const SCRIPT_VISATTR*, SCRIPT_ANALYSIS*,
int*, GOFFSET*, ABC*);
255 HRESULT (WINAPI* fScriptStringAnalyse)
256 (HDC,
const void*, int, int, int, DWORD, int, SCRIPT_CONTROL*, SCRIPT_STATE*,
const int*, SCRIPT_TABDEF*,
const BYTE*, SCRIPT_STRING_ANALYSIS*);
257 HRESULT (WINAPI* fScriptStringOut)
258 (SCRIPT_STRING_ANALYSIS, int, int, UINT,
const RECT*, int, int, BOOL);
259 HRESULT (WINAPI* fScriptStringFree)
260 (SCRIPT_STRING_ANALYSIS*);
261 HRESULT (WINAPI* fScriptStringGetLogicalWidths)
262 (SCRIPT_STRING_ANALYSIS,
int*);
263 const int*(WINAPI* fScriptString_pcOutChars) (SCRIPT_STRING_ANALYSIS);
264 const SIZE*(WINAPI* fScriptString_pSize) (SCRIPT_STRING_ANALYSIS);
265 HRESULT (WINAPI* fScriptStringCPtoX)
266 (SCRIPT_STRING_ANALYSIS, int, BOOL,
int*);
268static UniscribeDLL sUniscribeDLL;
272 inline bool IS_WIN30_DIB (
const Led_DIB* dib)
276 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
277 return Led_ByteSwapFromWindows (hdr.biSize) ==
sizeof (BITMAPINFOHEADER);
279 inline size_t DIBNumColors (
const Led_DIB* dib)
283 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
290 if (IS_WIN30_DIB (dib)) {
291 unsigned long clrUsed = Led_ByteSwapFromWindows (hdr.biClrUsed);
300 unsigned short bitCount = IS_WIN30_DIB (dib) ? Led_ByteSwapFromWindows (hdr.biBitCount)
301 : Led_ByteSwapFromWindows (((const BITMAPCOREHEADER*)dib)->bcBitCount);
317#if qStroika_Foundation_Common_Platform_Windows
320 inline RGBQUAD mkRGBQuad (COLORREF c)
323 r.rgbBlue = GetBValue (c);
324 r.rgbGreen = GetGValue (c);
325 r.rgbRed = GetRValue (c);
329 inline void MaybeAddColorRefToTable_ (RGBQUAD colorTable[256],
size_t* iP, COLORREF c)
331 Assert (
sizeof (RGBQUAD) ==
sizeof (COLORREF));
332 COLORREF* ct =
reinterpret_cast<COLORREF*
> (colorTable);
333 if (find (ct, ct + *iP, c) == ct + *iP and c != RGB (255, 255, 255)) {
334 colorTable[*iP] = mkRGBQuad (c);
339 void CreateStandardColorTable (RGBQUAD colorTable[256], COLORREF c1 = RGB (0, 0, 0), COLORREF c2 = RGB (0, 0, 0),
340 COLORREF c3 = RGB (0, 0, 0), COLORREF c4 = RGB (0, 0, 0))
345 (void)::memset (colorTable, 0,
sizeof (RGBQUAD) * 256);
347 const BYTE kColorSpecVals[] = {0, 32, 64, 128, 192, 255};
348 const size_t kColorSpecValCnt =
sizeof (kColorSpecVals) /
sizeof (kColorSpecVals[0]);
359 for (; i < 256; ++i) {
360 colorTable[i].rgbRed = kColorSpecVals[redIdx];
361 colorTable[i].rgbGreen = kColorSpecVals[greenIdx];
362 colorTable[i].rgbBlue = kColorSpecVals[blueIdx];
364 if (blueIdx >= kColorSpecValCnt) {
367 if (greenIdx >= kColorSpecValCnt) {
370 if (redIdx >= kColorSpecValCnt) {
371 Assert (i == kColorSpecValCnt * kColorSpecValCnt * kColorSpecValCnt - 1);
384 size_t nColorsLeft = 255 - i;
385 Assert (nColorsLeft == 41);
389 MaybeAddColorRefToTable_ (colorTable, &i, c1);
390 MaybeAddColorRefToTable_ (colorTable, &i, c2);
391 MaybeAddColorRefToTable_ (colorTable, &i, c3);
392 MaybeAddColorRefToTable_ (colorTable, &i, c4);
394 nColorsLeft = 255 - i;
395 Assert (nColorsLeft > 0);
397 size_t aveSpace = 255 / nColorsLeft;
399 BYTE startAt =
static_cast<BYTE
> (aveSpace);
400 while (i < 254 and startAt < 255) {
401 COLORREF c = RGB (startAt, startAt, startAt);
402 Assert (
sizeof (RGBQUAD) ==
sizeof (COLORREF));
403 COLORREF* ct =
reinterpret_cast<COLORREF*
> (colorTable);
404 if (find (ct, ct + i, c) == ct + i) {
405 colorTable[i] = mkRGBQuad (c);
409 startAt +=
static_cast<BYTE
> (aveSpace);
412 Assert (nColorsLeft == 255 - i);
414 Assert (nColorsLeft < 5);
415 Assert (nColorsLeft >= 1);
417 for (; i <= 255; ++i) {
418 colorTable[i].rgbRed =
static_cast<BYTE
> (i);
419 colorTable[i].rgbGreen =
static_cast<BYTE
> (i);
420 colorTable[i].rgbBlue =
static_cast<BYTE
> (i);
424 HPALETTE CreatePaletteForColorTable (
const RGBQUAD colorTable[256])
430 LPLOGPALETTE lplgPal =
reinterpret_cast<LPLOGPALETTE
> (
static_cast<char*
> (palBuf));
432 lplgPal->palVersion = 0x300;
433 lplgPal->palNumEntries = 256;
435 for (
size_t i = 0; i <= 255; ++i) {
436 lplgPal->palPalEntry[i].peRed = colorTable[i].rgbRed;
437 lplgPal->palPalEntry[i].peGreen = colorTable[i].rgbGreen;
438 lplgPal->palPalEntry[i].peBlue = colorTable[i].rgbBlue;
439 lplgPal->palPalEntry[i].peFlags = 0;
441 return ::CreatePalette (lplgPal);
444 HPALETTE CreateStandardPalette (COLORREF c1, COLORREF c2, COLORREF c3, COLORREF c4)
446 RGBQUAD colorTable[256];
447 CreateStandardColorTable (colorTable, c1, c2, c3, c4);
448 return CreatePaletteForColorTable (colorTable);
451 HBITMAP Create8BitDIBSection (HDC refDC, DWORD dwX, DWORD dwY,
const RGBQUAD* colorTable =
nullptr, LPBYTE* ppBits =
nullptr)
453 LPBYTE ignored =
nullptr;
454 if (ppBits ==
nullptr) {
458 const WORD wBits = 8;
460 RGBQUAD colorTableBuf[256];
461 if (colorTable ==
nullptr) {
462 CreateStandardColorTable (colorTableBuf);
463 colorTable = colorTableBuf;
467 size_t nInfoSize =
sizeof (BITMAPINFOHEADER) +
sizeof (RGBQUAD) * (1 << wBits);
469 LPBITMAPINFO pbmi =
reinterpret_cast<LPBITMAPINFO
> (
static_cast<char*
> (bmiBuf));
470 (void)::memset (pbmi, 0, nInfoSize);
471 pbmi->bmiHeader.biSize =
sizeof (BITMAPINFOHEADER);
472 pbmi->bmiHeader.biWidth = dwX;
473 pbmi->bmiHeader.biHeight = dwY;
474 pbmi->bmiHeader.biPlanes = 1;
475 pbmi->bmiHeader.biBitCount = wBits;
476 pbmi->bmiHeader.biCompression = BI_RGB;
478 for (
int i = 0; i < 256; ++i) {
479 pbmi->bmiColors[i].rgbRed = colorTable[i].rgbRed;
480 pbmi->bmiColors[i].rgbGreen = colorTable[i].rgbGreen;
481 pbmi->bmiColors[i].rgbBlue = colorTable[i].rgbBlue;
482 pbmi->bmiColors[i].rgbReserved = 0;
484 pbmi->bmiHeader.biClrUsed = 256;
486 return ::CreateDIBSection (refDC, pbmi, DIB_RGB_COLORS, (
void**)ppBits,
nullptr, 0);
489 HBITMAP Create16BitDIBSection (HDC refDC, DWORD dwX, DWORD dwY)
492 size_t nInfoSize =
sizeof (BITMAPINFOHEADER) + 3 *
sizeof (DWORD);
494 LPBITMAPINFO pbmi =
reinterpret_cast<LPBITMAPINFO
> (
static_cast<char*
> (bmiBuf));
495 (void)::memset (pbmi, 0, nInfoSize);
496 pbmi->bmiHeader.biSize =
sizeof (BITMAPINFOHEADER);
497 pbmi->bmiHeader.biWidth = dwX;
498 pbmi->bmiHeader.biHeight = dwY;
499 pbmi->bmiHeader.biPlanes = 1;
500 pbmi->bmiHeader.biBitCount = 16;
504 LPDWORD pMasks = (LPDWORD)(pbmi->bmiColors);
505 pMasks[0] = 0x00007c00;
506 pMasks[1] = 0x000003e0;
507 pMasks[2] = 0x0000001f;
508 pbmi->bmiHeader.biCompression = BI_BITFIELDS;
511 return ::CreateDIBSection (refDC, pbmi, DIB_RGB_COLORS, (
void**)&pBits,
nullptr, 0);
514 HBITMAP Create32BitDIBSection (HDC refDC, DWORD dwX, DWORD dwY)
517 size_t nInfoSize =
sizeof (BITMAPINFOHEADER) + 3 *
sizeof (DWORD);
519 LPBITMAPINFO pbmi =
reinterpret_cast<LPBITMAPINFO
> (
static_cast<char*
> (bmiBuf));
520 (void)::memset (pbmi, 0, nInfoSize);
521 pbmi->bmiHeader.biSize =
sizeof (BITMAPINFOHEADER);
522 pbmi->bmiHeader.biWidth = dwX;
523 pbmi->bmiHeader.biHeight = dwY;
524 pbmi->bmiHeader.biPlanes = 1;
525 pbmi->bmiHeader.biBitCount = 32;
529 LPDWORD pMasks = (LPDWORD)(pbmi->bmiColors);
530 pMasks[0] = 0x00ff0000;
531 pMasks[1] = 0x0000ff00;
532 pMasks[2] = 0x000000ff;
533 pbmi->bmiHeader.biCompression = BI_BITFIELDS;
536 return ::CreateDIBSection (refDC, pbmi, DIB_RGB_COLORS, (
void**)&pBits,
nullptr, 0);
541#if qStroika_Foundation_Common_Platform_Windows && qUseFakeTTGetWPlacementToImage
542static bool Win9x_Workaround_GetCharPlacementFunction (HDC hdc,
const wchar_t* srcText,
size_t len,
wchar_t* glyphImagesOut);
545#if qStroika_Foundation_Common_Platform_Windows
551BOOL Bitmap::CreateCompatibleBitmap (HDC hdc, DistanceType nWidth, DistanceType nHeight)
553 Assert (m_hObject ==
nullptr);
554 m_hObject = ::CreateCompatibleBitmap (hdc, nWidth, nHeight);
555 fImageSize = Led_Size (nHeight, nWidth);
556 return (m_hObject !=
nullptr);
559BOOL Bitmap::CreateCompatibleDIBSection (HDC hdc, DistanceType nWidth, DistanceType nHeight)
562 Require (m_hObject ==
nullptr);
565 fImageSize = Led_Size (nHeight, nWidth);
567 int deviceDepth = ::GetDeviceCaps (hdc, BITSPIXEL) * ::GetDeviceCaps (hdc, PLANES);
568 if (deviceDepth > 16) {
571 else if (deviceDepth <= 8) {
576 m_hObject = Create8BitDIBSection (hdc, nWidth, nHeight);
579 m_hObject = Create16BitDIBSection (hdc, nWidth, nHeight);
582 m_hObject = Create32BitDIBSection (hdc, nWidth, nHeight);
587 return m_hObject !=
nullptr;
590void Bitmap::LoadBitmap (HINSTANCE hInstance, LPCTSTR lpBitmapName)
592 Require (m_hObject ==
nullptr);
593 m_hObject = ::LoadBitmap (hInstance, lpBitmapName);
597 Verify (::GetObject (m_hObject,
sizeof (BITMAP), (LPVOID)&bm));
598 fImageSize = Led_Size (bm.bmHeight, bm.bmWidth);
612const Color Color::kWhite =
Color (Color::kColorValueMax, Color::kColorValueMax, Color::kColorValueMax);
613const Color Color::kRed =
Color (Color::kColorValueMax, 0, 0);
614const Color Color::kGreen =
Color (0, Color::kColorValueMax / 2, 0);
615const Color Color::kBlue =
Color (0, 0, Color::kColorValueMax);
616const Color Color::kCyan =
Color (0, Color::kColorValueMax, Color::kColorValueMax);
617const Color Color::kMagenta =
Color (Color::kColorValueMax, 0, Color::kColorValueMax);
618const Color Color::kYellow =
Color (Color::kColorValueMax, Color::kColorValueMax, 0);
619const Color Color::kMaroon =
Color (Color::kColorValueMax / 2, 0, 0);
620const Color Color::kOlive =
Color (Color::kColorValueMax / 2, Color::kColorValueMax / 2, 0);
621const Color Color::kNavyBlue =
Color (0, 0, Color::kColorValueMax / 2);
622const Color Color::kPurple =
Color (Color::kColorValueMax / 2, 0, Color::kColorValueMax / 2);
623const Color Color::kTeal =
Color (0, Color::kColorValueMax / 2, Color::kColorValueMax / 2);
624const Color Color::kGray =
Color (Color::kColorValueMax / 2, Color::kColorValueMax / 2, Color::kColorValueMax / 2);
625const Color Color::kSilver =
Color (Color::kColorValueMax * 3 / 4, Color::kColorValueMax * 3 / 4, Color::kColorValueMax * 3 / 4);
626const Color Color::kDarkGreen =
Color (0, (Color::kColorValueMax / 256) * 100, 0);
627const Color Color::kLimeGreen =
Color (0, Color::kColorValueMax, 0);
628const Color Color::kFuchsia = Color::kMagenta;
629const Color Color::kAqua = Color::kCyan;
636#if qStroika_FeatureSupported_XWindows
637string FontSpecification::mkOSRep (
const string& foundry,
const string& family,
const string& weight,
const string& slant,
const string& pointSize)
640 (void)::sprintf (hRes,
"%d", Globals::Get ().GetMainScreenLogPixelsH ());
642 (void)::sprintf (vRes,
"%d", Globals::Get ().GetMainScreenLogPixelsV ());
643 string result =
"-" + foundry +
"-" + family +
"-" + weight +
"-" + slant +
"-*-*-*-" + pointSize +
"-" + hRes +
"-" + vRes +
"-*-*-*-*";
647string FontSpecification::GetOSRep ()
const
649 string foundry =
"*";
650 string weight = fBold ?
"bold" :
"medium";
651 string slant = fItalics ?
"i" :
"r";
652 char pointSize[1024];
653 (void)::sprintf (pointSize,
"%d", GetPointSize () * 10);
654 return mkOSRep (foundry, fFontFamily, weight, slant, pointSize);
657void FontSpecification::SetFromOSRep (
const string& osRep)
663 Tablet::ParseFontName (osRep, &familyName, &fontSize, &fontWeight, &fontSlant);
664 SetFontName (familyName);
665 if (fontSlant ==
"i") {
666 SetStyle_Italic (
true);
668 else if (fontSlant ==
"r") {
669 SetStyle_Italic (
false);
671 if (fontWeight ==
"bold") {
672 SetStyle_Bold (
true);
674 else if (fontWeight ==
"medium") {
675 SetStyle_Bold (
false);
677 int fspPointSize = GetPointSize ();
678 if (::sscanf (fontSize.c_str (),
"%d", &fspPointSize) == 1) {
680 if (fspPointSize < 5) {
683 if (fspPointSize > 100) {
686 SetPointSize (fspPointSize);
695void FontSpecification::SetFontName (
const SDKString& fontName)
697#if qStroika_Foundation_Common_Platform_Windows
698 Characters::CString::Copy (fFontInfo.lfFaceName, Memory::NEltsOf (fFontInfo.lfFaceName), fontName.c_str ());
699 fFontInfo.lfCharSet = DEFAULT_CHARSET;
700#elif qStroika_FeatureSupported_XWindows
701 fFontFamily = fontName;
705#if qStroika_Foundation_Common_Platform_Windows
708 Characters::CString::Copy (fName, Memory::NEltsOf (fName), from);
712void FontSpecification::SetFontNameSpecifier (FontNameSpecifier fontNameSpecifier)
714#if qStroika_Foundation_Common_Platform_Windows
715 Characters::CString::Copy (fFontInfo.lfFaceName, Memory::NEltsOf (fFontInfo.lfFaceName), fontNameSpecifier.fName);
716 fFontInfo.lfCharSet = DEFAULT_CHARSET;
717#elif qStroika_FeatureSupported_XWindows
718 fFontFamily = fontNameSpecifier;
722#if qStroika_Foundation_Common_Platform_Windows
723struct FontSelectionInfo {
724 FontSelectionInfo (BYTE desiredCharset)
725 : fDesiredCharset (desiredCharset)
726 , fUsesBestCharset (false)
728 , fIsANSI_VAR_Font (false)
729 , fIsGoodBackupCharset (false)
730 , fIsFavoriteForCharset (false)
731 , fIsVariablePitch (false)
732 , fStartsWithAt (false)
734 memset (&fBestFont, 0,
sizeof (fBestFont));
736 BYTE fDesiredCharset;
738 bool fUsesBestCharset;
740 bool fIsANSI_VAR_Font;
741 bool fIsGoodBackupCharset;
742 bool fIsFavoriteForCharset;
743 bool fIsVariablePitch;
745 inline int Score ()
const
748 if (fUsesBestCharset) {
754 if (fIsANSI_VAR_Font) {
757 if (fIsGoodBackupCharset) {
760 if (fIsFavoriteForCharset) {
763 if (fIsVariablePitch) {
773static int FAR PASCAL EnumFontCallback (
const LOGFONT* lplf,
const TEXTMETRIC* , DWORD fontType, LPARAM arg)
777 FontSelectionInfo& result = *(FontSelectionInfo*)arg;
779 static LOGFONT theANSILogFont;
780 if (theANSILogFont.lfFaceName[0] ==
'\0') {
781 HFONT xxx = HFONT (::GetStockObject (ANSI_VAR_FONT));
782 Verify (::GetObject (xxx,
sizeof theANSILogFont, &theANSILogFont));
785 FontSelectionInfo potentialResult = result;
786 memcpy (&potentialResult.fBestFont, lplf, sizeof (LOGFONT));
788 if (potentialResult.fDesiredCharset == DEFAULT_CHARSET) {
789 potentialResult.fUsesBestCharset = bool (lplf->lfCharSet == theANSILogFont.lfCharSet);
792 potentialResult.fUsesBestCharset = bool (lplf->lfCharSet == potentialResult.fDesiredCharset);
794 potentialResult.fIsTT = bool (fontType & TRUETYPE_FONTTYPE);
795 potentialResult.fIsANSI_VAR_Font = ::_tcscmp (lplf->lfFaceName, theANSILogFont.lfFaceName) == 0;
796 potentialResult.fIsGoodBackupCharset = (lplf->lfCharSet == DEFAULT_CHARSET or lplf->lfCharSet == theANSILogFont.lfCharSet);
798 switch (potentialResult.fDesiredCharset) {
799 case SHIFTJIS_CHARSET: {
800 if (potentialResult.fBestFont.lfFaceName ==
SDKString{Led_SDK_TCHAROF (
"MS P Gothic")} or
801 potentialResult.fBestFont.lfFaceName ==
SDKString{Led_SDK_TCHAROF (
"MS Gothic")} or
802 potentialResult.fBestFont.lfFaceName ==
SDKString{Led_SDK_TCHAROF (
"MS PGothic")}) {
803 potentialResult.fIsFavoriteForCharset =
true;
806 case CHINESEBIG5_CHARSET: {
807 if (potentialResult.fBestFont.lfFaceName ==
SDKString{Led_SDK_TCHAROF (
"MS HEI")} or
808 potentialResult.fBestFont.lfFaceName ==
SDKString{Led_SDK_TCHAROF (
"MingLiU")}) {
809 potentialResult.fIsFavoriteForCharset =
true;
814 potentialResult.fIsVariablePitch = lplf->lfPitchAndFamily & VARIABLE_PITCH;
815 potentialResult.fStartsWithAt = lplf->lfFaceName[0] ==
'@';
817 if (potentialResult.Score () > result.Score ()) {
818 result = potentialResult;
827 static bool sDefaultFontValid =
false;
829 if (not sDefaultFontValid) {
830#if qStroika_Foundation_Common_Platform_Windows
831 sDefaultFont = GetStaticDefaultFont (DEFAULT_CHARSET);
832#elif qStroika_FeatureSupported_XWindows
834 sDefaultFont.SetFontNameSpecifier (
"times");
835 sDefaultFont.SetPointSize (12);
838#if qStroika_Foundation_Common_Platform_Windows
839 sDefaultFont.SetTextColor (Led_GetTextColor ());
841 sDefaultFontValid =
true;
843 return (sDefaultFont);
846#if qStroika_Foundation_Common_Platform_Windows
862 FontSelectionInfo selectedFont (charSet);
863 WindowDC screenDC (
nullptr);
865 ::EnumFontFamilies (screenDC.m_hDC,
nullptr, EnumFontCallback,
reinterpret_cast<LPARAM
> (&selectedFont));
867 ::EnumFontFamilies (screenDC.m_hDC,
nullptr,
reinterpret_cast<FONTENUMPROC
> (EnumFontCallback),
reinterpret_cast<LPARAM
> (&selectedFont));
869 fooo.LightSetOSRep (selectedFont.fBestFont);
874 static LOGFONT theANSILogFont;
875 if (theANSILogFont.lfFaceName[0] ==
'\0') {
876 HFONT xxx = HFONT (::GetStockObject (ANSI_VAR_FONT));
877 Verify (::GetObject (xxx,
sizeof theANSILogFont, &theANSILogFont));
879 fooo.SetPointSize (min (max (
FontSpecification (theANSILogFont).GetPointSize (),
static_cast<unsigned short> (8)),
880 static_cast<unsigned short> (14)));
883 defaultFont.MergeIn (fooo);
884 defaultFont.SetTextColor (Led_GetTextColor ());
885 return (defaultFont);
894IncrementalFontSpecification Led::Intersection (
const IncrementalFontSpecification& lhs,
const IncrementalFontSpecification& rhs)
896 IncrementalFontSpecification result = lhs;
900 if (not lhs.GetFontNameSpecifier_Valid () or not rhs.GetFontNameSpecifier_Valid () or
901 lhs.GetFontNameSpecifier () != rhs.GetFontNameSpecifier ()) {
902 result.InvalidateFontNameSpecifier ();
908 if (not lhs.GetStyle_Bold_Valid () or not rhs.GetStyle_Bold_Valid () or lhs.GetStyle_Bold () != rhs.GetStyle_Bold ()) {
909 result.InvalidateStyle_Bold ();
913 if (not lhs.GetStyle_Italic_Valid () or not rhs.GetStyle_Italic_Valid () or lhs.GetStyle_Italic () != rhs.GetStyle_Italic ()) {
914 result.InvalidateStyle_Italic ();
918 if (not lhs.GetStyle_Underline_Valid () or not rhs.GetStyle_Underline_Valid () or lhs.GetStyle_Underline () != rhs.GetStyle_Underline ()) {
919 result.InvalidateStyle_Underline ();
923 if (not lhs.GetStyle_SubOrSuperScript_Valid () or not rhs.GetStyle_SubOrSuperScript_Valid () or
924 lhs.GetStyle_SubOrSuperScript () != rhs.GetStyle_SubOrSuperScript ()) {
925 result.InvalidateStyle_SubOrSuperScript ();
928#if qStroika_Foundation_Common_Platform_Windows
930 if (not lhs.GetStyle_Strikeout_Valid () or not rhs.GetStyle_Strikeout_Valid () or lhs.GetStyle_Strikeout () != rhs.GetStyle_Strikeout ()) {
931 result.InvalidateStyle_Strikeout ();
938 if (not lhs.GetTextColor_Valid () or not rhs.GetTextColor_Valid () or lhs.GetTextColor () != rhs.GetTextColor ()) {
939 result.InvalidateTextColor ();
948 bool needsInval =
false;
949 if (lhs.GetPointSizeIncrement_Valid () != rhs.GetPointSizeIncrement_Valid () or
950 (lhs.GetPointSizeIncrement_Valid () and lhs.GetPointSizeIncrement () != rhs.GetPointSizeIncrement ())) {
953 if (lhs.GetPointSize_Valid () != rhs.GetPointSize_Valid () or (lhs.GetPointSize_Valid () and lhs.GetPointSize () != rhs.GetPointSize ())) {
957 result.InvalidatePointSize ();
964#if qStroika_Foundation_Common_Platform_Windows
970class Tablet::RecolorHelper {
972 RecolorHelper (HDC baseHDC, Led_Size size,
Color hilightBackColor,
Color hilightForeColor,
Color oldBackColor,
Color oldForeColor);
976 static RecolorHelper* CheckCacheAndReconstructIfNeeded (RecolorHelper* _THIS_, HDC baseHDC, Led_Size size,
Color hilightBackColor,
980 nonvirtual
void DoRecolor (
const Led_Rect& hilightArea);
983 nonvirtual
void DoRecolor_SimpleDSTINVERT (
const Led_Rect& hilightArea);
984 nonvirtual
void DoRecolor_SimplePATINVERT (
const Led_Rect& hilightArea);
987 nonvirtual
void DoRecolor_CopyTo8BitManualMungePixAndBack (
const Led_Rect& hilightArea);
990 nonvirtual
void MakeMappingTable ();
993 uint8_t fMappingTable[256];
996 nonvirtual uint8_t FindClosestColorInColorTable_ (COLORREF c)
const;
999 nonvirtual COLORREF MapColor (COLORREF c)
const;
1000 nonvirtual COLORREF MapColor (RGBQUAD c)
const;
1005 RGBQUAD fColorTable[256];
1006 HBITMAP fDibSection;
1008 size_t fDibDataByteCount;
1011 COLORREF fHilightBackColor;
1012 COLORREF fHilightForeColor;
1013 COLORREF fOldBackColor;
1014 COLORREF fOldForeColor;
1016COLORREF Tablet::RecolorHelper::MapColor (COLORREF c)
const
1019 fIntrp = (float)(255 - GetRValue (c)) / 256.0f;
1020 BYTE red =
static_cast<BYTE
> (GetRValue (fHilightBackColor) + fIntrp * GetRValue (fHilightForeColor) - fIntrp * GetRValue (fHilightBackColor));
1022 fIntrp = (float)(255 - GetGValue (c)) / 256.0f;
1023 BYTE green =
static_cast<BYTE
> (GetGValue (fHilightBackColor) + fIntrp * GetGValue (fHilightForeColor) - fIntrp * GetGValue (fHilightBackColor));
1025 fIntrp = (float)(255 - GetBValue (c)) / 256.0f;
1026 BYTE blue =
static_cast<BYTE
> (GetBValue (fHilightBackColor) + fIntrp * GetBValue (fHilightForeColor) - fIntrp * GetBValue (fHilightBackColor));
1027 return RGB (red, green, blue);
1029inline COLORREF Tablet::RecolorHelper::MapColor (RGBQUAD c)
const
1031 return MapColor (RGB (c.rgbRed, c.rgbGreen, c.rgbBlue));
1034Tablet::RecolorHelper::RecolorHelper (HDC baseHDC, Led_Size size,
Color hilightBackColor,
Color hilightForeColor,
Color oldBackColor,
Color oldForeColor)
1035 : fDibData (nullptr)
1037 , fDibDataByteCount (0)
1042 , fDibSection (nullptr)
1043 , fOldBitmap (nullptr)
1044 , fHilightBackColor (hilightBackColor.GetOSRep ())
1045 , fHilightForeColor (hilightForeColor.GetOSRep ())
1046 , fOldBackColor (oldBackColor.GetOSRep ())
1047 , fOldForeColor (oldForeColor.GetOSRep ())
1049 CreateStandardColorTable (fColorTable, fHilightBackColor, fHilightForeColor, fOldBackColor, fOldForeColor);
1050 fDibSection = Create8BitDIBSection (baseHDC, size.h, size.v, fColorTable, &fDibData);
1052 Verify (::GetObject (fDibSection,
sizeof (BITMAP), &bm) ==
sizeof (BITMAP));
1053 fDibDataByteCount = bm.bmWidthBytes * bm.bmHeight;
1054 fHMemDC = ::CreateCompatibleDC (fBaseDC);
1055 fOldBitmap =
reinterpret_cast<HBITMAP
> (::SelectObject (fHMemDC, fDibSection));
1056 MakeMappingTable ();
1059Tablet::RecolorHelper::~RecolorHelper ()
1061 if (fDibSection !=
nullptr) {
1062 ::SelectObject (fHMemDC, fOldBitmap);
1063 ::DeleteDC (fHMemDC);
1064 ::DeleteObject (fDibSection);
1068Tablet::RecolorHelper* Tablet::RecolorHelper::CheckCacheAndReconstructIfNeeded (RecolorHelper* _THIS_, HDC baseHDC, Led_Size size,
Color hilightBackColor,
1071 if (_THIS_ ==
nullptr or size.h > _THIS_->fSize.h or size.v > _THIS_->fSize.v or baseHDC != _THIS_->fBaseDC or
1072 hilightBackColor.GetOSRep () != _THIS_->fHilightBackColor or hilightForeColor.GetOSRep () != _THIS_->fHilightForeColor or
1073 oldBackColor.GetOSRep () != _THIS_->fOldBackColor or oldForeColor.GetOSRep () != _THIS_->fOldForeColor) {
1074 Led_Size areaSize = size;
1075 if (_THIS_ !=
nullptr) {
1076 areaSize.v = max (size.v, _THIS_->fSize.v);
1077 areaSize.h = max (size.h, _THIS_->fSize.h);
1079 RecolorHelper* tmp =
new RecolorHelper (baseHDC, areaSize, hilightBackColor, hilightForeColor, oldBackColor, oldForeColor);
1086void Tablet::RecolorHelper::MakeMappingTable ()
1088 for (
size_t i = 0; i < 256; ++i) {
1089 fMappingTable[i] = FindClosestColorInColorTable_ (MapColor (fColorTable[i]));
1093uint8_t Tablet::RecolorHelper::FindClosestColorInColorTable_ (COLORREF c)
const
1096 uint8_t closest = 0;
1097 unsigned int closestDistance = 0xffffffff;
1098 for (
size_t i = 0; i < 256; ++i) {
1099 unsigned int thisDist = Distance_Squared (c, RGB (fColorTable[i].rgbRed, fColorTable[i].rgbGreen, fColorTable[i].rgbBlue));
1100 if (thisDist < closestDistance) {
1101 closest =
static_cast<uint8_t
> (i);
1102 closestDistance = thisDist;
1103 if (closestDistance == 0) {
1111void Tablet::RecolorHelper::DoRecolor (
const Led_Rect& hilightArea)
1113 HPALETTE hPal =
nullptr;
1114 HPALETTE hOldPal =
nullptr;
1115 bool isPaletteDevice = !!(::GetDeviceCaps (fBaseDC, RASTERCAPS) & RC_PALETTE);
1116 if (isPaletteDevice) {
1120 hPal = CreatePaletteForColorTable (fColorTable);
1122 hOldPal = ::SelectPalette (fBaseDC, hPal, TRUE);
1123 ::RealizePalette (fBaseDC);
1126 DoRecolor_CopyTo8BitManualMungePixAndBack (hilightArea);
1128 if (isPaletteDevice) {
1129 if (hOldPal !=
nullptr) {
1130 ::SelectPalette (fBaseDC, hOldPal, TRUE);
1132 ::DeleteObject (hPal);
1136void Tablet::RecolorHelper::DoRecolor_SimpleDSTINVERT (
const Led_Rect& hilightArea)
1141 ::BitBlt (fBaseDC, hilightArea.left, hilightArea.top, hilightArea.GetWidth (), hilightArea.GetHeight (), fBaseDC, hilightArea.left,
1142 hilightArea.top, DSTINVERT);
1145void Tablet::RecolorHelper::DoRecolor_SimplePATINVERT (
const Led_Rect& hilightArea)
1149 Color useColor = Color::kWhite -
Color (fHilightBackColor);
1150 HGDIOBJ oldPen = ::SelectObject (fBaseDC, ::GetStockObject (NULL_PEN));
1151 Brush backgroundBrush (useColor.GetOSRep ());
1152 HGDIOBJ oldBrush = ::SelectObject (fBaseDC, backgroundBrush);
1153 ::BitBlt (fBaseDC, hilightArea.left, hilightArea.top, hilightArea.GetWidth (), hilightArea.GetHeight (), fBaseDC, hilightArea.left,
1154 hilightArea.top, PATINVERT);
1155 (void)::SelectObject (fBaseDC, oldPen);
1156 (void)::SelectObject (fBaseDC, oldBrush);
1159void Tablet::RecolorHelper::DoRecolor_CopyTo8BitManualMungePixAndBack (
const Led_Rect& hilightArea)
1167 ::BitBlt (fHMemDC, 0, 0, hilightArea.GetWidth (), hilightArea.GetHeight (), fBaseDC, hilightArea.left, hilightArea.top, SRCCOPY);
1188 const unsigned char* kMappingTable = fMappingTable;
1189 unsigned char* dataStart = fDibData;
1190 unsigned char* dataEnd = dataStart + fDibDataByteCount;
1191 for (
unsigned char* i = dataStart; i < dataEnd; ++i) {
1192 *i = kMappingTable[*i];
1197 ::BitBlt (fBaseDC, hilightArea.left, hilightArea.top, hilightArea.GetWidth (), hilightArea.GetHeight (), fHMemDC, 0, 0, SRCCOPY);
1201#if qStroika_Frameworks_Led_SupportGDI
1207#if qStroika_Foundation_Common_Platform_MacOS
1208Tablet::Tablet (GrafPtr gp)
1213#elif qStroika_Foundation_Common_Platform_Windows
1214Tablet::Tablet (HDC hdc, Tablet::OwnDCControl ownsDC)
1216 , fRecolorHelper (nullptr)
1218 , m_bPrinting (false)
1224#elif qStroika_FeatureSupported_XWindows
1225Tablet::Tablet (Display* display, Drawable drawable)
1226 : fDrawableOrigin (Led_Point (0, 0))
1228 , fCurDrawLineLoc (Led_Point (0, 0))
1229 , fDisplay (display)
1230 , fDrawable (drawable)
1233 , fCachedFontInfo (nullptr)
1234 , fFontMappingCache ()
1236 int screen = DefaultScreen (display);
1237 fGC = ::XCreateGC (display, drawable, 0,
nullptr);
1238 ::XSetForeground (display, fGC, BlackPixel (display, screen));
1239 ::XSetBackground (display, fGC, WhitePixel (display, screen));
1240 XSetGraphicsExposures (display, fGC,
true);
1241 XWindowAttributes wa;
1242 (void)::memset (&wa, 0,
sizeof (wa));
1247 int (*oldErrHandler) (Display*, XErrorEvent*) = ::XSetErrorHandler (IgnoreXErrorHandler);
1248 Status s = ::XGetWindowAttributes (display, drawable, &wa);
1249 ::XSetErrorHandler (oldErrHandler);
1250 if (s != 0 and wa.map_installed) {
1251 fColormap = wa.colormap;
1254 fColormap = DefaultColormap (fDisplay, DefaultScreen (fDisplay));
1265#if qStroika_Foundation_Common_Platform_Windows
1266 delete fRecolorHelper;
1267 if (m_hDC !=
nullptr and fOwnsDC == eOwnsDC) {
1268 ::DeleteDC (Detach ());
1270#elif qStroika_FeatureSupported_XWindows
1271 ::XFreeGC (fDisplay, fGC);
1272 for (
auto i = fFontCache.begin (); i != fFontCache.end (); ++i) {
1273 ::XFreeFont (fDisplay, i->second);
1283Led_Point Tablet::CvtFromTWIPS (TWIPS_Point from)
const
1285 return Led_Point{CvtFromTWIPSV (from.v), CvtFromTWIPSH (from.h)};
1293TWIPS_Point Tablet::CvtToTWIPS (Led_Point from)
const
1295 return TWIPS_Point{CvtToTWIPSV (from.v), CvtToTWIPSH (from.h)};
1303Led_Rect Tablet::CvtFromTWIPS (TWIPS_Rect from)
const
1305 return Led_Rect{CvtFromTWIPS (from.GetOrigin ()), Led_Size (CvtFromTWIPS (from.GetSize ()))};
1313TWIPS_Rect Tablet::CvtToTWIPS (Led_Rect from)
const
1315 return TWIPS_Rect{CvtToTWIPS (from.GetOrigin ()), CvtToTWIPS (Led_Point (from.GetSize ()))};
1323void Tablet::ScrollBitsAndInvalRevealed (
const Led_Rect& windowRect, CoordinateType scrollVBy)
1325#if qStroika_Foundation_Common_Platform_MacOS
1326 Rect qdMoveRect = AsQDRect (windowRect);
1327 RgnHandle updateRgn = ::NewRgn ();
1330 ::ScrollRect (&qdMoveRect, 0, scrollVBy, updateRgn);
1332 ::InvalWindowRgn (::GetWindowFromPort (fGrafPort), updateRgn);
1334 ::InvalRgn (updateRgn);
1336 ::DisposeRgn (updateRgn);
1337#elif qStroika_Foundation_Common_Platform_Windows
1338 RECT gdiMoveRect = AsRECT (windowRect);
1341 HWND w = GetWindow ();
1343 ::ScrollWindow (w, 0, scrollVBy, &gdiMoveRect, &gdiMoveRect);
1344#elif qStroika_FeatureSupported_XWindows
1345 if (scrollVBy != 0) {
1355 if (::XCheckTypedEvent (fDisplay, Expose, &e) or ::XCheckTypedEvent (fDisplay, GraphicsExpose, &e)) {
1356 ::XPutBackEvent (fDisplay, &e);
1360 Led_Rect srcMoveRect = windowRect;
1361 Led_Rect exposedRect = windowRect;
1362 if (scrollVBy > 0) {
1364 srcMoveRect.bottom -= scrollVBy;
1365 exposedRect.bottom = scrollVBy;
1368 srcMoveRect.top -= scrollVBy;
1369 exposedRect.top = exposedRect.bottom + scrollVBy;
1371 XGCValues prevValues;
1372 const unsigned long kSavedAttrs = GCGraphicsExposures;
1373 (void)::memset (&prevValues, 0,
sizeof (prevValues));
1374 ::XGetGCValues (fDisplay, fGC, kSavedAttrs, &prevValues);
1375 ::XSetClipMask (fDisplay, fGC, None);
1376 ::XSetGraphicsExposures (fDisplay, fGC,
true);
1377 ::XCopyArea (fDisplay, fDrawable, fDrawable, fGC, srcMoveRect.GetLeft (), srcMoveRect.GetTop (), srcMoveRect.GetWidth (),
1378 srcMoveRect.GetHeight (), srcMoveRect.GetLeft (), srcMoveRect.top + scrollVBy);
1379 ::XChangeGC (fDisplay, fGC, kSavedAttrs, &prevValues);
1386 (void)::memset (&event, 0,
sizeof (event));
1387 event.type = Expose;
1388 event.xexpose.send_event =
true;
1389 event.xexpose.display = fDisplay;
1390 event.xexpose.window = fDrawable;
1391 event.xexpose.x = (int)exposedRect.GetLeft ();
1392 event.xexpose.y = (int)exposedRect.GetTop ();
1393 event.xexpose.width = (int)exposedRect.GetWidth ();
1394 event.xexpose.height = (int)exposedRect.GetHeight ();
1395 event.xexpose.count = 0;
1396 Verify (::XSendEvent (fDisplay, fDrawable,
false, ExposureMask, &event) != 0);
1398 ::XClearArea (fDisplay, fDrawable, (
int)exposedRect.GetLeft (), (
int)exposedRect.GetTop (), (
unsigned int)exposedRect.GetWidth (),
1399 (
unsigned int)exposedRect.GetHeight (),
true);
1411void Tablet::FrameRegion (
const Region& r,
const Color& c)
1413#if qStroika_Foundation_Common_Platform_MacOS
1414 MacPortAndClipRegionEtcSaver saver;
1417 GDI_RGBForeColor (c.GetOSRep ());
1418 ::FrameRgn (r.GetOSRep ());
1419#elif qStroika_Foundation_Common_Platform_Windows
1420 Brush brush = Brush (c.GetOSRep ());
1421 (void)::FrameRgn (*
this, r, brush, 1, 1);
1435void Tablet::FrameRectangle (
const Led_Rect& r,
Color c, DistanceType borderWidth)
1441 Led_Rect topBar = Led_Rect (r.top, r.left, borderWidth, r.GetWidth ());
1442 Led_Rect leftBar = Led_Rect (r.top, r.left, r.GetHeight (), borderWidth);
1443 EraseBackground_SolidHelper (topBar, c);
1444 EraseBackground_SolidHelper (leftBar, c);
1445 EraseBackground_SolidHelper (topBar + Led_Point (r.GetHeight () - borderWidth, 0), c);
1446 EraseBackground_SolidHelper (leftBar + Led_Point (0, r.GetWidth () - borderWidth), c);
1457void Tablet::MeasureText (
const FontMetrics& precomputedFontMetrics,
const Led_tChar* text,
size_t nTChars, DistanceType* charLocations)
1461#if qStroika_Foundation_Common_Platform_MacOS
1465#if qStroika_Foundation_Common_Platform_MacOS
1466 const DistanceType kMaxTextWidthResult = 0x7fff;
1467#elif qStroika_Foundation_Common_Platform_Windows
1468 DistanceType kMaxTextWidthResult = kRunning32BitGDI ? 0x7fffffff : 0x7fff;
1469 if (IsPrinting ()) {
1471 SIZE ve = GetViewportExt ();
1472 SIZE we = GetWindowExt ();
1473 kMaxTextWidthResult = ::MulDiv (kMaxTextWidthResult, we.cx, ve.cx) - 1;
1475#elif qStroika_FeatureSupported_XWindows
1476 const DistanceType kMaxTextWidthResult = 0x7fff;
1478 size_t kMaxChars = kMaxTextWidthResult / precomputedFontMetrics.GetMaxCharacterWidth ();
1479#if qUseUniscribeToImage
1480 if (kMaxChars > kMaxUNISCRIBECharacters) {
1481 kMaxChars = kMaxUNISCRIBECharacters;
1484 Assert (kMaxChars > 1);
1486 DistanceType runningCharCount = 0;
1487 for (
size_t charsToGo = nTChars; charsToGo > 0;) {
1488 size_t i = nTChars - charsToGo;
1489 Assert (i < nTChars);
1491 while (text[i] ==
'\t') {
1492 Assert (charsToGo > 0);
1494 charLocations[i] = runningCharCount;
1496 if (--charsToGo == 0) {
1500 if (charsToGo == 0) {
1504 size_t charsThisTime = min (charsToGo, kMaxChars);
1505 for (
size_t tabIndex = 1; tabIndex < charsThisTime; tabIndex++) {
1506 if (text[i + tabIndex] ==
'\t') {
1507 charLocations[i + tabIndex] = runningCharCount;
1508 charsThisTime = tabIndex;
1513#if qStroika_Foundation_Common_Platform_Windows
1515 Assert (
sizeof (
int) ==
sizeof (DistanceType));
1516#if qUseUniscribeToImage
1518 if (sUniscribeDLL.IsAvail ()) {
1519 SCRIPT_CONTROL scriptControl;
1520 memset (&scriptControl, 0,
sizeof (scriptControl));
1522 SCRIPT_STATE scriptState;
1523 memset (&scriptState, 0,
sizeof (scriptState));
1531 scriptState.fInhibitSymSwap =
true;
1533 SCRIPT_STRING_ANALYSIS ssa;
1534 memset (&ssa, 0,
sizeof (ssa));
1536 Verify (sUniscribeDLL.ScriptStringAnalyse (m_hAttribDC, &text[i], charsThisTime, 0, -1, SSA_GLYPHS | SSA_FALLBACK, -1,
1537 &scriptControl, &scriptState,
nullptr,
nullptr,
nullptr, &ssa) == S_OK);
1540 for (
size_t j = 0; j < charsThisTime; ++j) {
1541 int leadingEdge = 0;
1542 int trailingEdge = 0;
1543 Verify (sUniscribeDLL.ScriptStringCPtoX (ssa, j,
false, &leadingEdge) == S_OK);
1544 Verify (sUniscribeDLL.ScriptStringCPtoX (ssa, j,
true, &trailingEdge) == S_OK);
1546 int logicalWidth = abs (trailingEdge - leadingEdge);
1548 charLocations[i + j] = runningCharCount + logicalWidth;
1551 charLocations[i + j] = charLocations[i + j - 1] + logicalWidth;
1556 Verify (sUniscribeDLL.ScriptStringGetLogicalWidths (ssa, logicalWidths) == S_OK);
1558 Assert (charsThisTime > 0);
1559 Assert (logicalWidths[0] >= 0);
1560 charLocations[i] = runningCharCount + logicalWidths[0];
1561 for (
size_t j = 1; j < charsThisTime; ++j) {
1562 Assert (logicalWidths[j] >= 0);
1563 charLocations[i + j] = charLocations[i + j - 1] + logicalWidths[j];
1566 Verify (sUniscribeDLL.ScriptStringFree (&ssa) == S_OK);
1573 Win32_GetTextExtentExPoint (m_hAttribDC, &text[i], charsThisTime, kMaxTextWidthResult,
nullptr, (
int*)&charLocations[i], &size);
1574 for (
size_t j = 0; j < charsThisTime; ++j) {
1575 charLocations[i + j] += runningCharCount;
1578#if qUseUniscribeToImage
1581#elif qStroika_FeatureSupported_XWindows
1585 for (
size_t j = 0; j < charsThisTime; ++j) {
1586 charLocations[i + j] = runningCharCount + ::XTextWidth (
const_cast<XFontStruct*
> (fCachedFontInfo), &text[i], j + 1);
1590 runningCharCount = charLocations[i + charsThisTime - 1];
1592 Assert (charsToGo >= charsThisTime);
1593 charsToGo -= charsThisTime;
1597#if qStroika_Foundation_Common_Platform_Windows && 0
1605 int lastWidth = (nTChars == 1) ? charLocations[0] : (charLocations[nTChars - 1] - charLocations[nTChars - 2]);
1608 Win32_GetTextExtentPoint (m_hAttribDC, &text[nTChars - 1], 1, &size);
1609 int sbWidth = size.cx;
1610 if (sbWidth != lastWidth) {
1611 charLocations[nTChars - 1] = ((nTChars == 1) ? 0 : charLocations[nTChars - 2]) + sbWidth;
1619 for (
size_t i = 0; i < nTChars; ++i) {
1620 Ensure (d <= charLocations[i]);
1621 d = charLocations[i];
1636void Tablet::TabbedTextOut ([[maybe_unused]]
const FontMetrics& precomputedFontMetrics,
const Led_tChar* text,
size_t nBytes,
1637 [[maybe_unused]] TextDirection direction, Led_Point outputAt, CoordinateType hTabOrigin,
1638 const TabStopList& tabStopList, DistanceType* amountDrawn, CoordinateType hScrollOffset)
1640 DistanceType widthSoFar = 0;
1641 const Led_tChar* textCursor = text;
1642 const Led_tChar* textEnd = text + nBytes;
1643 while (textCursor < textEnd) {
1645 const Led_tChar* nextTabAt = textCursor;
1646 for (; nextTabAt < textEnd;) {
1647 if (*nextTabAt ==
'\t') {
1654#if qStroika_Foundation_Common_Platform_Windows
1655 int oldBkMode = SetBkMode (TRANSPARENT);
1657#if qUseUniscribeToImage
1659#if qTryToOptimizeLongUNISCRIBEScriptOutCalls
1660 const size_t kMaxCharsToDrawAtATime = 500;
1662 size_t len = nextTabAt - textCursor;
1666 if (sUniscribeDLL.IsAvail ()) {
1667 SCRIPT_CONTROL scriptControl;
1668 memset (&scriptControl, 0,
sizeof (scriptControl));
1670 SCRIPT_STATE scriptState;
1671 memset (&scriptState, 0,
sizeof (scriptState));
1672 scriptState.fOverrideDirection =
true;
1673 scriptState.fInhibitSymSwap =
true;
1675 const Led_tChar* thisChunkPtr = textCursor;
1676 for (
size_t thisChunkLen = len; thisChunkLen > 0;) {
1677 if (thisChunkLen > kMaxUNISCRIBECharacters) {
1678 thisChunkLen = kMaxUNISCRIBECharacters;
1680#if qTryToOptimizeLongUNISCRIBEScriptOutCalls
1681 if (thisChunkLen > kMaxCharsToDrawAtATime) {
1682 thisChunkLen = kMaxCharsToDrawAtATime;
1686 SCRIPT_STRING_ANALYSIS ssa;
1687 memset (&ssa, 0,
sizeof (ssa));
1688 if (not SUCCEEDED (sUniscribeDLL.ScriptStringAnalyse (m_hDC, thisChunkPtr, thisChunkLen, 0, -1, SSA_GLYPHS | SSA_FALLBACK,
1689 -1, &scriptControl, &scriptState,
nullptr,
nullptr,
nullptr, &ssa))) {
1690 goto UniscribeFailure;
1693 Verify (sUniscribeDLL.ScriptStringOut (ssa, outputAt.h + int (widthSoFar) - hScrollOffset, outputAt.v, 0,
nullptr,
1694 0, 0,
false) == S_OK);
1695 const SIZE* sizep = sUniscribeDLL.ScriptString_pSize (ssa);
1697 widthSoFar += sizep->cx;
1698 Verify (sUniscribeDLL.ScriptStringFree (&ssa) == S_OK);
1701#if qTryToOptimizeLongUNISCRIBEScriptOutCalls
1704 if (len > kMaxCharsToDrawAtATime) {
1706 Verify (::GetViewportOrgEx (m_hAttribDC, &vpOrg));
1708 Verify (::GetWindowOrgEx (m_hAttribDC, &wOrg));
1709 int deviceWidth = GetDeviceCaps (HORZRES);
1712 Verify (::DPtoLP (m_hAttribDC, &x, 1));
1713 if (x.x < outputAt.h + int (widthSoFar) - hScrollOffset) {
1720 thisChunkPtr += thisChunkLen;
1721 thisChunkLen = (textCursor + len - thisChunkPtr);
1730 if (direction == eLeftToRight) {
1731 Win32_TextOut (m_hDC,
static_cast<int> (outputAt.h + widthSoFar - hScrollOffset),
static_cast<int> (outputAt.v), textCursor,
1732 static_cast<int> (nextTabAt - textCursor));
1740 if (amountDrawn !=
nullptr or (nextTabAt < textEnd)) {
1742 Win32_GetTextExtentPoint (m_hAttribDC, textCursor,
static_cast<int> (nextTabAt - textCursor), &size);
1743 widthSoFar += size.cx;
1751#if qUseGetCharPlacementToImage
1753 size_t len = nextTabAt - textCursor;
1755 GCP_RESULTSW gcpResult;
1756 memset (&gcpResult, 0,
sizeof (gcpResult));
1757 gcpResult.lStructSize =
sizeof (GCP_RESULTS);
1758 gcpResult.lpGlyphs = glyphs.data ();
1759 gcpResult.nGlyphs =
static_cast<UINT
> (len);
1760 if (::GetCharacterPlacementW (m_hDC, textCursor,
static_cast<int> (len), 0, &gcpResult, GCP_GLYPHSHAPE | GCP_LIGATE) != 0) {
1761 Verify (::ExtTextOutW (m_hDC, outputAt.h + widthSoFar - hScrollOffset, outputAt.v, ETO_GLYPH_INDEX,
nullptr,
1762 gcpResult.lpGlyphs, gcpResult.nGlyphs,
nullptr));
1763 goto Succeeded_But_Need_To_Adjust_Width;
1768#if qUseFakeTTGetWPlacementToImage
1770 size_t len = nextTabAt - textCursor;
1772 if (Win9x_Workaround_GetCharPlacementFunction (m_hDC, textCursor, len, glyphs.data ()) != 0) {
1773 Verify (::ExtTextOutW (m_hDC, outputAt.h + widthSoFar - hScrollOffset, outputAt.v, ETO_GLYPH_INDEX,
nullptr,
1774 glyphs.data (),
static_cast<UINT
> (len),
nullptr));
1775 goto Succeeded_But_Need_To_Adjust_Width;
1781 size_t len = nextTabAt - textCursor;
1784 Verify (::ExtTextOutW (m_hDC, outputAt.h + widthSoFar - hScrollOffset, outputAt.v, 0,
nullptr, textCursor,
1785 static_cast<UINT
> (len),
nullptr));
1788 Succeeded_But_Need_To_Adjust_Width:
1795 if (amountDrawn !=
nullptr or (nextTabAt < textEnd)) {
1797 Win32_GetTextExtentPoint (m_hAttribDC, textCursor,
static_cast<int> (nextTabAt - textCursor), &size);
1798 widthSoFar += size.cx;
1801#if qUseUniscribeToImage
1805 (void)SetBkMode (oldBkMode);
1806#elif qStroika_FeatureSupported_XWindows
1807 Led_Point cursor = Led_Point (outputAt.v + precomputedFontMetrics.GetAscent (), outputAt.h - hScrollOffset) - fDrawableOrigin;
1809 memset (&item, 0,
sizeof (item));
1810 item.chars =
const_cast<char*
> (textCursor);
1811 item.nchars = nextTabAt - textCursor;
1814 ::XDrawText (fDisplay, fDrawable, fGC, cursor.h + widthSoFar, cursor.v, &item, 1);
1816 widthSoFar += ::XTextWidth (
const_cast<XFontStruct*
> (fCachedFontInfo), item.chars, item.nchars);
1820 if (nextTabAt < textEnd) {
1821 DistanceType thisTabWidth;
1823 DistanceType curOutputAtZeroBased = (outputAt.h - hTabOrigin) + widthSoFar;
1824 DistanceType tabStop = tabStopList.ComputeTabStopAfterPosition (
this, curOutputAtZeroBased);
1825 thisTabWidth = tabStop - curOutputAtZeroBased;
1826 Assert (thisTabWidth >= 0);
1829 widthSoFar += thisTabWidth;
1832 textCursor = nextTabAt;
1834 if (amountDrawn !=
nullptr) {
1835 *amountDrawn = widthSoFar;
1839void Tablet::SetBackColor (
const Color& backColor)
1841#if qStroika_Foundation_Common_Platform_Windows
1842 SetBkColor (backColor.GetOSRep ());
1843#elif qStroika_FeatureSupported_XWindows
1844 if (backColor == Color::kWhite) {
1845 ::XSetBackground (fDisplay, fGC, WhitePixel (fDisplay, DefaultScreen (fDisplay)));
1847 else if (backColor == Color::kBlack) {
1848 ::XSetBackground (fDisplay, fGC, BlackPixel (fDisplay, DefaultScreen (fDisplay)));
1852 memset (&bgColorDef, 0,
sizeof (bgColorDef));
1853 bgColorDef.red = backColor.GetRed ();
1854 bgColorDef.green = backColor.GetGreen ();
1855 bgColorDef.blue = backColor.GetBlue ();
1856 Colormap cmap = DefaultColormap (fDisplay, DefaultScreen (fDisplay));
1857 Status s = XAllocColor (fDisplay, cmap, &bgColorDef);
1859 ::XSetBackground (fDisplay, fGC, WhitePixel (fDisplay, DefaultScreen (fDisplay)));
1862 ::XSetBackground (fDisplay, fGC, bgColorDef.pixel);
1868void Tablet::SetForeColor (
const Color& foreColor)
1870#if qStroika_Foundation_Common_Platform_Windows
1871 SetTextColor (foreColor.GetOSRep ());
1872#elif qStroika_FeatureSupported_XWindows
1873 if (foreColor == Color::kWhite) {
1874 ::XSetForeground (fDisplay, fGC, WhitePixel (fDisplay, DefaultScreen (fDisplay)));
1876 else if (foreColor == Color::kBlack) {
1877 ::XSetForeground (fDisplay, fGC, BlackPixel (fDisplay, DefaultScreen (fDisplay)));
1881 memset (&fgColorDef, 0,
sizeof (fgColorDef));
1882 fgColorDef.red = foreColor.GetRed ();
1883 fgColorDef.green = foreColor.GetGreen ();
1884 fgColorDef.blue = foreColor.GetBlue ();
1885 Colormap cmap = DefaultColormap (fDisplay, DefaultScreen (fDisplay));
1886 Status s = ::XAllocColor (fDisplay, cmap, &fgColorDef);
1888 ::XSetForeground (fDisplay, fGC, BlackPixel (fDisplay, DefaultScreen (fDisplay)));
1891 ::XSetForeground (fDisplay, fGC, fgColorDef.pixel);
1902void Tablet::EraseBackground_SolidHelper (
const Led_Rect& eraseRect,
const Color& eraseColor)
1904 if (not eraseRect.IsEmpty ()) {
1905#if qStroika_Foundation_Common_Platform_Windows
1906 Led_Rect eraser = eraseRect;
1907 Brush backgroundBrush (eraseColor.GetOSRep ());
1908 GDI_Obj_Selector pen (
this, ::GetStockObject (NULL_PEN));
1909 GDI_Obj_Selector brush (
this, backgroundBrush);
1912 Rectangle (AsRECT (eraser));
1913#elif qStroika_FeatureSupported_XWindows
1914 XGCValues prevValues;
1915 const unsigned long kSavedAttrs = GCForeground;
1916 Colormap cmap = DefaultColormap (fDisplay, 0);
1918 memset (&fgColorDef, 0,
sizeof (fgColorDef));
1919 fgColorDef.red = eraseColor.GetRed ();
1920 fgColorDef.green = eraseColor.GetGreen ();
1921 fgColorDef.blue = eraseColor.GetBlue ();
1922 Status s = ::XAllocColor (fDisplay, cmap, &fgColorDef);
1924 ::XSetForeground (fDisplay, fGC, fgColorDef.pixel);
1926 Led_Rect adjustedEraseRect = eraseRect - fDrawableOrigin;
1927 ::XFillRectangle (fDisplay, fDrawable, fGC, adjustedEraseRect.GetLeft (), adjustedEraseRect.GetTop (),
1928 adjustedEraseRect.GetWidth (), adjustedEraseRect.GetHeight ());
1929 ::XChangeGC (fDisplay, fGC, kSavedAttrs, &prevValues);
1945void Tablet::HilightArea_SolidHelper (
const Led_Rect& hilightArea, [[maybe_unused]]
Color hilightBackColor,
1946 [[maybe_unused]]
Color hilightForeColor,
Color oldBackColor, [[maybe_unused]]
Color oldForeColor)
1948 if (not hilightArea.IsEmpty ()) {
1949#if qStroika_Foundation_Common_Platform_Windows
1953 if (hilightBackColor.GetOSRep () == Color::kBlack.GetOSRep () and hilightForeColor.GetOSRep () == Color::kWhite.GetOSRep () and
1954 oldBackColor.GetOSRep () == Color::kWhite.GetOSRep () and oldForeColor.GetOSRep () == Color::kBlack.GetOSRep ()) {
1959 BitBlt (hilightArea.left, hilightArea.top, hilightArea.GetWidth (), hilightArea.GetHeight (),
this, hilightArea.left,
1960 hilightArea.top, DSTINVERT);
1964 fRecolorHelper = RecolorHelper::CheckCacheAndReconstructIfNeeded (fRecolorHelper, m_hDC,
1965 Led_Size (hilightArea.GetHeight (), hilightArea.GetWidth ()),
1966 hilightBackColor, hilightForeColor, oldBackColor, oldForeColor);
1967 fRecolorHelper->DoRecolor (hilightArea);
1969 static RecolorHelper* recolorHelper =
nullptr;
1970 recolorHelper = RecolorHelper::CheckCacheAndReconstructIfNeeded (recolorHelper, m_hDC,
1971 Led_Size (hilightArea.GetHeight (), hilightArea.GetWidth ()),
1972 hilightBackColor, hilightForeColor, oldBackColor, oldForeColor);
1973 recolorHelper->DoRecolor (hilightArea);
1976#elif qStroika_FeatureSupported_XWindows
1981 XGCValues prevValues;
1982 const unsigned long kSavedAttrs = GCFunction | GCForeground | GCBackground;
1983 (void)::memset (&prevValues, 0,
sizeof (prevValues));
1984 ::XGetGCValues (fDisplay, fGC, kSavedAttrs, &prevValues);
1985 ::XSetFunction (fDisplay, fGC, GXxor);
1986 long whiteP = WhitePixel (fDisplay, DefaultScreen (fDisplay));
1987 long blackP = BlackPixel (fDisplay, DefaultScreen (fDisplay)) ^ whiteP;
1988 ::XSetBackground (fDisplay, fGC, whiteP);
1989 ::XSetForeground (fDisplay, fGC, blackP);
1990 Led_Rect adjustedRect = hilightArea - fDrawableOrigin;
1991 ::XFillRectangle (fDisplay, fDrawable, fGC, adjustedRect.GetLeft (), adjustedRect.GetTop (), adjustedRect.GetWidth (),
1992 adjustedRect.GetHeight ());
1993 ::XChangeGC (fDisplay, fGC, kSavedAttrs, &prevValues);
2005void Tablet::HilightArea_SolidHelper (
const Region& hilightArea, [[maybe_unused]]
Color hilightBackColor, [[maybe_unused]]
Color hilightForeColor,
2006 [[maybe_unused]]
Color oldBackColor, [[maybe_unused]]
Color oldForeColor)
2008 if (not hilightArea.IsEmpty ()) {
2009#if qStroika_Foundation_Common_Platform_Windows
2011#elif qStroika_FeatureSupported_XWindows
2021FontMetrics Tablet::GetFontMetrics ()
const
2023#if qStroika_Foundation_Common_Platform_Windows
2026 Verify (::GetTextMetrics (m_hAttribDC, &tms) != 0);
2028#elif qStroika_FeatureSupported_XWindows
2029 FontMetrics::PlatformSpecific result;
2030 memset (&result, 0,
sizeof (result));
2032 result.fAscent = fCachedFontInfo->ascent;
2033 result.fDescent = fCachedFontInfo->descent;
2034 result.fLeading = 0;
2035 result.fMaxCharWidth = fCachedFontInfo->max_bounds.width;
2040#if qStroika_FeatureSupported_XWindows
2047 map<string, XFontStruct*>::const_iterator i = fFontCache.find (fontSpec.GetOSRep ());
2048 if (i != fFontCache.end ()) {
2049 XFontStruct* newFontStruct = i->second;
2050 if (newFontStruct != fCachedFontInfo) {
2051 fCachedFontInfo = i->second;
2053 ::XSetFont (fDisplay, fGC, fCachedFontInfo->fid);
2060 if (fFontCache.size () >= kMaxFontCacheSize) {
2062 ::XFreeFont (fDisplay, fFontCache.begin ()->second);
2063 fFontCache.erase (fFontCache.begin ());
2071 fCachedFontInfo =
nullptr;
2072 fCachedFontInfo = ::XLoadQueryFont (fDisplay, fontSpec.GetOSRep ().c_str ());
2073 if (fCachedFontInfo ==
nullptr) {
2077 map<string, string>::const_iterator i = fFontMappingCache.find (fontSpec.GetOSRep ());
2080 if (i != fFontMappingCache.end ()) {
2081 useFontName = i->second;
2082 Assert (not useFontName.empty ());
2086 char pointSize[1024];
2087 (void)::sprintf (pointSize,
"%d", fontSpec.GetPointSize () * 10);
2088 const string kMatchAny =
"*";
2089 string tryFontRep = fontSpec.mkOSRep (kMatchAny, fontSpec.GetFontNameSpecifier (), kMatchAny, kMatchAny, kMatchAny);
2091 char** fontList = ::XListFonts (fDisplay, tryFontRep.c_str (), 100000, &nFonts);
2092#if qDebugFontDetails
2093 bool nameMatchFailure =
false;
2095 if (fontList ==
nullptr) {
2096#if qDebugFontDetails
2097 nameMatchFailure =
true;
2100 if (fontSpec.GetFontNameSpecifier () ==
"Times New Roman") {
2101 tryFontRep = fontSpec.mkOSRep (kMatchAny,
"times", kMatchAny, kMatchAny, kMatchAny);
2102 fontList = ::XListFonts (fDisplay, tryFontRep.c_str (), 100000, &nFonts);
2105 if (fontList ==
nullptr) {
2106#if qDebugFontDetails
2107 nameMatchFailure =
true;
2109 tryFontRep = fontSpec.mkOSRep (kMatchAny, kMatchAny, kMatchAny, kMatchAny, kMatchAny);
2110 fontList = ::XListFonts (fDisplay, tryFontRep.c_str (), 100000, &nFonts);
2113 vector<string> vFontList;
2115 vFontList.reserve (nFonts);
2116 for (
size_t i = 0; i < nFonts; ++i) {
2117 vFontList.push_back (fontList[i]);
2120 ::XFreeFontNames (fontList);
2122 string bestMatchingName = BestMatchFont (fontSpec, vFontList);
2123#if qDebugFontDetails
2124 if (nameMatchFailure) {
2125 fprintf (stderr,
"Couldn't find fontName '%s'- using BestMatchSpec = '%s'\r\n", fontSpec.GetFontNameSpecifier ().
c_str (),
2126 bestMatchingName.c_str ());
2129 useFontName = bestMatchingName;
2130 Assert (not useFontName.empty ());
2131#if qDebugFontDetails
2132 fprintf (stderr,
"Adding mapping to fFontMappingCache: '%s'- ==> '%s'\r\n", fontSpec.GetOSRep ().c_str (), useFontName.c_str ());
2134 fFontMappingCache.insert (map<string, string>::value_type (fontSpec.GetOSRep (), useFontName));
2136 fCachedFontInfo = ::XLoadQueryFont (fDisplay, useFontName.c_str ());
2139 fFontCache.insert (map<string, XFontStruct*>::value_type (fontSpec.GetOSRep (), fCachedFontInfo));
2141 ::XSetFont (fDisplay, fGC, fCachedFontInfo->fid);
2144void Tablet::SetDrawableOrigin (
const Led_Point& origin)
2146 fDrawableOrigin = origin;
2150#if qStroika_FeatureSupported_XWindows
2151static bool FontNamesEqual (
const string& lhs,
const string& rhs)
2153 if (lhs.length () != rhs.length ()) {
2156 for (
size_t i = 0; i < lhs.length (); ++i) {
2157 if (lhs[i] != rhs[i]) {
2166 float bestScore = 0.0f;
2168 int fspPointSize = fsp.GetPointSize ();
2169 SDKString fspWeight = fsp.GetStyle_Bold () ?
"bold" :
"medium";
2170 SDKString fspItalics = fsp.GetStyle_Italic () ?
"i" :
"r";
2171 const string kMatchAny =
"*";
2172 for (
auto i = fontsList.begin (); i != fontsList.end (); ++i) {
2177 ParseFontName (*i, &name, &size, &weight, &slant);
2178 bool rightFontName = (FontNamesEqual (fspName, name));
2180 float thisScore = 1;
2181 if (rightFontName) {
2184 int thisPointSize = 0;
2185 if (::sscanf (size.c_str (),
"%d", &thisPointSize) == 1) {
2186 int pointSizeDiff = abs (thisPointSize - (fspPointSize * 10));
2187 float scoreAdj = (100.0f - (pointSizeDiff / 10.0f)) / 10.0f;
2188 scoreAdj = max (0.0f, scoreAdj);
2189 thisScore += scoreAdj;
2191 if (weight == fspWeight) {
2194 if (slant == fspItalics) {
2198 if (thisScore > bestScore) {
2199 bestScore = thisScore;
2200 bestAnswer = FontSpecification::mkOSRep (kMatchAny, name, weight, slant, size);
2206int Tablet::IgnoreXErrorHandler (Display* , XErrorEvent* )
2231 size_t end = fontName.find (
'-', start);
2232 foundry = fontName.substr (start, end - start);
2235 end = fontName.find (
'-', start);
2236 family = fontName.substr (start, end - start);
2239 end = fontName.find (
'-', start);
2240 weight = fontName.substr (start, end - start);
2243 end = fontName.find (
'-', start);
2244 slant = fontName.substr (start, end - start);
2247 end = fontName.find (
'-', start);
2248 setwidth = fontName.substr (start, end - start);
2251 end = fontName.find (
'-', start);
2252 string ignored = fontName.substr (start, end - start);
2255 end = fontName.find (
'-', start);
2256 pixels = fontName.substr (start, end - start);
2259 end = fontName.find (
'-', start);
2260 points = fontName.substr (start, end - start);
2263 end = fontName.find (
'-', start);
2264 hRes = fontName.substr (start, end - start);
2267 end = fontName.find (
'-', start);
2268 vRes = fontName.substr (start, end - start);
2270 *familyName = family;
2272 *fontWeight = weight;
2282#if qStroika_Foundation_Common_Platform_MacOS
2283OffscreenTablet::OT::OT (GrafPtr gp)
2287#elif qStroika_Foundation_Common_Platform_Windows
2288OffscreenTablet::OT::OT (HDC hdc, Tablet::OwnDCControl ownsDC)
2289 : inherited (hdc, ownsDC)
2292#elif qStroika_FeatureSupported_XWindows
2293OffscreenTablet::OT::OT (Display* display, Drawable drawable)
2294 : inherited (display, drawable)
2304OffscreenTablet::OffscreenTablet ()
2305 : fOrigTablet (nullptr)
2306 , fOffscreenRect (Led_Rect (0, 0, 0, 0))
2307 , fOffscreenTablet (nullptr)
2308#if qStroika_Foundation_Common_Platform_MacOS
2309 , fOrigDevice (nullptr)
2310 , fOrigPort (nullptr)
2311 , fOffscreenGWorld (nullptr)
2312#elif qStroika_Foundation_Common_Platform_Windows
2315 , fOldBitmapInDC (nullptr)
2316#elif qStroika_FeatureSupported_XWindows
2322OffscreenTablet::~OffscreenTablet ()
2324#if qStroika_Foundation_Common_Platform_MacOS
2325 if (fOrigPort !=
nullptr) {
2326 ::SetGWorld (fOrigPort, fOrigDevice);
2328 if (fOffscreenGWorld !=
nullptr) {
2329 ::DisposeGWorld (fOffscreenGWorld);
2331 delete fOffscreenTablet;
2332#elif qStroika_Foundation_Common_Platform_Windows
2333 if (fOldBitmapInDC !=
nullptr) {
2334 (void)fMemDC.SelectObject (fOldBitmapInDC);
2336#elif qStroika_FeatureSupported_XWindows
2338 ::XFreePixmap (fOrigTablet->fDisplay, fPixmap);
2349void OffscreenTablet::Setup (Tablet* origTablet)
2351 Require (fOrigTablet ==
nullptr);
2354 fOrigTablet = origTablet;
2355#if qStroika_Foundation_Common_Platform_MacOS
2357 Assert (fOrigPort ==
nullptr);
2358 Assert (fOrigDevice ==
nullptr);
2359 ::GetGWorld (&fOrigPort, &fOrigDevice);
2362 Assert (fOffscreenGWorld ==
nullptr);
2364 Rect bounds = AsQDRect (Led_Rect (0, 0, 1, 1));
2365 OSErr theErr = SafeNewGWorld (&fOffscreenGWorld, 0, &bounds,
nullptr,
nullptr, noNewDevice | useTempMem);
2366 if (theErr != noErr) {
2367 fOffscreenGWorld =
nullptr;
2370 if (fOffscreenGWorld !=
nullptr) {
2371 fOffscreenTablet =
new OT (
reinterpret_cast<GrafPtr
> (fOffscreenGWorld));
2373#elif qStroika_Foundation_Common_Platform_Windows
2374 if (fMemDC.CreateCompatibleDC (fOrigTablet)) {
2375 fOffscreenTablet = &fMemDC;
2377#elif qStroika_FeatureSupported_XWindows
2378 Assert (fPixmap == 0);
2389Tablet* OffscreenTablet::PrepareRect (
const Led_Rect& currentRowRect, DistanceType extraToAddToBottomOfRect)
2391 Tablet* result = fOrigTablet;
2392#if qStroika_Foundation_Common_Platform_MacOS
2393 if (fOffscreenTablet !=
nullptr) {
2394 fOffscreenRect = currentRowRect;
2395 fOffscreenRect.bottom += extraToAddToBottomOfRect;
2396 Rect bounds = AsQDRect (fOffscreenRect);
2397 ::OffsetRect (&bounds, -bounds.left, -bounds.top);
2399 Led_Size curOffscreenGWorldSize;
2402 curOffscreenGWorldSize = AsLedSize (GetRectSize (*::GetPixBounds (::GetPortPixMap (fOffscreenGWorld), &junk)));
2405 Led_Size curOffscreenGWorldSize = AsLedSize (GetRectSize ((*fOffscreenGWorld->portPixMap)->bounds));
2407 if ((fOffscreenRect.GetSize () == curOffscreenGWorldSize) or SafeUpdateGWorld (&fOffscreenGWorld, 0, &bounds,
nullptr,
nullptr, 0) >= 0) {
2409 if (::LockPixels (::GetGWorldPixMap (fOffscreenGWorld))) {
2411 delete fOffscreenTablet;
2412 fOffscreenTablet =
new OT (
reinterpret_cast<GrafPtr
> (fOffscreenGWorld));
2413 result = fOffscreenTablet;
2414 ::SetGWorld (fOffscreenGWorld,
nullptr);
2415 ::SetOrigin (fOffscreenRect.left, fOffscreenRect.top);
2420 ::SetGWorld (fOrigPort, fOrigDevice);
2421 if (fOffscreenGWorld !=
nullptr) {
2422 ::DisposeGWorld (fOffscreenGWorld);
2423 fOffscreenGWorld =
nullptr;
2425 delete fOffscreenTablet;
2426 fOffscreenTablet =
nullptr;
2429#elif qStroika_Foundation_Common_Platform_Windows
2430 if (fOffscreenTablet !=
nullptr) {
2431 fOffscreenRect = currentRowRect;
2432 fOffscreenRect.bottom += extraToAddToBottomOfRect;
2434 if (fMemoryBitmap ==
nullptr or (fOffscreenRect.GetSize () != fMemoryBitmap.GetImageSize ())) {
2437 if (fOldBitmapInDC !=
nullptr) {
2438 (void)fMemDC.SelectObject (fOldBitmapInDC);
2440 fMemoryBitmap.DeleteObject ();
2441#if qUseDIBSectionForOffscreenBitmap
2442 if (fMemoryBitmap.CreateCompatibleDIBSection (fOrigTablet->m_hDC, fOffscreenRect.GetWidth (), fOffscreenRect.GetHeight ()) == 0) {
2443 fOffscreenTablet =
nullptr;
2446 if (fMemoryBitmap.CreateCompatibleBitmap (fOrigTablet->m_hDC, fOffscreenRect.GetWidth (), fOffscreenRect.GetHeight ()) == 0) {
2447 fOffscreenTablet =
nullptr;
2450 if (fOffscreenTablet !=
nullptr) {
2451 fOldBitmapInDC = fMemDC.SelectObject (fMemoryBitmap);
2452 if (fOldBitmapInDC ==
nullptr) {
2453 fOffscreenTablet =
nullptr;
2457 if (fOffscreenTablet !=
nullptr) {
2458 result = fOffscreenTablet;
2460 if (fOffscreenTablet !=
nullptr) {
2461 fMemDC.SetWindowOrg (fOffscreenRect.left, fOffscreenRect.top);
2464#elif qStroika_FeatureSupported_XWindows
2465 Led_Size pixmapSize = fOffscreenRect.GetSize ();
2466 fOffscreenRect = currentRowRect;
2467 fOffscreenRect.bottom += extraToAddToBottomOfRect;
2468 if (fPixmap == 0 or pixmapSize != fOffscreenRect.GetSize ()) {
2470 delete fOffscreenTablet;
2471 fOffscreenTablet =
nullptr;
2473 ::XFreePixmap (fOrigTablet->fDisplay, fPixmap);
2476 unsigned int depth = 1;
2479 XWindowAttributes winAttrs;
2480 (void)::memset (&winAttrs, 0,
sizeof (winAttrs));
2485 int (*oldErrHandler) (Display*, XErrorEvent*) = ::XSetErrorHandler (Tablet::IgnoreXErrorHandler);
2486 Status s = ::XGetWindowAttributes (fOrigTablet->fDisplay, fOrigTablet->fDrawable, &winAttrs);
2487 ::XSetErrorHandler (oldErrHandler);
2490 depth = ::XDefaultDepthOfScreen (::XScreenOfDisplay (fOrigTablet->fDisplay, DefaultScreen (fOrigTablet->fDisplay)));
2493 depth = winAttrs.depth;
2496 fPixmap = ::XCreatePixmap (fOrigTablet->fDisplay, fOrigTablet->fDrawable, fOffscreenRect.GetWidth (), fOffscreenRect.GetHeight (), depth);
2497 Assert (fPixmap != 0);
2499 fOffscreenTablet =
new OT (fOrigTablet->fDisplay, fPixmap);
2500 fOffscreenTablet->fColormap = fOrigTablet->fColormap;
2501 fOffscreenTablet->fFontMappingCache = fOrigTablet->fFontMappingCache;
2504 delete fOffscreenTablet;
2505 fOffscreenTablet =
nullptr;
2509 if (fOffscreenTablet !=
nullptr) {
2510 fOffscreenTablet->SetDrawableOrigin (fOffscreenRect.GetTopLeft ());
2511 result = fOffscreenTablet;
2522void OffscreenTablet::BlastBitmapToOrigTablet ()
2524 if (fOffscreenTablet !=
nullptr) {
2525#if qStroika_Foundation_Common_Platform_MacOS
2526 Rect bounds = AsQDRect (fOffscreenRect);
2527 ::SetGWorld (fOrigPort, fOrigDevice);
2528 GDI_RGBForeColor (Color::kBlack.GetOSRep ());
2529 GDI_RGBBackColor (Color::kWhite.GetOSRep ());
2530 GrafPtr tabletGrafPort = *fOffscreenTablet;
2534 ::CopyBits (::GetPortBitMapForCopyBits (tabletGrafPort), ::GetPortBitMapForCopyBits (fOrigPort),
2535 ::GetPortBounds (tabletGrafPort, &tmp), &bounds, srcCopy,
nullptr);
2538 ::CopyBits (&tabletGrafPort->portBits, &((GrafPtr)fOrigPort)->portBits, &tabletGrafPort->portRect, &bounds, srcCopy,
nullptr);
2540 ::UnlockPixels (::GetGWorldPixMap (fOffscreenGWorld));
2541#elif qStroika_Foundation_Common_Platform_Windows
2542 Tablet* screenDC = fOrigTablet;
2543 screenDC->BitBlt (fOffscreenRect.left, fOffscreenRect.top, fOffscreenRect.GetWidth (), fOffscreenRect.GetHeight (),
2544 fOffscreenTablet, fOffscreenRect.left, fOffscreenRect.top, SRCCOPY);
2545#elif qStroika_FeatureSupported_XWindows
2546 Assert (fPixmap != 0);
2547 ::XCopyArea (fOrigTablet->fDisplay, fOffscreenTablet->fDrawable, fOrigTablet->fDrawable, fOrigTablet->fGC, 0, 0,
2548 fOffscreenRect.GetWidth (), fOffscreenRect.GetHeight (), (
int)fOffscreenRect.GetLeft (), (
int)fOffscreenRect.GetTop ());
2554#if qStroika_Frameworks_Led_SupportGDI
2561InstalledFonts::InstalledFonts (
2562#
if qStroika_FeatureSupported_XWindows
2565 FilterOptions filterOptions)
2566 : fFilterOptions (filterOptions)
2569#if qStroika_Foundation_Common_Platform_Windows
2571 memset (&lf, 0,
sizeof (LOGFONT));
2572 lf.lfCharSet = DEFAULT_CHARSET;
2573 WindowDC screenDC (
nullptr);
2574 ::EnumFontFamiliesEx (screenDC.m_hDC, &lf, (FONTENUMPROC)FontFamilyAdderProc,
reinterpret_cast<LPARAM
> (
this), 0);
2575 sort (fFontNames.begin (), fFontNames.end ());
2576 vector<SDKString>::iterator rest = unique (fFontNames.begin (), fFontNames.end ());
2577 fFontNames.erase (rest, fFontNames.end ());
2578#elif qStroika_FeatureSupported_XWindows
2579 int fontListSize = 0;
2580 char** fontList = ::XListFonts (display,
"*", 200000, &fontListSize);
2581 set<string> fontNames;
2582 for (
int i = 0; i < fontListSize; ++i) {
2583 string longFontName = fontList[i];
2584 string tmp = longFontName;
2585 if (tmp.length () > 0 and tmp[0] ==
'-') {
2586 size_t nextDash = tmp.find (
'-', 1);
2587 if (nextDash != string::npos and nextDash > 1) {
2588 tmp = tmp.substr (nextDash + 1);
2590 nextDash = tmp.find (
'-');
2591 string fontFamilyName = tmp.substr (0, nextDash);
2592 if (not fontFamilyName.empty ()) {
2593 fontNames.insert (fontFamilyName);
2597 ::XFreeFontNames (fontList);
2599 fFontNames = vector<string> (fontNames.begin (), fontNames.end ());
2605#if qStroika_Foundation_Common_Platform_Windows
2606BOOL FAR PASCAL InstalledFonts::FontFamilyAdderProc (ENUMLOGFONTEX* pelf, NEWTEXTMETRICEX* ,
int fontType, LPVOID pThis)
2608 InstalledFonts* thisP =
reinterpret_cast<InstalledFonts*
> (pThis);
2610 if (thisP->fFilterOptions & eSkipRasterFonts) {
2613 if (fontType & RASTER_FONTTYPE)
2616 if (thisP->fFilterOptions & eSkipAtSignFonts) {
2617 if (pelf->elfLogFont.lfFaceName[0] ==
'@')
2620 thisP->fFontNames.push_back (pelf->elfLogFont.lfFaceName);
2626#if qStroika_Frameworks_Led_SupportGDI
2634Globals* Globals::sThe =
nullptr;
2637class Globals::_Global_DESTRUCTOR_ {
2639 ~_Global_DESTRUCTOR_ ()
2641 delete (Globals::sThe);
2642 Globals::sThe =
nullptr;
2644} sTheLed_GDIGlobalsDESTRUCTOR_;
2650 InvalidateGlobals ();
2653void Globals::InvalidateGlobals ()
2657#if qStroika_Foundation_Common_Platform_MacOS
2660#elif qStroika_Foundation_Common_Platform_Windows
2661 WindowDC screenDC (
nullptr);
2662 fLogPixelsH = ::GetDeviceCaps (screenDC, LOGPIXELSX);
2663 fLogPixelsV = ::GetDeviceCaps (screenDC, LOGPIXELSY);
2664#elif qStroika_FeatureSupported_XWindows
2673 const int kResToUse = 100;
2674 fLogPixelsH = kResToUse;
2675 fLogPixelsV = kResToUse;
2680#if qStroika_Frameworks_Led_SupportGDI
2686void Led::AddRectangleToRegion (Led_Rect addRect, Region* toRgn)
2689 *toRgn = *toRgn + Region (addRect);
2703Led_Size Led::Led_GetDIBImageSize (
const Led_DIB* dib)
2706 Assert (
sizeof (BITMAPINFOHEADER) == 40);
2707 Assert (
sizeof (BITMAPCOREHEADER) == 12);
2708 Assert (
sizeof (RGBTRIPLE) == 3);
2710 if (IS_WIN30_DIB (dib)) {
2711 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
2712 return (Led_Size (abs (Led_ByteSwapFromWindows (hdr.biHeight)), abs (Led_ByteSwapFromWindows (hdr.biWidth))));
2715 const BITMAPCOREHEADER& hdr = *(
reinterpret_cast<const BITMAPCOREHEADER*
> (dib));
2716 return (Led_Size (Led_ByteSwapFromWindows (hdr.bcHeight), Led_ByteSwapFromWindows (hdr.bcWidth)));
2725size_t Led::Led_GetDIBPalletByteCount (
const Led_DIB* dib)
2736 if (IS_WIN30_DIB (dib)) {
2737 size_t byteCount = DIBNumColors (dib) *
sizeof (RGBQUAD);
2738 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
2740 if (Led_ByteSwapFromWindows (hdr.biCompression) == BI_BITFIELDS) {
2741#if qStroika_Foundation_Common_Platform_Windows
2742 Assert (
sizeof (DWORD) ==
sizeof (
unsigned int));
2744 Assert (4 ==
sizeof (
unsigned int));
2745 byteCount += 3 *
sizeof (
unsigned int);
2750 Assert (
sizeof (RGBTRIPLE) == 3);
2751 return (DIBNumColors (dib) *
sizeof (RGBTRIPLE));
2764size_t Led::Led_GetDIBImageRowByteCount (
const Led_DIB* dib)
2767 Led_Size imageSize = Led_GetDIBImageSize (dib);
2768 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
2770 unsigned short bitCount = Led_ByteSwapFromWindows (hdr.biBitCount);
2771 return (((imageSize.h * bitCount + 31) & ~31) >> 3);
2783size_t Led::Led_GetDIBImageByteCount (
const Led_DIB* dib)
2786 Led_Size imageSize = Led_GetDIBImageSize (dib);
2787 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
2788 size_t byteCount = Led_ByteSwapFromWindows (hdr.biSize);
2790 byteCount += Led_GetDIBPalletByteCount (dib);
2792 unsigned long imageByteSize = Led_ByteSwapFromWindows (hdr.biSizeImage);
2793 if (imageByteSize == 0) {
2794 unsigned short bitCount = Led_ByteSwapFromWindows (hdr.biBitCount);
2797 imageByteSize = imageSize.v * (((imageSize.h * bitCount + 31) & ~31) >> 3);
2799 byteCount += imageByteSize;
2813Led_DIB* Led::Led_CloneDIB (
const Led_DIB* dib)
2816 size_t nBytes = Led_GetDIBImageByteCount (dib);
2817 Led_DIB* newDIB =
reinterpret_cast<Led_DIB*
> (
new char[nBytes]);
2818 (void)::memcpy (newDIB, dib, nBytes);
2831const void* Led::Led_GetDIBBitsPointer (
const Led_DIB* dib)
2834 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
2835 return reinterpret_cast<const char*
> (dib) + Led_ByteSwapFromWindows (hdr.biSize) + Led_GetDIBPalletByteCount (dib);
2838#if qStroika_Foundation_Common_Platform_Windows
2844Led_DIB* Led::Led_DIBFromHBITMAP (HDC hDC, HBITMAP hbm)
2848 Verify (::GetObject (hbm,
sizeof (BITMAP), (LPVOID)&bm));
2850 Led_DIB* dibResult =
nullptr;
2852 BITMAPINFOHEADER bmiHdr;
2853 memset (&bmiHdr, 0,
sizeof (bmiHdr));
2854 bmiHdr.biSize =
sizeof (BITMAPINFOHEADER);
2855 bmiHdr.biWidth = bm.bmWidth;
2856 bmiHdr.biHeight = bm.bmHeight;
2857 bmiHdr.biPlanes = 1;
2858 bmiHdr.biBitCount = 24;
2859 bmiHdr.biCompression = BI_RGB;
2860 bmiHdr.biSizeImage = ((((bmiHdr.biWidth * bmiHdr.biBitCount) + 31) & ~31) >> 3) * bmiHdr.biHeight;
2861 size_t nBytes = Led_GetDIBImageByteCount (
reinterpret_cast<Led_DIB*
> (&bmiHdr));
2862 dibResult =
reinterpret_cast<Led_DIB*
> (
new char[nBytes]);
2863 Assert (nBytes >
sizeof (BITMAPINFOHEADER));
2865 (void)::memcpy (dibResult, &bmiHdr,
sizeof (bmiHdr));
2866 DISABLE_COMPILER_MSC_WARNING_END (6386)
2869 [[maybe_unused]]
int nScanLinesCopied =
2870 ::GetDIBits (hDC, hbm, 0, dibResult->bmiHeader.biHeight,
2871 reinterpret_cast<char*
> (dibResult) + Led_GetDIBPalletByteCount (dibResult) +
sizeof (BITMAPINFOHEADER), dibResult, DIB_RGB_COLORS);
2872 Assert (nScanLinesCopied == dibResult->bmiHeader.biHeight);
2877#if qStroika_Frameworks_Led_ProvideIMESupport
2885IME* IME::sThe =
nullptr;
2887#ifndef qUseNewIMECode
2888#define qUseNewIMECode 1
2892class IME::_Global_DESTRUCTOR_ {
2894 ~_Global_DESTRUCTOR_ ()
2897 IME::sThe =
nullptr;
2899} sTheIME_DESTRUCTOR_;
2902 : fSendIMEMessageProc (nullptr)
2903 , fIMEEnableProc (nullptr)
2904 , fImmGetContext (nullptr)
2905 , fImmSetCompositionFont (nullptr)
2906 , fImmReleaseContext (nullptr)
2907 , fImmGetCompositionStringW (nullptr)
2908 , fImmSetCompositionWindow (nullptr)
2909 , fImmSetOpenStatus (nullptr)
2910 , fWinNlsAvailable (false)
2914 Assert (sThe ==
nullptr);
2918 const char IMEPROCNAME[] =
"SendIMEMessageExW";
2920 const char IMEPROCNAME[] =
"SendIMEMessageExA";
2922 HINSTANCE hNLS = ::GetModuleHandle (_T (
"USER32.DLL"));
2923 if (hNLS !=
nullptr) {
2924 fSendIMEMessageProc = (LRESULT (FAR PASCAL*) (HWND, DWORD))::GetProcAddress (hNLS, IMEPROCNAME);
2925 fIMEEnableProc = (BOOL (FAR PASCAL*) (HWND, BOOL))::GetProcAddress (hNLS,
"WINNLSEnableIME");
2927 fWinNlsAvailable = fSendIMEMessageProc !=
nullptr and fIMEEnableProc !=
nullptr;
2929 HINSTANCE hIMM = ::GetModuleHandle (_T (
"IMM32.DLL"));
2930 if (hIMM !=
nullptr) {
2932 constexpr char ImmSetCompositionFontNAME[] =
"ImmSetCompositionFontW";
2934 constexpr char ImmSetCompositionFontNAME[] =
"ImmSetCompositionFontA";
2936 fImmGetContext = (HIMC (FAR PASCAL*) (HWND))::GetProcAddress (hIMM,
"ImmGetContext");
2937 fImmSetCompositionFont = (BOOL (FAR PASCAL*) (HIMC,
const LOGFONT*))::GetProcAddress (hIMM, ImmSetCompositionFontNAME);
2938 fImmReleaseContext = (BOOL (FAR PASCAL*) (HWND, HIMC))::GetProcAddress (hIMM,
"ImmReleaseContext");
2939 fImmGetCompositionStringW = (LONG (FAR PASCAL*) (HIMC, DWORD, LPVOID, DWORD))::GetProcAddress (hIMM,
"ImmGetCompositionStringW");
2940 fImmSetCompositionWindow = (BOOL (FAR PASCAL*) (HIMC,
const void*))::GetProcAddress (hIMM,
"ImmSetCompositionWindow");
2941 fImmSetOpenStatus = (BOOL (FAR PASCAL*) (HIMC, BOOL))::GetProcAddress (hIMM,
"ImmSetOpenStatus");
2945void IME::NotifyPosition (HWND hWnd,
const SHORT x,
const SHORT y)
2947 if (x != fLastX || y != fLastY) {
2948 UpdatePosition (hWnd, x, y);
2952void IME::NotifyOfFontChange (HWND hWnd,
const LOGFONT& lf)
2954 if (fImmGetContext !=
nullptr and fImmSetCompositionFont !=
nullptr and fImmReleaseContext !=
nullptr) {
2956 if ((hImc = fImmGetContext (hWnd)) != NULL) {
2957 fImmSetCompositionFont (hImc, &lf);
2958 fImmReleaseContext (hWnd, hImc);
2964void IME::SendSimpleMessage (HWND hWnd, UINT fnc, WPARAM wParam)
2966 if (fSendIMEMessageProc !=
nullptr) {
2967 HANDLE hime = ::GlobalAlloc (GMEM_MOVEABLE | GMEM_LOWER | GMEM_DDESHARE, (DWORD)
sizeof (IMESTRUCT));
2970 lpime = (LPIMESTRUCT)GlobalLock (hime);
2974 if (lpime ==
nullptr) {
2979 lpime->wParam = wParam;
2980 fSendIMEMessageProc (hWnd, (LONG)hime);
2981 wParam = lpime->wParam;
2982 ::GlobalUnlock (hime);
2983 ::GlobalFree (hime);
2988void IME::IMEOn (HWND hWnd)
2991 if (fImmGetContext !=
nullptr and fImmSetOpenStatus !=
nullptr and fImmReleaseContext !=
nullptr) {
2993 if ((hImc = fImmGetContext (hWnd)) != NULL) {
2994 Verify (fImmSetOpenStatus (hImc,
true));
2995 fImmReleaseContext (hWnd, hImc);
2999 SendSimpleMessage (hWnd, IME_SETOPEN, 1);
3003void IME::IMEOff (HWND hWnd)
3006 if (fImmGetContext !=
nullptr and fImmSetOpenStatus !=
nullptr and fImmReleaseContext !=
nullptr) {
3008 if ((hImc = fImmGetContext (hWnd)) != NULL) {
3009 Verify (fImmSetOpenStatus (hImc,
false));
3010 fImmReleaseContext (hWnd, hImc);
3014 SendSimpleMessage (hWnd, IME_SETOPEN, 0);
3018void IME::UpdatePosition (
const HWND hWnd,
const SHORT x,
const SHORT y)
3020 if (fSendIMEMessageProc !=
nullptr) {
3022 if (fImmGetContext !=
nullptr and fImmSetCompositionWindow !=
nullptr and fImmReleaseContext !=
nullptr) {
3024 if ((hImc = fImmGetContext (hWnd)) != NULL) {
3025 COMPOSITIONFORM compForm;
3026 memset (&compForm, 0,
sizeof (compForm));
3027 compForm.dwStyle = CFS_FORCE_POSITION;
3028 compForm.ptCurrentPos.x = x;
3029 compForm.ptCurrentPos.y = y;
3030 Verify (fImmSetCompositionWindow (hImc, &compForm));
3031 fImmReleaseContext (hWnd, hImc);
3037 HANDLE hime = ::GlobalAlloc (GMEM_MOVEABLE | GMEM_LOWER | GMEM_DDESHARE, (DWORD)
sizeof (IMESTRUCT));
3038 LPIMESTRUCT lpime =
nullptr;
3039 if (hime !=
nullptr) {
3040 lpime = (LPIMESTRUCT)GlobalLock (hime);
3046 if (lpime ==
nullptr) {
3050 lpime->fnc = IME_SETCONVERSIONWINDOW;
3051 lpime->wParam = MCW_WINDOW;
3053 lpime->dchSource = 0;
3055 lpime->lParam1 = MAKELONG (x, y);
3056 lpime->lParam2 = 0L;
3057 lpime->lParam3 = 0L;
3061 short ret = fSendIMEMessageProc (hWnd, (LONG)hime);
3062 ret = ret ? 0 : (short)lpime->wParam;
3064 ::GlobalUnlock (hime);
3065 ::GlobalFree (hime);
3073 if (fImmGetContext !=
nullptr and fImmSetCompositionFont !=
nullptr and fImmReleaseContext !=
nullptr) {
3074 HFONT hFont =
nullptr;
3075 if ((hFont = (HFONT)::SendMessage (hWnd, WM_GETFONT, 0, 0L)) !=
nullptr) {
3077 if (::GetObject (hFont,
sizeof (LOGFONT), &lFont)) {
3079 if ((hImc = fImmGetContext (hWnd)) != NULL) {
3080 fImmSetCompositionFont (hImc, &lFont);
3081 fImmReleaseContext (hWnd, hImc);
3089wstring IME::GetCompositionResultStringW (HWND hWnd)
3092 if (fImmGetCompositionStringW !=
nullptr and fImmGetContext !=
nullptr and fImmReleaseContext !=
nullptr) {
3094 if ((hImc = fImmGetContext (hWnd)) != 0) {
3095 wchar_t curIMEString[2048];
3096 LONG nChars = fImmGetCompositionStringW (hImc, GCS_RESULTSTR, curIMEString,
static_cast<DWORD
> (Memory::NEltsOf (curIMEString)));
3098 nChars /=
sizeof (wchar_t);
3099 if (nChars >= 0 and
static_cast<size_t> (nChars) < Memory::NEltsOf (curIMEString)) {
3100 curIMEString[nChars] =
'\0';
3103 curIMEString[0] =
'\0';
3105 result = curIMEString;
3106 fImmReleaseContext (hWnd, hImc);
3113Led_Rect Led::CenterRectInRect (
const Led_Rect& r,
const Led_Rect& centerIn)
3115 CoordinateType xLeft = (centerIn.left + centerIn.right) / 2 - r.GetWidth () / 2;
3116 CoordinateType yTop = (centerIn.top + centerIn.bottom) / 2 - r.GetHeight () / 2;
3117 return Led_Rect (yTop, xLeft, r.GetHeight (), r.GetWidth ());
3120#if qStroika_Foundation_Common_Platform_Windows
3121void Led::Led_CenterWindowInParent (HWND w)
3123 Assert (::IsWindow (w));
3124 HWND hWndCenter = ::GetWindow (w, GW_OWNER);
3125 if (hWndCenter ==
nullptr) {
3126 hWndCenter = ::GetDesktopWindow ();
3128 Assert (::IsWindow (hWndCenter));
3132 ::GetWindowRect (w, &rcDlg);
3134 ::GetWindowRect (hWndCenter, &rcCenter);
3137 int xLeft = (rcCenter.left + rcCenter.right) / 2 - AsLedRect (rcDlg).GetWidth () / 2;
3138 int yTop = (rcCenter.top + rcCenter.bottom) / 2 - AsLedRect (rcDlg).GetHeight () / 2;
3141 ::SetWindowPos (w,
nullptr, xLeft, yTop, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
3147#if qStroika_Foundation_Common_Platform_Windows && qUseFakeTTGetWPlacementToImage
3160#define SWAPWORD(x) MAKEWORD (HIBYTE (x), LOBYTE (x))
3161#define SWAPLONG(x) MAKELONG (SWAPWORD (HIWORD (x)), SWAPWORD (LOWORD (x)))
3169 USHORT entrySelector;
3174using LPCMAP4 = CMAP4*;
3182#define CMAPHEADERSIZE (sizeof (USHORT) * 2)
3191#define ENCODINGSIZE (sizeof (USHORT) * 2 + sizeof (ULONG))
3193struct CMAPENCODING {
3200#define MAKETABLENAME(ch1, ch2, ch3, ch4) ((((DWORD)(ch4)) << 24) | (((DWORD)(ch3)) << 16) | (((DWORD)(ch2)) << 8) | ((DWORD)(ch1)))
3203static USHORT GetTTUnicodeGlyphIndex (HDC hdc, USHORT ch);
3207static DWORD dwCmapName = MAKETABLENAME (
'c',
'm',
'a',
'p');
3209static USHORT* GetEndCountArray (LPBYTE pBuff)
3211 return (USHORT*)(pBuff + 7 *
sizeof (USHORT));
3214static USHORT* GetStartCountArray (LPBYTE pBuff)
3216 DWORD segCount = ((LPCMAP4)pBuff)->segCountX2 / 2;
3217 return (USHORT*)(pBuff + 8 *
sizeof (USHORT) +
3218 segCount *
sizeof (USHORT));
3221static USHORT* GetIdDeltaArray (LPBYTE pBuff)
3223 DWORD segCount = ((LPCMAP4)pBuff)->segCountX2 / 2;
3224 return (USHORT*)(pBuff + 8 *
sizeof (USHORT) +
3225 segCount * 2 *
sizeof (USHORT));
3228static USHORT* GetIdRangeOffsetArray (LPBYTE pBuff)
3230 DWORD segCount = ((LPCMAP4)pBuff)->segCountX2 / 2;
3231 return (USHORT*)(pBuff + 8 *
sizeof (USHORT) +
3232 segCount * 3 *
sizeof (USHORT));
3235static void SwapArrays (LPCMAP4 pFormat4)
3237 DWORD segCount = pFormat4->segCountX2 / 2;
3239 USHORT *pGlyphId, *pEndOfBuffer, *pstartCount = GetStartCountArray ((LPBYTE)pFormat4), *pidDelta = GetIdDeltaArray ((LPBYTE)pFormat4),
3240 *pidRangeOffset = GetIdRangeOffsetArray ((LPBYTE)pFormat4), *pendCount = GetEndCountArray ((LPBYTE)pFormat4);
3243 for (i = 0; i < segCount; ++i) {
3244 pendCount[i] = SWAPWORD (pendCount[i]);
3245 pstartCount[i] = SWAPWORD (pstartCount[i]);
3246 pidDelta[i] = SWAPWORD (pidDelta[i]);
3247 pidRangeOffset[i] = SWAPWORD (pidRangeOffset[i]);
3251 pGlyphId = pidRangeOffset + segCount;
3252 pEndOfBuffer = (USHORT*)((LPBYTE)pFormat4 + pFormat4->length);
3253 for (; pGlyphId < pEndOfBuffer; ++pGlyphId) {
3254 *pGlyphId = SWAPWORD (*pGlyphId);
3258static BOOL GetFontEncoding (HDC hdc, CMAPENCODING* pEncoding,
int iEncoding)
3265 BOOL fSuccess = TRUE;
3268 dwResult = GetFontData (hdc, dwCmapName, CMAPHEADERSIZE + ENCODINGSIZE * iEncoding, pEncoding,
sizeof (CMAPENCODING));
3269 fSuccess = (dwResult ==
sizeof (CMAPENCODING));
3272 pEncoding->PlatformId = SWAPWORD (pEncoding->PlatformId);
3275 pEncoding->EncodingId = SWAPWORD (pEncoding->EncodingId);
3278 pEncoding->Offset = SWAPLONG (pEncoding->Offset);
3284static BOOL GetFontFormat4Header (HDC hdc, LPCMAP4 pFormat4, DWORD dwOffset)
3290 BOOL fSuccess = TRUE;
3296 pField = (USHORT*)pFormat4;
3298 for (i = 0; i < 7; ++i) {
3300 dwResult = GetFontData (hdc, dwCmapName, dwOffset +
sizeof (USHORT) * i, pField,
sizeof (USHORT));
3303 *pField = SWAPWORD (*pField);
3307 fSuccess = (dwResult ==
sizeof (USHORT)) && fSuccess;
3314static BOOL GetFontFormat4Subtable (HDC hdc,
3315 LPCMAP4 pFormat4Subtable,
3323 if (!GetFontFormat4Header (hdc, pFormat4Subtable, dwOffset)) {
3328 length = pFormat4Subtable->length - (7 *
sizeof (USHORT));
3329 dwResult = GetFontData (hdc, dwCmapName,
3330 dwOffset + 7 *
sizeof (USHORT),
3331 (LPBYTE)pFormat4Subtable->Arrays,
3334 if (dwResult != length) {
3340 SwapArrays (pFormat4Subtable);
3345static BOOL GetTTUnicodeCoverage (HDC hdc,
3362 CMAPENCODING Encoding{};
3367 LPCMAP4 pFormat4Subtable;
3371 dwResult = GetFontData (hdc, dwCmapName,
sizeof (USHORT), &nEncodings,
sizeof (USHORT));
3372 nEncodings = SWAPWORD (nEncodings);
3374 if (dwResult !=
sizeof (USHORT)) {
3382 iUnicode = nEncodings;
3383 for (i = 0; i < nEncodings; ++i) {
3385 if (!GetFontEncoding (hdc, &Encoding, i)) {
3405 if (Encoding.PlatformId == 3 && (Encoding.EncodingId == 1 || Encoding.EncodingId == 0)) {
3411 if (iUnicode >= nEncodings) {
3418 if (!GetFontFormat4Header (hdc, &Format4, Encoding.Offset)) {
3424 if (Format4.format != 4) {
3434 *pcbNeeded = Format4.length;
3435 if (*pcbNeeded > cbSize || pBuffer ==
nullptr) {
3443 pFormat4Subtable = (LPCMAP4)malloc (Format4.length);
3444 if (pFormat4Subtable ==
nullptr) {
3451 if (!GetFontFormat4Subtable (hdc, pFormat4Subtable, Encoding.Offset)) {
3458 CopyMemory (pBuffer, pFormat4Subtable, pFormat4Subtable->length);
3460 free (pFormat4Subtable);
3464static BOOL FindFormat4Segment (LPCMAP4 pTable,
3477 USHORT i, segCount = pTable->segCountX2 / 2;
3478 USHORT* pendCount = GetEndCountArray ((LPBYTE)pTable);
3479 USHORT* pstartCount = GetStartCountArray ((LPBYTE)pTable);
3482 for (i = 0; i < segCount && pendCount[i] < ch; ++i)
3490 if (pstartCount[i] > ch)
3498static USHORT GetTTUnicodeGlyphIndex (HDC hdc,
3509 LPCMAP4 pUnicodeCMapTable;
3512 USHORT* idRangeOffset;
3515 USHORT GlyphIndex = 0;
3518 GetTTUnicodeCoverage (hdc,
nullptr, 0, &dwSize);
3519 pUnicodeCMapTable = (LPCMAP4)malloc (dwSize);
3520 if (!GetTTUnicodeCoverage (hdc, pUnicodeCMapTable, dwSize, &dwSize)) {
3523 free (pUnicodeCMapTable);
3528 if (!FindFormat4Segment (pUnicodeCMapTable, ch, &iSegment)) {
3529 free (pUnicodeCMapTable);
3534 idRangeOffset = GetIdRangeOffsetArray ((LPBYTE)pUnicodeCMapTable);
3535 idDelta = GetIdDeltaArray ((LPBYTE)pUnicodeCMapTable);
3536 startCount = GetStartCountArray ((LPBYTE)pUnicodeCMapTable);
3539 if (idRangeOffset[iSegment] == 0) {
3541 GlyphIndex = (idDelta[iSegment] + ch) % 65536;
3547 idResult = *(idRangeOffset[iSegment] / 2 + (ch - startCount[iSegment]) + &idRangeOffset[iSegment]);
3550 GlyphIndex = (idDelta[iSegment] + idResult) % 65536;
3556 free (pUnicodeCMapTable);
3560static bool Win9x_Workaround_GetCharPlacementFunction (HDC hdc,
const wchar_t* srcText,
size_t len,
wchar_t* glyphImagesOut)
3571 for (
size_t i = 0; i < len; ++i) {
3572 glyphImagesOut[i] = GetTTUnicodeGlyphIndex (hdc, srcText[i]);
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
#define RequireNotNull(p)
nonvirtual tuple< const wchar_t *, wstring_view > c_str(Memory::StackBuffer< wchar_t > *possibleBackingStore) const
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
conditional_t< qTargetPlatformSDKUseswchar_t, wchar_t, char > SDKChar
basic_string< SDKChar > SDKString
DISABLE_COMPILER_MSC_WARNING_START(4996)
void ThrowIfNull(const Private_::ConstVoidStar &p, const HRESULT &hr)
Template specialization for ThrowIfNull (), for thing being thrown HRESULT - really throw HRESULTErro...