OSDN Git Service

Fix crash when registry is set to an unexpected value
[winmerge-jp/winmerge-jp.git] / Src / OptionsFont.cpp
1 /** 
2  * @file  OptionsFont.cpp
3  *
4  * @brief Implementation for Options::Font class.
5  */
6 #include "pch.h"
7 #include "OptionsFont.h"
8 #include "unicoder.h"
9 #include "ExConverter.h"
10 #include "OptionsDef.h"
11 #include "OptionsMgr.h"
12 #include <cassert>
13
14 namespace Options { namespace Font {
15
16 /**
17  * @brief Initialize basic default values in a LOGFONT structure. 
18  * A helper function for SetDefaults(); it should not be used otherwise.
19  */
20 void InitializeLogFont(LOGFONT &logfont, int lfHeight, int lfCharSet, int lfPitchAndFamily, String lfFaceName)
21 {
22         logfont.lfHeight = lfHeight;
23         logfont.lfWidth = 0;
24         logfont.lfEscapement = 0;
25         logfont.lfOrientation = 0;
26         logfont.lfWeight = FW_NORMAL;
27         logfont.lfItalic = false;
28         logfont.lfUnderline = false;
29         logfont.lfStrikeOut = false;
30         logfont.lfCharSet = static_cast<BYTE>(lfCharSet);
31         logfont.lfOutPrecision = OUT_STRING_PRECIS;
32         logfont.lfClipPrecision = CLIP_STROKE_PRECIS;
33         logfont.lfQuality = DRAFT_QUALITY;
34         logfont.lfPitchAndFamily = static_cast<BYTE>(lfPitchAndFamily);
35         lstrcpyn(logfont.lfFaceName, lfFaceName.c_str(), (sizeof(logfont.lfFaceName)/sizeof(logfont.lfFaceName[0])) );
36 }
37
38 /**
39  * @brief Initialize the in-memory Options::Font structure (and possibly the related Registry entries)
40  * for both File-Contents and Directory-Tree windows.
41  */
42 void SetDefaults(COptionsMgr *pOptionsMgr)
43 {
44         HDC hDC = GetDC(nullptr);
45         const int logPixelsY = GetDeviceCaps(hDC, LOGPIXELSY);
46
47         // *****
48         // File-Contents windows use fixed-width fonts.  Here we discover the 
49         // correct default fontname from the system code page, if possible.  The 
50         // default size is 12 points.  If a fontname cannot be found (why?),   
51         // "Courier New" will be used for the fontname.
52         LOGFONT fontFile = {0};
53         const int pointsFile = 12;
54
55         CodePageInfo cpi = {0};
56         IExconverter *pexconv = Exconverter::getInstance();
57         if (pexconv==nullptr || !pexconv->getCodePageInfo(GetACP(), &cpi)
58                 || cpi.proportionalFont == cpi.fixedWidthFont)
59         {
60                 cpi.bGDICharset = ANSI_CHARSET;
61                 cpi.fixedWidthFont = _T("Courier New");
62         }
63         InitializeLogFont(fontFile, -::MulDiv(pointsFile, logPixelsY, 72), cpi.bGDICharset, FF_MODERN | FIXED_PITCH, cpi.fixedWidthFont);
64
65         
66         // *****
67         // The Directory-Tree window uses (by default) the program's Menu font and size;  if 
68         // that cannot be determined (why?), 9-point "Segoe UI" is used (typical since Win7).
69         LOGFONT fontDir = {0};
70         const int pointsDir = 9;
71         NONCLIENTMETRICS ncm = { 0 };
72         ncm.cbSize = sizeof(NONCLIENTMETRICS);
73         if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0))
74         {
75                 const int lfHeight = -::MulDiv(pointsDir, logPixelsY, 72);
76                 fontDir = ncm.lfMenuFont;
77                 if (abs(fontDir.lfHeight) > abs(lfHeight))
78                         fontDir.lfHeight = lfHeight;
79                 if (wcscmp(fontDir.lfFaceName, L"Meiryo") == 0 || wcscmp(fontDir.lfFaceName, L"\U000030e1\U000030a4\U000030ea\U000030aa"/* "Meiryo" in Japanese */) == 0)
80                         wcscpy_s(fontDir.lfFaceName, L"Meiryo UI");
81         }
82         else
83         {       
84                 // in the case of Windows XP
85                 InitializeLogFont(fontDir, -::MulDiv(pointsDir, logPixelsY, 72), DEFAULT_CHARSET, FF_DONTCARE, L"Segoe UI");
86         }
87         
88         // *****
89         // The values generated above are used as the 'default' Options::Font values.  The 'actual' value 
90         // for each option is obtained from the Registry, if the entry exists.  If the Registry entry
91         // does not exist, it is built using this given 'default' value and the 'actual' value becomes
92         // the same as the 'default'.
93         for (int i = 0; i < 2; ++i)
94         {
95                 LOGFONT thisFont = (i == 0 ? fontFile : fontDir);
96                 String name = (i == 0 ? OPT_FONT_FILECMP : OPT_FONT_DIRCMP);
97
98                 pOptionsMgr->InitOption(name + OPT_FONT_USECUSTOM, false);
99                 pOptionsMgr->InitOption(name + OPT_FONT_POINTSIZE, ::MulDiv(abs(thisFont.lfHeight), 72, logPixelsY), 1, 72);
100                 pOptionsMgr->InitOption(name + OPT_FONT_HEIGHT, thisFont.lfHeight);
101                 pOptionsMgr->InitOption(name + OPT_FONT_ESCAPEMENT, thisFont.lfEscapement);
102                 pOptionsMgr->InitOption(name + OPT_FONT_ORIENTATION, thisFont.lfOrientation);
103                 pOptionsMgr->InitOption(name + OPT_FONT_WEIGHT, thisFont.lfWeight);
104                 pOptionsMgr->InitOption(name + OPT_FONT_ITALIC, thisFont.lfItalic != 0);
105                 pOptionsMgr->InitOption(name + OPT_FONT_UNDERLINE, thisFont.lfUnderline != 0);
106                 pOptionsMgr->InitOption(name + OPT_FONT_STRIKEOUT, thisFont.lfStrikeOut != 0);
107                 pOptionsMgr->InitOption(name + OPT_FONT_CHARSET, thisFont.lfCharSet);
108                 pOptionsMgr->InitOption(name + OPT_FONT_OUTPRECISION, thisFont.lfOutPrecision);
109                 pOptionsMgr->InitOption(name + OPT_FONT_CLIPPRECISION, thisFont.lfClipPrecision);
110                 pOptionsMgr->InitOption(name + OPT_FONT_QUALITY, thisFont.lfQuality);
111                 pOptionsMgr->InitOption(name + OPT_FONT_PITCHANDFAMILY, thisFont.lfPitchAndFamily);
112                 pOptionsMgr->InitOption(name + OPT_FONT_FACENAME, ucr::toTString(thisFont.lfFaceName));
113         }
114         ReleaseDC(nullptr, hDC);
115 }
116
117 LOGFONT Load(const COptionsMgr *pOptionsMgr, const String& name)
118 {
119         // Build a new LOGFONT with values from the 'actual' values of the in-memory Options::Font table.
120         // The Registry is not accessed.
121         LOGFONT lfnew = { 0 };
122         HDC hDC = GetDC(nullptr);
123         lfnew.lfHeight = -MulDiv(pOptionsMgr->GetInt(name + OPT_FONT_POINTSIZE), GetDeviceCaps(hDC, LOGPIXELSY), 72);
124         if (lfnew.lfHeight == 0)
125                 lfnew.lfHeight = pOptionsMgr->GetInt(name + OPT_FONT_HEIGHT);
126         lfnew.lfWidth = 0;
127         lfnew.lfEscapement = pOptionsMgr->GetInt(name + OPT_FONT_ESCAPEMENT);
128         lfnew.lfOrientation = pOptionsMgr->GetInt(name + OPT_FONT_ORIENTATION);
129         lfnew.lfWeight = pOptionsMgr->GetInt(name + OPT_FONT_WEIGHT);
130         lfnew.lfItalic = pOptionsMgr->GetBool(name + OPT_FONT_ITALIC);
131         lfnew.lfUnderline = pOptionsMgr->GetBool(name + OPT_FONT_UNDERLINE);
132         lfnew.lfStrikeOut = pOptionsMgr->GetBool(name + OPT_FONT_STRIKEOUT);
133         lfnew.lfCharSet = static_cast<BYTE>(pOptionsMgr->GetInt(name + OPT_FONT_CHARSET));
134         lfnew.lfOutPrecision = static_cast<BYTE>(pOptionsMgr->GetInt(name + OPT_FONT_OUTPRECISION));
135         lfnew.lfClipPrecision = static_cast<BYTE>(pOptionsMgr->GetInt(name + OPT_FONT_CLIPPRECISION));
136         lfnew.lfQuality = static_cast<BYTE>(pOptionsMgr->GetInt(name + OPT_FONT_QUALITY));
137         lfnew.lfPitchAndFamily = static_cast<BYTE>(pOptionsMgr->GetInt(name + OPT_FONT_PITCHANDFAMILY));
138         lstrcpyn(lfnew.lfFaceName,
139                 pOptionsMgr->GetString(name + OPT_FONT_FACENAME).c_str(), sizeof(lfnew.lfFaceName)/sizeof(lfnew.lfFaceName[0]));
140         ReleaseDC(nullptr, hDC);
141         return lfnew;
142 }
143
144 void Save(COptionsMgr *pOptionsMgr, const String& name, const LOGFONT* lf, bool bUseCustom)
145 {
146         // Store LOGFONT values into both the 'actual' value of the in-memory Options::Font table, and 
147         // into the appropriate Registry entries.
148         HDC hDC = GetDC(nullptr);
149         pOptionsMgr->SaveOption(name + OPT_FONT_USECUSTOM, bUseCustom);
150         pOptionsMgr->SaveOption(name + OPT_FONT_POINTSIZE, -MulDiv(lf->lfHeight, 72, GetDeviceCaps(hDC, LOGPIXELSY)));
151         pOptionsMgr->SaveOption(name + OPT_FONT_HEIGHT, lf->lfHeight);
152         pOptionsMgr->SaveOption(name + OPT_FONT_ESCAPEMENT, lf->lfEscapement);
153         pOptionsMgr->SaveOption(name + OPT_FONT_ORIENTATION, lf->lfOrientation);
154         pOptionsMgr->SaveOption(name + OPT_FONT_WEIGHT, lf->lfWeight);
155         pOptionsMgr->SaveOption(name + OPT_FONT_ITALIC, lf->lfItalic != 0);
156         pOptionsMgr->SaveOption(name + OPT_FONT_UNDERLINE, lf->lfUnderline != 0);
157         pOptionsMgr->SaveOption(name + OPT_FONT_STRIKEOUT, lf->lfStrikeOut != 0);
158         pOptionsMgr->SaveOption(name + OPT_FONT_CHARSET, lf->lfCharSet);
159         pOptionsMgr->SaveOption(name + OPT_FONT_OUTPRECISION, lf->lfOutPrecision);
160         pOptionsMgr->SaveOption(name + OPT_FONT_CLIPPRECISION, lf->lfClipPrecision);
161         pOptionsMgr->SaveOption(name + OPT_FONT_QUALITY, lf->lfQuality);
162         pOptionsMgr->SaveOption(name + OPT_FONT_PITCHANDFAMILY, (int)lf->lfPitchAndFamily);
163         pOptionsMgr->SaveOption(name + OPT_FONT_FACENAME, lf->lfFaceName);
164         ReleaseDC(nullptr, hDC);
165 }
166
167 void Reset(COptionsMgr *pOptionsMgr, const String& name)
168 {
169         // Resets the in-memory Options::Font 'actual' values to be original 'default' values.
170         // The Registry values are not modified, except to turn off the OPT_FONT_USECUSTOM 
171         // Registry entry.
172         pOptionsMgr->SaveOption(name + OPT_FONT_USECUSTOM, false);
173         pOptionsMgr->Reset(name + OPT_FONT_POINTSIZE);
174         pOptionsMgr->Reset(name + OPT_FONT_HEIGHT);
175         pOptionsMgr->Reset(name + OPT_FONT_ESCAPEMENT);
176         pOptionsMgr->Reset(name + OPT_FONT_ORIENTATION);
177         pOptionsMgr->Reset(name + OPT_FONT_WEIGHT);
178         pOptionsMgr->Reset(name + OPT_FONT_ITALIC);
179         pOptionsMgr->Reset(name + OPT_FONT_UNDERLINE);
180         pOptionsMgr->Reset(name + OPT_FONT_STRIKEOUT);
181         pOptionsMgr->Reset(name + OPT_FONT_CHARSET);
182         pOptionsMgr->Reset(name + OPT_FONT_OUTPRECISION);
183         pOptionsMgr->Reset(name + OPT_FONT_CLIPPRECISION);
184         pOptionsMgr->Reset(name + OPT_FONT_QUALITY);
185         pOptionsMgr->Reset(name + OPT_FONT_PITCHANDFAMILY);
186         pOptionsMgr->Reset(name + OPT_FONT_FACENAME);
187 }
188
189 }
190 }