|
|
@@ -71803,7 +71803,7 @@ int PopupMenu::getNumItems() const noexcept |
|
|
|
int num = 0; |
|
|
|
|
|
|
|
for (int i = items.size(); --i >= 0;) |
|
|
|
if (! (items.getUnchecked(i))->isSeparator) |
|
|
|
if (! items.getUnchecked(i)->isSeparator) |
|
|
|
++num; |
|
|
|
|
|
|
|
return num; |
|
|
@@ -246395,41 +246395,44 @@ void MessageManager::doPlatformSpecificShutdown() |
|
|
|
// compiled on its own). |
|
|
|
#if JUCE_INCLUDED_FILE |
|
|
|
|
|
|
|
static int CALLBACK wfontEnum2 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) |
|
|
|
namespace FontEnumerators |
|
|
|
{ |
|
|
|
if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0) |
|
|
|
int CALLBACK fontEnum2 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) |
|
|
|
{ |
|
|
|
const String fontName (lpelfe->elfLogFont.lfFaceName); |
|
|
|
if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0) |
|
|
|
{ |
|
|
|
const String fontName (lpelfe->elfLogFont.lfFaceName); |
|
|
|
|
|
|
|
((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters ("@")); |
|
|
|
} |
|
|
|
((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters ("@")); |
|
|
|
} |
|
|
|
|
|
|
|
return 1; |
|
|
|
} |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
static int CALLBACK wfontEnum1 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) |
|
|
|
{ |
|
|
|
if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0) |
|
|
|
int CALLBACK fontEnum1 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) |
|
|
|
{ |
|
|
|
LOGFONTW lf = { 0 }; |
|
|
|
lf.lfWeight = FW_DONTCARE; |
|
|
|
lf.lfOutPrecision = OUT_OUTLINE_PRECIS; |
|
|
|
lf.lfQuality = DEFAULT_QUALITY; |
|
|
|
lf.lfCharSet = DEFAULT_CHARSET; |
|
|
|
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; |
|
|
|
lf.lfPitchAndFamily = FF_DONTCARE; |
|
|
|
if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0) |
|
|
|
{ |
|
|
|
LOGFONTW lf = { 0 }; |
|
|
|
lf.lfWeight = FW_DONTCARE; |
|
|
|
lf.lfOutPrecision = OUT_OUTLINE_PRECIS; |
|
|
|
lf.lfQuality = DEFAULT_QUALITY; |
|
|
|
lf.lfCharSet = DEFAULT_CHARSET; |
|
|
|
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; |
|
|
|
lf.lfPitchAndFamily = FF_DONTCARE; |
|
|
|
|
|
|
|
const String fontName (lpelfe->elfLogFont.lfFaceName); |
|
|
|
fontName.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName)); |
|
|
|
const String fontName (lpelfe->elfLogFont.lfFaceName); |
|
|
|
fontName.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName)); |
|
|
|
|
|
|
|
HDC dc = CreateCompatibleDC (0); |
|
|
|
EnumFontFamiliesEx (dc, &lf, |
|
|
|
(FONTENUMPROCW) &wfontEnum2, |
|
|
|
lParam, 0); |
|
|
|
DeleteDC (dc); |
|
|
|
} |
|
|
|
HDC dc = CreateCompatibleDC (0); |
|
|
|
EnumFontFamiliesEx (dc, &lf, |
|
|
|
(FONTENUMPROCW) &fontEnum2, |
|
|
|
lParam, 0); |
|
|
|
DeleteDC (dc); |
|
|
|
} |
|
|
|
|
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
StringArray Font::findAllTypefaceNames() |
|
|
@@ -246447,7 +246450,7 @@ StringArray Font::findAllTypefaceNames() |
|
|
|
lf.lfPitchAndFamily = FF_DONTCARE; |
|
|
|
|
|
|
|
EnumFontFamiliesEx (dc, &lf, |
|
|
|
(FONTENUMPROCW) &wfontEnum1, |
|
|
|
(FONTENUMPROCW) &FontEnumerators::fontEnum1, |
|
|
|
(LPARAM) &results, 0); |
|
|
|
} |
|
|
|
|
|
|
@@ -246477,123 +246480,21 @@ void Font::getPlatformDefaultFontNames (String& defaultSans, String& defaultSeri |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
class FontDCHolder : private DeletedAtShutdown |
|
|
|
{ |
|
|
|
public: |
|
|
|
|
|
|
|
FontDCHolder() |
|
|
|
: fontH (0), previousFontH (0), dc (0), numKPs (0), size (0), |
|
|
|
bold (false), italic (false) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
~FontDCHolder() |
|
|
|
{ |
|
|
|
deleteDCAndFont(); |
|
|
|
clearSingletonInstance(); |
|
|
|
} |
|
|
|
|
|
|
|
juce_DeclareSingleton_SingleThreaded_Minimal (FontDCHolder); |
|
|
|
|
|
|
|
HDC loadFont (const String& fontName_, const bool bold_, const bool italic_, const int size_) |
|
|
|
{ |
|
|
|
if (fontName != fontName_ || bold != bold_ || italic != italic_ || size != size_) |
|
|
|
{ |
|
|
|
fontName = fontName_; |
|
|
|
bold = bold_; |
|
|
|
italic = italic_; |
|
|
|
size = size_; |
|
|
|
|
|
|
|
deleteDCAndFont(); |
|
|
|
|
|
|
|
dc = CreateCompatibleDC (0); |
|
|
|
SetMapperFlags (dc, 0); |
|
|
|
SetMapMode (dc, MM_TEXT); |
|
|
|
|
|
|
|
LOGFONTW lf = { 0 }; |
|
|
|
lf.lfCharSet = DEFAULT_CHARSET; |
|
|
|
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; |
|
|
|
lf.lfOutPrecision = OUT_OUTLINE_PRECIS; |
|
|
|
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; |
|
|
|
lf.lfQuality = PROOF_QUALITY; |
|
|
|
lf.lfItalic = (BYTE) (italic ? TRUE : FALSE); |
|
|
|
lf.lfWeight = bold ? FW_BOLD : FW_NORMAL; |
|
|
|
lf.lfHeight = size > 0 ? size : -256; |
|
|
|
fontName.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName)); |
|
|
|
|
|
|
|
HFONT standardSizedFont = CreateFontIndirect (&lf); |
|
|
|
|
|
|
|
if (standardSizedFont != 0) |
|
|
|
{ |
|
|
|
if ((previousFontH = SelectObject (dc, standardSizedFont)) != 0) |
|
|
|
{ |
|
|
|
fontH = standardSizedFont; |
|
|
|
|
|
|
|
if (size == 0) |
|
|
|
{ |
|
|
|
OUTLINETEXTMETRIC otm; |
|
|
|
if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0) |
|
|
|
{ |
|
|
|
lf.lfHeight = -(int) otm.otmEMSquare; |
|
|
|
fontH = CreateFontIndirect (&lf); |
|
|
|
|
|
|
|
SelectObject (dc, fontH); |
|
|
|
DeleteObject (standardSizedFont); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return dc; |
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
HFONT fontH; |
|
|
|
HGDIOBJ previousFontH; |
|
|
|
HDC dc; |
|
|
|
String fontName; |
|
|
|
HeapBlock <KERNINGPAIR> kps; |
|
|
|
int numKPs, size; |
|
|
|
bool bold, italic; |
|
|
|
|
|
|
|
void deleteDCAndFont() |
|
|
|
{ |
|
|
|
if (dc != 0) |
|
|
|
{ |
|
|
|
SelectObject (dc, previousFontH); // Replacing the previous font before deleting the DC avoids a warning in BoundsChecker |
|
|
|
DeleteDC (dc); |
|
|
|
dc = 0; |
|
|
|
} |
|
|
|
|
|
|
|
if (fontH != 0) |
|
|
|
{ |
|
|
|
DeleteObject (fontH); |
|
|
|
fontH = 0; |
|
|
|
} |
|
|
|
|
|
|
|
kps.free(); |
|
|
|
} |
|
|
|
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (FontDCHolder); |
|
|
|
}; |
|
|
|
|
|
|
|
juce_ImplementSingleton_SingleThreaded (FontDCHolder); |
|
|
|
|
|
|
|
class WindowsTypeface : public Typeface |
|
|
|
{ |
|
|
|
public: |
|
|
|
WindowsTypeface (const Font& font) |
|
|
|
: Typeface (font.getTypefaceName()), |
|
|
|
fontH (0), |
|
|
|
previousFontH (0), |
|
|
|
dc (CreateCompatibleDC (0)), |
|
|
|
ascent (1.0f), |
|
|
|
defaultGlyph (-1), |
|
|
|
bold (font.isBold()), |
|
|
|
italic (font.isItalic()) |
|
|
|
{ |
|
|
|
HDC dc = getDC(); |
|
|
|
loadFont(); |
|
|
|
|
|
|
|
TEXTMETRIC tm; |
|
|
|
if (GetTextMetrics (dc, &tm)) |
|
|
|
{ |
|
|
|
ascent = tm.tmAscent / (float) tm.tmHeight; |
|
|
@@ -246602,12 +246503,20 @@ public: |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
~WindowsTypeface() |
|
|
|
{ |
|
|
|
SelectObject (dc, previousFontH); // Replacing the previous font before deleting the DC avoids a warning in BoundsChecker |
|
|
|
DeleteDC (dc); |
|
|
|
|
|
|
|
if (fontH != 0) |
|
|
|
DeleteObject (fontH); |
|
|
|
} |
|
|
|
|
|
|
|
float getAscent() const { return ascent; } |
|
|
|
float getDescent() const { return 1.0f - ascent; } |
|
|
|
|
|
|
|
float getStringWidth (const String& text) |
|
|
|
{ |
|
|
|
HDC dc = getDC(); |
|
|
|
const CharPointer_UTF16 utf16 (text.toUTF16()); |
|
|
|
const int numChars = utf16.length(); |
|
|
|
HeapBlock<int16> results (numChars + 1); |
|
|
@@ -246626,7 +246535,6 @@ public: |
|
|
|
|
|
|
|
void getGlyphPositions (const String& text, Array <int>& resultGlyphs, Array <float>& xOffsets) |
|
|
|
{ |
|
|
|
HDC dc = getDC(); |
|
|
|
const CharPointer_UTF16 utf16 (text.toUTF16()); |
|
|
|
const int numChars = utf16.length(); |
|
|
|
HeapBlock<int16> results (numChars + 1); |
|
|
@@ -246652,12 +246560,6 @@ public: |
|
|
|
|
|
|
|
bool getOutlineForGlyph (int glyphNumber, Path& glyphPath) |
|
|
|
{ |
|
|
|
HDC dc = getDC(); |
|
|
|
|
|
|
|
TEXTMETRIC tm; |
|
|
|
if (! GetTextMetrics (dc, &tm)) |
|
|
|
return false; |
|
|
|
|
|
|
|
if (glyphNumber < 0) |
|
|
|
glyphNumber = defaultGlyph; |
|
|
|
|
|
|
@@ -246673,16 +246575,13 @@ public: |
|
|
|
|
|
|
|
const TTPOLYGONHEADER* pheader = reinterpret_cast<TTPOLYGONHEADER*> (data.getData()); |
|
|
|
|
|
|
|
const float height = (float) tm.tmHeight; |
|
|
|
const float scaleX = 1.0f / height; |
|
|
|
const float scaleY = -1.0f / height; |
|
|
|
const float scaleX = 1.0f / tm.tmHeight; |
|
|
|
const float scaleY = -scaleX; |
|
|
|
|
|
|
|
while ((char*) pheader < data + bufSize) |
|
|
|
{ |
|
|
|
float x = scaleX * pheader->pfxStart.x.value; |
|
|
|
float y = scaleY * pheader->pfxStart.y.value; |
|
|
|
|
|
|
|
glyphPath.startNewSubPath (x, y); |
|
|
|
glyphPath.startNewSubPath (scaleX * pheader->pfxStart.x.value, |
|
|
|
scaleY * pheader->pfxStart.y.value); |
|
|
|
|
|
|
|
const TTPOLYCURVE* curve = (const TTPOLYCURVE*) ((const char*) pheader + sizeof (TTPOLYGONHEADER)); |
|
|
|
const char* const curveEnd = ((const char*) pheader) + pheader->cb; |
|
|
@@ -246692,12 +246591,8 @@ public: |
|
|
|
if (curve->wType == TT_PRIM_LINE) |
|
|
|
{ |
|
|
|
for (int i = 0; i < curve->cpfx; ++i) |
|
|
|
{ |
|
|
|
x = scaleX * curve->apfx[i].x.value; |
|
|
|
y = scaleY * curve->apfx[i].y.value; |
|
|
|
|
|
|
|
glyphPath.lineTo (x, y); |
|
|
|
} |
|
|
|
glyphPath.lineTo (scaleX * curve->apfx[i].x.value, |
|
|
|
scaleY * curve->apfx[i].y.value); |
|
|
|
} |
|
|
|
else if (curve->wType == TT_PRIM_QSPLINE) |
|
|
|
{ |
|
|
@@ -246705,23 +246600,16 @@ public: |
|
|
|
{ |
|
|
|
const float x2 = scaleX * curve->apfx[i].x.value; |
|
|
|
const float y2 = scaleY * curve->apfx[i].y.value; |
|
|
|
float x3, y3; |
|
|
|
float x3 = scaleX * curve->apfx[i + 1].x.value; |
|
|
|
float y3 = scaleY * curve->apfx[i + 1].y.value; |
|
|
|
|
|
|
|
if (i < curve->cpfx - 2) |
|
|
|
{ |
|
|
|
x3 = 0.5f * (x2 + scaleX * curve->apfx[i + 1].x.value); |
|
|
|
y3 = 0.5f * (y2 + scaleY * curve->apfx[i + 1].y.value); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
x3 = scaleX * curve->apfx[i + 1].x.value; |
|
|
|
y3 = scaleY * curve->apfx[i + 1].y.value; |
|
|
|
x3 = 0.5f * (x2 + x3); |
|
|
|
y3 = 0.5f * (y2 + y3); |
|
|
|
} |
|
|
|
|
|
|
|
glyphPath.quadraticTo (x2, y2, x3, y3); |
|
|
|
|
|
|
|
x = x3; |
|
|
|
y = y3; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -246739,6 +246627,10 @@ public: |
|
|
|
|
|
|
|
private: |
|
|
|
static const MAT2 identityMatrix; |
|
|
|
HFONT fontH; |
|
|
|
HGDIOBJ previousFontH; |
|
|
|
HDC dc; |
|
|
|
TEXTMETRIC tm; |
|
|
|
float ascent; |
|
|
|
int defaultGlyph; |
|
|
|
bool bold, italic; |
|
|
@@ -246762,6 +246654,43 @@ private: |
|
|
|
|
|
|
|
SortedSet<KerningPair> kerningPairs; |
|
|
|
|
|
|
|
void loadFont() |
|
|
|
{ |
|
|
|
SetMapperFlags (dc, 0); |
|
|
|
SetMapMode (dc, MM_TEXT); |
|
|
|
|
|
|
|
LOGFONTW lf = { 0 }; |
|
|
|
lf.lfCharSet = DEFAULT_CHARSET; |
|
|
|
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; |
|
|
|
lf.lfOutPrecision = OUT_OUTLINE_PRECIS; |
|
|
|
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; |
|
|
|
lf.lfQuality = PROOF_QUALITY; |
|
|
|
lf.lfItalic = (BYTE) (italic ? TRUE : FALSE); |
|
|
|
lf.lfWeight = bold ? FW_BOLD : FW_NORMAL; |
|
|
|
lf.lfHeight = -256; |
|
|
|
name.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName)); |
|
|
|
|
|
|
|
HFONT standardSizedFont = CreateFontIndirect (&lf); |
|
|
|
|
|
|
|
if (standardSizedFont != 0) |
|
|
|
{ |
|
|
|
if ((previousFontH = SelectObject (dc, standardSizedFont)) != 0) |
|
|
|
{ |
|
|
|
fontH = standardSizedFont; |
|
|
|
|
|
|
|
OUTLINETEXTMETRIC otm; |
|
|
|
if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0) |
|
|
|
{ |
|
|
|
lf.lfHeight = -(int) otm.otmEMSquare; |
|
|
|
fontH = CreateFontIndirect (&lf); |
|
|
|
|
|
|
|
SelectObject (dc, fontH); |
|
|
|
DeleteObject (standardSizedFont); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void createKerningPairs (HDC dc, const float height) |
|
|
|
{ |
|
|
|
HeapBlock<KERNINGPAIR> rawKerning; |
|
|
@@ -246821,10 +246750,6 @@ private: |
|
|
|
|
|
|
|
if (index < 0) |
|
|
|
{ |
|
|
|
TEXTMETRIC tm; |
|
|
|
if (! GetTextMetrics (dc, &tm)) |
|
|
|
return 0; |
|
|
|
|
|
|
|
kp.glyph2 = -1; |
|
|
|
kp.kerning = getGlyphWidth (dc, kp.glyph1) / (float) tm.tmHeight; |
|
|
|
kerningPairs.add (kp); |
|
|
@@ -246835,11 +246760,6 @@ private: |
|
|
|
return kerningPairs.getReference (index).kerning; |
|
|
|
} |
|
|
|
|
|
|
|
HDC getDC() const |
|
|
|
{ |
|
|
|
return FontDCHolder::getInstance()->loadFont (name, bold, italic, 0); |
|
|
|
} |
|
|
|
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsTypeface); |
|
|
|
}; |
|
|
|
|
|
|
@@ -248357,7 +248277,7 @@ public: |
|
|
|
{ |
|
|
|
setMinimised (false); |
|
|
|
|
|
|
|
if (fullScreen != shouldBeFullScreen) |
|
|
|
if (isFullScreen() != shouldBeFullScreen) |
|
|
|
{ |
|
|
|
fullScreen = shouldBeFullScreen; |
|
|
|
const WeakReference<Component> deletionChecker (component); |
|
|
@@ -281766,10 +281686,7 @@ public: |
|
|
|
[menu setAutoenablesItems: false]; |
|
|
|
[menu update]; |
|
|
|
[parentItem setTag: tag]; |
|
|
|
|
|
|
|
if (! [[parentItem submenu] equals: menu]) // NB this comparison is needed to avoid a strange |
|
|
|
[parentItem setSubmenu: menu]; // crash deep inside Apple code when no windows are focused.. |
|
|
|
|
|
|
|
[parentItem setSubmenu: menu]; |
|
|
|
[menu release]; |
|
|
|
} |
|
|
|
|
|
|
@@ -281817,7 +281734,7 @@ public: |
|
|
|
} |
|
|
|
|
|
|
|
if (Time::getMillisecondCounter() > lastUpdateTime + 500) |
|
|
|
menuBarItemsChanged (nullptr); |
|
|
|
(new AsyncMenuUpdater())->post(); |
|
|
|
} |
|
|
|
|
|
|
|
void invoke (const int commandId, ApplicationCommandManager* const commandManager, const int topLevelIndex) const |
|
|
@@ -282003,6 +281920,21 @@ private: |
|
|
|
if (mods.isCommandDown()) m |= NSCommandKeyMask; |
|
|
|
return m; |
|
|
|
} |
|
|
|
|
|
|
|
class AsyncMenuUpdater : public CallbackMessage |
|
|
|
{ |
|
|
|
public: |
|
|
|
AsyncMenuUpdater() {} |
|
|
|
|
|
|
|
void messageCallback() |
|
|
|
{ |
|
|
|
if (JuceMainMenuHandler::instance != nullptr) |
|
|
|
JuceMainMenuHandler::instance->menuBarItemsChanged (nullptr); |
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
JUCE_DECLARE_NON_COPYABLE (AsyncMenuUpdater); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
JuceMainMenuHandler* JuceMainMenuHandler::instance = nullptr; |
|
|
|