diff --git a/Builds/Linux/Makefile b/Builds/Linux/Makefile
index e049d3f5e3..f16b9d7fa4 100644
--- a/Builds/Linux/Makefile
+++ b/Builds/Linux/Makefile
@@ -307,6 +307,7 @@ OBJECTS := \
$(OBJDIR)/juce_win32_ASIO_60eb61ca.o \
$(OBJDIR)/juce_win32_AudioCDReader_66c7252.o \
$(OBJDIR)/juce_win32_CameraDevice_ea35306d.o \
+ $(OBJDIR)/juce_win32_Direct2DGraphicsContext_9f1b6be1.o \
$(OBJDIR)/juce_win32_DirectSound_3462415e.o \
$(OBJDIR)/juce_win32_DynamicLibraryLoader_2df0d241.o \
$(OBJDIR)/juce_win32_FileChooser_18a257.o \
@@ -1697,6 +1698,11 @@ $(OBJDIR)/juce_win32_CameraDevice_ea35306d.o: ../../src/native/windows/juce_win3
@echo "Compiling juce_win32_CameraDevice.cpp"
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+$(OBJDIR)/juce_win32_Direct2DGraphicsContext_9f1b6be1.o: ../../src/native/windows/juce_win32_Direct2DGraphicsContext.cpp
+ -@mkdir -p $(OBJDIR)
+ @echo "Compiling juce_win32_Direct2DGraphicsContext.cpp"
+ @$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+
$(OBJDIR)/juce_win32_DirectSound_3462415e.o: ../../src/native/windows/juce_win32_DirectSound.cpp
-@mkdir -p $(OBJDIR)
@echo "Compiling juce_win32_DirectSound.cpp"
diff --git a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj
index 0420d33e03..487722f683 100644
--- a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj
+++ b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj
@@ -302,6 +302,7 @@
4B4E17467BC41E2166549998 = { isa = PBXBuildFile; fileRef = 8F383A785B4876198C5B0194; };
9686F29C29D1C26E353DE68A = { isa = PBXBuildFile; fileRef = F3B50EE3939E9F16D13C3C7C; };
79B4C2F1C0CF592ACE8093C0 = { isa = PBXBuildFile; fileRef = 3A37CD82212075940421CE4F; };
+ 88A87D28B3809665F28DC16E = { isa = PBXBuildFile; fileRef = 7F3EF672D07ECE3E13AAF267; };
BC3C22F5350ED7433D303A04 = { isa = PBXBuildFile; fileRef = 58B70C726D186B4E770300BC; };
527CF9C21EB7512B2283E61C = { isa = PBXBuildFile; fileRef = 0CFD86AE0B7CBAE2ADE75C53; };
0B41EC4D7839F8CBCB8F9A0D = { isa = PBXBuildFile; fileRef = DCD09B6EF4A4A109DE01F152; };
@@ -956,6 +957,7 @@
F3B50EE3939E9F16D13C3C7C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_AudioCDReader.cpp; path = ../../src/native/windows/juce_win32_AudioCDReader.cpp; sourceTree = SOURCE_ROOT; };
9C4D1018ECC0BA07346453EF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_win32_AutoLinkLibraries.h; path = ../../src/native/windows/juce_win32_AutoLinkLibraries.h; sourceTree = SOURCE_ROOT; };
3A37CD82212075940421CE4F = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_CameraDevice.cpp; path = ../../src/native/windows/juce_win32_CameraDevice.cpp; sourceTree = SOURCE_ROOT; };
+ 7F3EF672D07ECE3E13AAF267 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_Direct2DGraphicsContext.cpp; path = ../../src/native/windows/juce_win32_Direct2DGraphicsContext.cpp; sourceTree = SOURCE_ROOT; };
58B70C726D186B4E770300BC = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_DirectSound.cpp; path = ../../src/native/windows/juce_win32_DirectSound.cpp; sourceTree = SOURCE_ROOT; };
0CFD86AE0B7CBAE2ADE75C53 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_DynamicLibraryLoader.cpp; path = ../../src/native/windows/juce_win32_DynamicLibraryLoader.cpp; sourceTree = SOURCE_ROOT; };
BA66E265749F75DBA86EC3F1 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_win32_DynamicLibraryLoader.h; path = ../../src/native/windows/juce_win32_DynamicLibraryLoader.h; sourceTree = SOURCE_ROOT; };
@@ -1728,6 +1730,7 @@
F3B50EE3939E9F16D13C3C7C,
9C4D1018ECC0BA07346453EF,
3A37CD82212075940421CE4F,
+ 7F3EF672D07ECE3E13AAF267,
58B70C726D186B4E770300BC,
0CFD86AE0B7CBAE2ADE75C53,
BA66E265749F75DBA86EC3F1,
@@ -2196,6 +2199,7 @@
4B4E17467BC41E2166549998,
9686F29C29D1C26E353DE68A,
79B4C2F1C0CF592ACE8093C0,
+ 88A87D28B3809665F28DC16E,
BC3C22F5350ED7433D303A04,
527CF9C21EB7512B2283E61C,
0B41EC4D7839F8CBCB8F9A0D,
diff --git a/Builds/VisualStudio2005/Juce.vcproj b/Builds/VisualStudio2005/Juce.vcproj
index a8f383abfc..72d02dce50 100644
--- a/Builds/VisualStudio2005/Juce.vcproj
+++ b/Builds/VisualStudio2005/Juce.vcproj
@@ -893,6 +893,7 @@
+
diff --git a/Builds/VisualStudio2008/Juce.vcproj b/Builds/VisualStudio2008/Juce.vcproj
index e2ed8bc41e..a8ffbf0bc7 100644
--- a/Builds/VisualStudio2008/Juce.vcproj
+++ b/Builds/VisualStudio2008/Juce.vcproj
@@ -893,6 +893,7 @@
+
diff --git a/Builds/VisualStudio2008_DLL/Juce.vcproj b/Builds/VisualStudio2008_DLL/Juce.vcproj
index 9742652310..7428441592 100644
--- a/Builds/VisualStudio2008_DLL/Juce.vcproj
+++ b/Builds/VisualStudio2008_DLL/Juce.vcproj
@@ -895,6 +895,7 @@
+
diff --git a/Builds/VisualStudio2010/Juce.vcxproj b/Builds/VisualStudio2010/Juce.vcxproj
index 599b605302..c8548547ec 100644
--- a/Builds/VisualStudio2010/Juce.vcxproj
+++ b/Builds/VisualStudio2010/Juce.vcxproj
@@ -390,6 +390,7 @@
+
diff --git a/Builds/VisualStudio2010/Juce.vcxproj.filters b/Builds/VisualStudio2010/Juce.vcxproj.filters
index 91293ea6cf..a91fde5a59 100644
--- a/Builds/VisualStudio2010/Juce.vcxproj.filters
+++ b/Builds/VisualStudio2010/Juce.vcxproj.filters
@@ -1096,6 +1096,9 @@
Juce\Source\native\windows
+
+ Juce\Source\native\windows
+
Juce\Source\native\windows
diff --git a/Builds/iPhone/Juce.xcodeproj/project.pbxproj b/Builds/iPhone/Juce.xcodeproj/project.pbxproj
index 17dcffd6b5..c48254e55a 100644
--- a/Builds/iPhone/Juce.xcodeproj/project.pbxproj
+++ b/Builds/iPhone/Juce.xcodeproj/project.pbxproj
@@ -302,6 +302,7 @@
4B4E17467BC41E2166549998 = { isa = PBXBuildFile; fileRef = 8F383A785B4876198C5B0194; };
9686F29C29D1C26E353DE68A = { isa = PBXBuildFile; fileRef = F3B50EE3939E9F16D13C3C7C; };
79B4C2F1C0CF592ACE8093C0 = { isa = PBXBuildFile; fileRef = 3A37CD82212075940421CE4F; };
+ 88A87D28B3809665F28DC16E = { isa = PBXBuildFile; fileRef = 7F3EF672D07ECE3E13AAF267; };
BC3C22F5350ED7433D303A04 = { isa = PBXBuildFile; fileRef = 58B70C726D186B4E770300BC; };
527CF9C21EB7512B2283E61C = { isa = PBXBuildFile; fileRef = 0CFD86AE0B7CBAE2ADE75C53; };
0B41EC4D7839F8CBCB8F9A0D = { isa = PBXBuildFile; fileRef = DCD09B6EF4A4A109DE01F152; };
@@ -956,6 +957,7 @@
F3B50EE3939E9F16D13C3C7C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_AudioCDReader.cpp; path = ../../src/native/windows/juce_win32_AudioCDReader.cpp; sourceTree = SOURCE_ROOT; };
9C4D1018ECC0BA07346453EF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_win32_AutoLinkLibraries.h; path = ../../src/native/windows/juce_win32_AutoLinkLibraries.h; sourceTree = SOURCE_ROOT; };
3A37CD82212075940421CE4F = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_CameraDevice.cpp; path = ../../src/native/windows/juce_win32_CameraDevice.cpp; sourceTree = SOURCE_ROOT; };
+ 7F3EF672D07ECE3E13AAF267 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_Direct2DGraphicsContext.cpp; path = ../../src/native/windows/juce_win32_Direct2DGraphicsContext.cpp; sourceTree = SOURCE_ROOT; };
58B70C726D186B4E770300BC = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_DirectSound.cpp; path = ../../src/native/windows/juce_win32_DirectSound.cpp; sourceTree = SOURCE_ROOT; };
0CFD86AE0B7CBAE2ADE75C53 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_win32_DynamicLibraryLoader.cpp; path = ../../src/native/windows/juce_win32_DynamicLibraryLoader.cpp; sourceTree = SOURCE_ROOT; };
BA66E265749F75DBA86EC3F1 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_win32_DynamicLibraryLoader.h; path = ../../src/native/windows/juce_win32_DynamicLibraryLoader.h; sourceTree = SOURCE_ROOT; };
@@ -1728,6 +1730,7 @@
F3B50EE3939E9F16D13C3C7C,
9C4D1018ECC0BA07346453EF,
3A37CD82212075940421CE4F,
+ 7F3EF672D07ECE3E13AAF267,
58B70C726D186B4E770300BC,
0CFD86AE0B7CBAE2ADE75C53,
BA66E265749F75DBA86EC3F1,
@@ -2196,6 +2199,7 @@
4B4E17467BC41E2166549998,
9686F29C29D1C26E353DE68A,
79B4C2F1C0CF592ACE8093C0,
+ 88A87D28B3809665F28DC16E,
BC3C22F5350ED7433D303A04,
527CF9C21EB7512B2283E61C,
0B41EC4D7839F8CBCB8F9A0D,
diff --git a/Juce.jucer b/Juce.jucer
index b36cfeba5d..e39ef89007 100644
--- a/Juce.jucer
+++ b/Juce.jucer
@@ -1359,6 +1359,8 @@
resource="0" file="src/native/windows/juce_win32_AutoLinkLibraries.h"/>
+
+ JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_USE_XCURSOR="default"
+ JUCE_DIRECT2D="default"/>
diff --git a/extras/Jucer (experimental)/JuceLibraryCode/AppConfig.h b/extras/Jucer (experimental)/JuceLibraryCode/AppConfig.h
index 7e8dd82edb..0dc80c4954 100644
--- a/extras/Jucer (experimental)/JuceLibraryCode/AppConfig.h
+++ b/extras/Jucer (experimental)/JuceLibraryCode/AppConfig.h
@@ -19,6 +19,7 @@
#define JUCE_ALSA 0
#define JUCE_QUICKTIME 0
#define JUCE_OPENGL 0
+//#define JUCE_DIRECT2D
#define JUCE_USE_FLAC 0
#define JUCE_USE_OGGVORBIS 0
#define JUCE_USE_CDBURNER 0
diff --git a/extras/Jucer (experimental)/Jucer.jucer b/extras/Jucer (experimental)/Jucer.jucer
index 7f253745fe..963b44bb2d 100644
--- a/extras/Jucer (experimental)/Jucer.jucer
+++ b/extras/Jucer (experimental)/Jucer.jucer
@@ -178,5 +178,5 @@
JUCE_USE_XINERAMA="default" JUCE_USE_XSHM="default" JUCE_ONLY_BUILD_CORE_LIBRARY="default"
JUCE_WEB_BROWSER="default" JUCE_SUPPORT_CARBON="default" JUCE_CHECK_MEMORY_LEAKS="default"
JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_STRINGS_ARE_UNICODE="default"
- JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default"/>
+ JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"/>
diff --git a/extras/amalgamator/Amalgamator.jucer b/extras/amalgamator/Amalgamator.jucer
index f7c915c245..b252176028 100644
--- a/extras/amalgamator/Amalgamator.jucer
+++ b/extras/amalgamator/Amalgamator.jucer
@@ -37,5 +37,5 @@
JUCE_PLUGINHOST_AU="default" JUCE_ONLY_BUILD_CORE_LIBRARY="enabled"
JUCE_WEB_BROWSER="default" JUCE_SUPPORT_CARBON="default" JUCE_CHECK_MEMORY_LEAKS="default"
JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_STRINGS_ARE_UNICODE="default"
- JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default"/>
+ JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"/>
diff --git a/extras/amalgamator/JuceLibraryCode/AppConfig.h b/extras/amalgamator/JuceLibraryCode/AppConfig.h
index aaff736abd..654892fe15 100644
--- a/extras/amalgamator/JuceLibraryCode/AppConfig.h
+++ b/extras/amalgamator/JuceLibraryCode/AppConfig.h
@@ -19,6 +19,7 @@
//#define JUCE_ALSA
//#define JUCE_QUICKTIME
//#define JUCE_OPENGL
+//#define JUCE_DIRECT2D
//#define JUCE_USE_FLAC
//#define JUCE_USE_OGGVORBIS
//#define JUCE_USE_CDBURNER
diff --git a/extras/audio plugin host/JuceLibraryCode/AppConfig.h b/extras/audio plugin host/JuceLibraryCode/AppConfig.h
index 191ea1e1ec..13a0dc7f9e 100644
--- a/extras/audio plugin host/JuceLibraryCode/AppConfig.h
+++ b/extras/audio plugin host/JuceLibraryCode/AppConfig.h
@@ -19,6 +19,7 @@
#define JUCE_ALSA 1
//#define JUCE_QUICKTIME
//#define JUCE_OPENGL
+//#define JUCE_DIRECT2D
//#define JUCE_USE_FLAC
//#define JUCE_USE_OGGVORBIS
//#define JUCE_USE_CDBURNER
diff --git a/extras/audio plugin host/Plugin Host.jucer b/extras/audio plugin host/Plugin Host.jucer
index 4dd93359c1..15b6365ea1 100644
--- a/extras/audio plugin host/Plugin Host.jucer
+++ b/extras/audio plugin host/Plugin Host.jucer
@@ -57,5 +57,5 @@
JUCE_PLUGINHOST_AU="enabled" JUCE_ONLY_BUILD_CORE_LIBRARY="default"
JUCE_WEB_BROWSER="default" JUCE_SUPPORT_CARBON="default" JUCE_CHECK_MEMORY_LEAKS="default"
JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_STRINGS_ARE_UNICODE="default"
- JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default"/>
+ JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"/>
diff --git a/extras/audio plugins/demo/JuceDemoPlugin.jucer b/extras/audio plugins/demo/JuceDemoPlugin.jucer
index 759f160256..e2a2873e1c 100644
--- a/extras/audio plugins/demo/JuceDemoPlugin.jucer
+++ b/extras/audio plugins/demo/JuceDemoPlugin.jucer
@@ -43,5 +43,6 @@
JUCE_USE_XINERAMA="default" JUCE_USE_XSHM="default" JUCE_USE_XRENDER="default"
JUCE_PLUGINHOST_VST="default" JUCE_PLUGINHOST_AU="default" JUCE_ONLY_BUILD_CORE_LIBRARY="default"
JUCE_WEB_BROWSER="default" JUCE_SUPPORT_CARBON="default" JUCE_CHECK_MEMORY_LEAKS="default"
- JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_USE_XCURSOR="default"/>
+ JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_USE_XCURSOR="default"
+ JUCE_DIRECT2D="default"/>
diff --git a/extras/audio plugins/demo/JuceLibraryCode/AppConfig.h b/extras/audio plugins/demo/JuceLibraryCode/AppConfig.h
index d659aac8bc..e16565bdf8 100644
--- a/extras/audio plugins/demo/JuceLibraryCode/AppConfig.h
+++ b/extras/audio plugins/demo/JuceLibraryCode/AppConfig.h
@@ -19,6 +19,7 @@
//#define JUCE_ALSA
#define JUCE_QUICKTIME 0
//#define JUCE_OPENGL
+//#define JUCE_DIRECT2D
//#define JUCE_USE_FLAC
//#define JUCE_USE_OGGVORBIS
//#define JUCE_USE_CDBURNER
diff --git a/extras/binarybuilder/BinaryBuilder.jucer b/extras/binarybuilder/BinaryBuilder.jucer
index 1133d4d5c3..83c37c405d 100644
--- a/extras/binarybuilder/BinaryBuilder.jucer
+++ b/extras/binarybuilder/BinaryBuilder.jucer
@@ -38,5 +38,5 @@
JUCE_PLUGINHOST_AU="default" JUCE_ONLY_BUILD_CORE_LIBRARY="enabled"
JUCE_WEB_BROWSER="default" JUCE_SUPPORT_CARBON="default" JUCE_CHECK_MEMORY_LEAKS="default"
JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_STRINGS_ARE_UNICODE="default"
- JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default"/>
+ JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"/>
diff --git a/extras/binarybuilder/JuceLibraryCode/AppConfig.h b/extras/binarybuilder/JuceLibraryCode/AppConfig.h
index aaff736abd..654892fe15 100644
--- a/extras/binarybuilder/JuceLibraryCode/AppConfig.h
+++ b/extras/binarybuilder/JuceLibraryCode/AppConfig.h
@@ -19,6 +19,7 @@
//#define JUCE_ALSA
//#define JUCE_QUICKTIME
//#define JUCE_OPENGL
+//#define JUCE_DIRECT2D
//#define JUCE_USE_FLAC
//#define JUCE_USE_OGGVORBIS
//#define JUCE_USE_CDBURNER
diff --git a/extras/example projects/HelloWorld.jucer b/extras/example projects/HelloWorld.jucer
index 3043f60585..45ff8d6c63 100644
--- a/extras/example projects/HelloWorld.jucer
+++ b/extras/example projects/HelloWorld.jucer
@@ -45,5 +45,5 @@
JUCE_PLUGINHOST_AU="default" JUCE_ONLY_BUILD_CORE_LIBRARY="default"
JUCE_WEB_BROWSER="default" JUCE_SUPPORT_CARBON="default" JUCE_CHECK_MEMORY_LEAKS="default"
JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_STRINGS_ARE_UNICODE="default"
- JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default"/>
+ JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"/>
diff --git a/extras/example projects/JuceLibraryCode/AppConfig.h b/extras/example projects/JuceLibraryCode/AppConfig.h
index b565f6099d..23094fe3f3 100644
--- a/extras/example projects/JuceLibraryCode/AppConfig.h
+++ b/extras/example projects/JuceLibraryCode/AppConfig.h
@@ -19,6 +19,7 @@
//#define JUCE_ALSA
//#define JUCE_QUICKTIME
//#define JUCE_OPENGL
+//#define JUCE_DIRECT2D
//#define JUCE_USE_FLAC
//#define JUCE_USE_OGGVORBIS
//#define JUCE_USE_CDBURNER
diff --git a/extras/juce demo/Juce Demo.jucer b/extras/juce demo/Juce Demo.jucer
index 02d4ef142c..be21b69ff1 100644
--- a/extras/juce demo/Juce Demo.jucer
+++ b/extras/juce demo/Juce Demo.jucer
@@ -112,5 +112,5 @@
JUCE_PLUGINHOST_AU="disabled" JUCE_ONLY_BUILD_CORE_LIBRARY="default"
JUCE_WEB_BROWSER="default" JUCE_SUPPORT_CARBON="default" JUCE_CHECK_MEMORY_LEAKS="default"
JUCE_CATCH_UNHANDLED_EXCEPTIONS="default" JUCE_STRINGS_ARE_UNICODE="default"
- JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default"/>
+ JUCE_USE_XRENDER="default" JUCE_USE_XCURSOR="default" JUCE_DIRECT2D="default"/>
diff --git a/extras/juce demo/JuceLibraryCode/AppConfig.h b/extras/juce demo/JuceLibraryCode/AppConfig.h
index 2084b095ce..d878651b93 100644
--- a/extras/juce demo/JuceLibraryCode/AppConfig.h
+++ b/extras/juce demo/JuceLibraryCode/AppConfig.h
@@ -19,6 +19,7 @@
//#define JUCE_ALSA
//#define JUCE_QUICKTIME
//#define JUCE_OPENGL
+//#define JUCE_DIRECT2D
//#define JUCE_USE_FLAC
//#define JUCE_USE_OGGVORBIS
//#define JUCE_USE_CDBURNER
diff --git a/extras/juce demo/Source/demos/AudioDemoLatencyPage.cpp b/extras/juce demo/Source/demos/AudioDemoLatencyPage.cpp
index e8e13dfd15..a5b3af1229 100644
--- a/extras/juce demo/Source/demos/AudioDemoLatencyPage.cpp
+++ b/extras/juce demo/Source/demos/AudioDemoLatencyPage.cpp
@@ -37,6 +37,7 @@ public:
recordedSound (1, 1),
playingSampleNum (0),
recordedSampleNum (-1),
+ sampleRate (0),
isRunning (false),
resultsBox (resultsBox_)
{
diff --git a/juce_Config.h b/juce_Config.h
index e5c75a3f73..056e844fae 100644
--- a/juce_Config.h
+++ b/juce_Config.h
@@ -117,6 +117,13 @@
#define JUCE_OPENGL 1
#endif
+/** JUCE_DIRECT2D: Enables the Windows 7 Direct2D renderer.
+ If you're building on a platform older than Vista, you won't be able to compile with this feature.
+*/
+#ifndef JUCE_DIRECT2D
+ #define JUCE_DIRECT2D 0
+#endif
+
//=============================================================================
/** JUCE_USE_FLAC: Enables the FLAC audio codec classes (available on all platforms).
If your app doesn't need to read FLAC files, you might want to disable this to
diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp
index 3d1215c604..ef1196b900 100644
--- a/juce_amalgamated.cpp
+++ b/juce_amalgamated.cpp
@@ -270,6 +270,13 @@
#define JUCE_OPENGL 1
#endif
+/** JUCE_DIRECT2D: Enables the Windows 7 Direct2D renderer.
+ If you're building on a platform older than Vista, you won't be able to compile with this feature.
+*/
+#ifndef JUCE_DIRECT2D
+ #define JUCE_DIRECT2D 0
+#endif
+
/** JUCE_USE_FLAC: Enables the FLAC audio codec classes (available on all platforms).
If your app doesn't need to read FLAC files, you might want to disable this to
reduce the size of your codebase and build time.
@@ -619,6 +626,11 @@
#pragma warning (pop)
#endif
+#if JUCE_DIRECT2D
+ #include
+ #include
+#endif
+
/** A simple COM smart pointer.
Avoids having to include ATL just to get one of these.
*/
@@ -671,7 +683,10 @@ public:
HRESULT __stdcall QueryInterface (REFIID refId, void __RPC_FAR* __RPC_FAR* result)
{
+ #ifndef __MINGW32__
if (refId == __uuidof (ComClass)) { AddRef(); *result = dynamic_cast (this); return S_OK; }
+ #endif
+
if (refId == IID_IUnknown) { AddRef(); *result = dynamic_cast (this); return S_OK; }
*result = 0;
@@ -78033,7 +78048,7 @@ void ComponentPeer::addMaskedRegion (int x, int y, int w, int h)
maskedRegion.add (x, y, w, h);
}
-const StringArray ComponentPeer::getAvailableRenderingEngines() throw()
+const StringArray ComponentPeer::getAvailableRenderingEngines()
{
StringArray s;
s.add ("Software Renderer");
@@ -78045,7 +78060,7 @@ int ComponentPeer::getCurrentRenderingEngine() throw()
return 0;
}
-void ComponentPeer::setCurrentRenderingEngine (int /*index*/) throw()
+void ComponentPeer::setCurrentRenderingEngine (int /*index*/)
{
}
@@ -239887,6 +239902,1237 @@ void MessageManager::doPlatformSpecificShutdown()
+/*** Start of inlined file: juce_win32_Fonts.cpp ***/
+// (This file gets included by juce_win32_NativeCode.cpp, rather than being
+// compiled on its own).
+#if JUCE_INCLUDED_FILE
+
+static int CALLBACK wfontEnum2 (ENUMLOGFONTEXW* lpelfe,
+ NEWTEXTMETRICEXW*,
+ int type,
+ LPARAM lParam)
+{
+ if (lpelfe != 0 && (type & RASTER_FONTTYPE) == 0)
+ {
+ const String fontName (lpelfe->elfLogFont.lfFaceName);
+
+ ((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters ("@"));
+ }
+
+ return 1;
+}
+
+static int CALLBACK wfontEnum1 (ENUMLOGFONTEXW* lpelfe,
+ NEWTEXTMETRICEXW*,
+ int type,
+ LPARAM lParam)
+{
+ if (lpelfe != 0 && (type & RASTER_FONTTYPE) == 0)
+ {
+ LOGFONTW lf;
+ zerostruct (lf);
+
+ 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.copyToUnicode (lf.lfFaceName, LF_FACESIZE - 1);
+
+ HDC dc = CreateCompatibleDC (0);
+ EnumFontFamiliesEx (dc, &lf,
+ (FONTENUMPROCW) &wfontEnum2,
+ lParam, 0);
+ DeleteDC (dc);
+ }
+
+ return 1;
+}
+
+const StringArray Font::findAllTypefaceNames()
+{
+ StringArray results;
+ HDC dc = CreateCompatibleDC (0);
+
+ {
+ LOGFONTW lf;
+ zerostruct (lf);
+
+ 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;
+ lf.lfFaceName[0] = 0;
+
+ EnumFontFamiliesEx (dc, &lf,
+ (FONTENUMPROCW) &wfontEnum1,
+ (LPARAM) &results, 0);
+ }
+
+ DeleteDC (dc);
+
+ results.sort (true);
+ return results;
+}
+
+extern bool juce_IsRunningInWine();
+
+void Font::getPlatformDefaultFontNames (String& defaultSans, String& defaultSerif, String& defaultFixed)
+{
+ if (juce_IsRunningInWine())
+ {
+ // If we're running in Wine, then use fonts that might be available on Linux..
+ defaultSans = "Bitstream Vera Sans";
+ defaultSerif = "Bitstream Vera Serif";
+ defaultFixed = "Bitstream Vera Sans Mono";
+ }
+ else
+ {
+ defaultSans = "Verdana";
+ defaultSerif = "Times";
+ defaultFixed = "Lucida Console";
+ }
+}
+
+class FontDCHolder : private DeletedAtShutdown
+{
+public:
+
+ FontDCHolder()
+ : dc (0), numKPs (0), size (0),
+ bold (false), italic (false)
+ {
+ }
+
+ ~FontDCHolder()
+ {
+ if (dc != 0)
+ {
+ DeleteDC (dc);
+ DeleteObject (fontH);
+ }
+
+ 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_;
+
+ if (dc != 0)
+ {
+ DeleteDC (dc);
+ DeleteObject (fontH);
+ kps.free();
+ }
+
+ fontH = 0;
+
+ dc = CreateCompatibleDC (0);
+ SetMapperFlags (dc, 0);
+ SetMapMode (dc, MM_TEXT);
+
+ LOGFONTW lfw;
+ zerostruct (lfw);
+
+ lfw.lfCharSet = DEFAULT_CHARSET;
+ lfw.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lfw.lfOutPrecision = OUT_OUTLINE_PRECIS;
+ lfw.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ lfw.lfQuality = PROOF_QUALITY;
+ lfw.lfItalic = (BYTE) (italic ? TRUE : FALSE);
+ lfw.lfWeight = bold ? FW_BOLD : FW_NORMAL;
+ fontName.copyToUnicode (lfw.lfFaceName, LF_FACESIZE - 1);
+
+ lfw.lfHeight = size > 0 ? size : -256;
+ HFONT standardSizedFont = CreateFontIndirect (&lfw);
+
+ if (standardSizedFont != 0)
+ {
+ if (SelectObject (dc, standardSizedFont) != 0)
+ {
+ fontH = standardSizedFont;
+
+ if (size == 0)
+ {
+ OUTLINETEXTMETRIC otm;
+ if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0)
+ {
+ lfw.lfHeight = -(int) otm.otmEMSquare;
+ fontH = CreateFontIndirect (&lfw);
+
+ SelectObject (dc, fontH);
+ DeleteObject (standardSizedFont);
+ }
+ }
+ }
+ else
+ {
+ jassertfalse;
+ }
+ }
+ else
+ {
+ jassertfalse;
+ }
+ }
+
+ return dc;
+ }
+
+ KERNINGPAIR* getKerningPairs (int& numKPs_)
+ {
+ if (kps == 0)
+ {
+ numKPs = GetKerningPairs (dc, 0, 0);
+ kps.calloc (numKPs);
+ GetKerningPairs (dc, numKPs, kps);
+ }
+
+ numKPs_ = numKPs;
+ return kps;
+ }
+
+private:
+
+ HFONT fontH;
+ HDC dc;
+ String fontName;
+ HeapBlock kps;
+ int numKPs, size;
+ bool bold, italic;
+
+ FontDCHolder (const FontDCHolder&);
+ FontDCHolder& operator= (const FontDCHolder&);
+};
+
+juce_ImplementSingleton_SingleThreaded (FontDCHolder);
+
+class WindowsTypeface : public CustomTypeface
+{
+public:
+ WindowsTypeface (const Font& font)
+ {
+ HDC dc = FontDCHolder::getInstance()->loadFont (font.getTypefaceName(),
+ font.isBold(), font.isItalic(), 0);
+
+ TEXTMETRIC tm;
+ tm.tmAscent = tm.tmHeight = 1;
+ tm.tmDefaultChar = 0;
+ GetTextMetrics (dc, &tm);
+
+ setCharacteristics (font.getTypefaceName(),
+ tm.tmAscent / (float) tm.tmHeight,
+ font.isBold(), font.isItalic(),
+ tm.tmDefaultChar);
+ }
+
+ bool loadGlyphIfPossible (juce_wchar character)
+ {
+ HDC dc = FontDCHolder::getInstance()->loadFont (name, isBold, isItalic, 0);
+
+ GLYPHMETRICS gm;
+
+ {
+ const WCHAR charToTest[] = { (WCHAR) character, 0 };
+ WORD index = 0;
+
+ if (GetGlyphIndices (dc, charToTest, 1, &index, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR
+ && index == 0xffff)
+ {
+ return false;
+ }
+ }
+
+ Path glyphPath;
+
+ TEXTMETRIC tm;
+ if (! GetTextMetrics (dc, &tm))
+ {
+ addGlyph (character, glyphPath, 0);
+ return true;
+ }
+
+ const float height = (float) tm.tmHeight;
+ static const MAT2 identityMatrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
+
+ const int bufSize = GetGlyphOutline (dc, character, GGO_NATIVE,
+ &gm, 0, 0, &identityMatrix);
+
+ if (bufSize > 0)
+ {
+ HeapBlock data (bufSize);
+
+ GetGlyphOutline (dc, character, GGO_NATIVE, &gm,
+ bufSize, data, &identityMatrix);
+
+ const TTPOLYGONHEADER* pheader = reinterpret_cast (data.getData());
+
+ const float scaleX = 1.0f / height;
+ const float scaleY = -1.0f / height;
+
+ while ((char*) pheader < data + bufSize)
+ {
+ float x = scaleX * pheader->pfxStart.x.value;
+ float y = scaleY * pheader->pfxStart.y.value;
+
+ glyphPath.startNewSubPath (x, y);
+
+ const TTPOLYCURVE* curve = (const TTPOLYCURVE*) ((const char*) pheader + sizeof (TTPOLYGONHEADER));
+ const char* const curveEnd = ((const char*) pheader) + pheader->cb;
+
+ while ((const char*) curve < curveEnd)
+ {
+ 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);
+ }
+ }
+ else if (curve->wType == TT_PRIM_QSPLINE)
+ {
+ for (int i = 0; i < curve->cpfx - 1; ++i)
+ {
+ const float x2 = scaleX * curve->apfx[i].x.value;
+ const float y2 = scaleY * curve->apfx[i].y.value;
+ float x3, y3;
+
+ 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;
+ }
+
+ glyphPath.quadraticTo (x2, y2, x3, y3);
+
+ x = x3;
+ y = y3;
+ }
+ }
+
+ curve = (const TTPOLYCURVE*) &(curve->apfx [curve->cpfx]);
+ }
+
+ pheader = (const TTPOLYGONHEADER*) curve;
+
+ glyphPath.closeSubPath();
+ }
+ }
+
+ addGlyph (character, glyphPath, gm.gmCellIncX / height);
+
+ int numKPs;
+ const KERNINGPAIR* const kps = FontDCHolder::getInstance()->getKerningPairs (numKPs);
+
+ for (int i = 0; i < numKPs; ++i)
+ {
+ if (kps[i].wFirst == character)
+ addKerningPair (kps[i].wFirst, kps[i].wSecond,
+ kps[i].iKernAmount / height);
+ }
+
+ return true;
+ }
+
+ juce_UseDebuggingNewOperator
+};
+
+const Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
+{
+ return new WindowsTypeface (font);
+}
+
+#endif
+/*** End of inlined file: juce_win32_Fonts.cpp ***/
+
+
+/*** Start of inlined file: juce_win32_Direct2DGraphicsContext.cpp ***/
+// (This file gets included by juce_win32_NativeCode.cpp, rather than being
+// compiled on its own).
+#if JUCE_INCLUDED_FILE && JUCE_DIRECT2D
+
+class SharedD2DFactory : public DeletedAtShutdown
+{
+public:
+ SharedD2DFactory()
+ {
+ D2D1CreateFactory (D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2dFactory);
+ DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory), (IUnknown**) &directWriteFactory);
+
+ if (directWriteFactory != 0)
+ directWriteFactory->GetSystemFontCollection (&systemFonts);
+ }
+
+ ~SharedD2DFactory()
+ {
+ clearSingletonInstance();
+ }
+
+ juce_DeclareSingleton (SharedD2DFactory, false);
+
+ ComSmartPtr d2dFactory;
+ ComSmartPtr directWriteFactory;
+ ComSmartPtr systemFonts;
+};
+
+juce_ImplementSingleton (SharedD2DFactory)
+
+class Direct2DLowLevelGraphicsContext : public LowLevelGraphicsContext
+{
+public:
+ Direct2DLowLevelGraphicsContext (HWND hwnd_)
+ : hwnd (hwnd_),
+ currentState (0)
+ {
+ RECT windowRect;
+ GetClientRect (hwnd, &windowRect);
+ D2D1_SIZE_U size = { windowRect.right - windowRect.left, windowRect.bottom - windowRect.top };
+ bounds.setSize (size.width, size.height);
+
+ D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties();
+ D2D1_HWND_RENDER_TARGET_PROPERTIES propsHwnd = D2D1::HwndRenderTargetProperties (hwnd, size);
+
+ HRESULT hr = SharedD2DFactory::getInstance()->d2dFactory->CreateHwndRenderTarget (props, propsHwnd, &renderingTarget);
+ // xxx check for error
+
+ hr = renderingTarget->CreateSolidColorBrush (D2D1::ColorF::ColorF (0.0f, 0.0f, 0.0f, 1.0f), &colourBrush);
+ }
+
+ ~Direct2DLowLevelGraphicsContext()
+ {
+ states.clear();
+ }
+
+ void resized()
+ {
+ RECT windowRect;
+ GetClientRect (hwnd, &windowRect);
+ D2D1_SIZE_U size = { windowRect.right - windowRect.left, windowRect.bottom - windowRect.top };
+
+ renderingTarget->Resize (size);
+ bounds.setSize (size.width, size.height);
+ }
+
+ void clear()
+ {
+ renderingTarget->Clear (D2D1::ColorF (D2D1::ColorF::White, 0.0f)); // xxx why white and not black?
+ }
+
+ void start()
+ {
+ renderingTarget->BeginDraw();
+ saveState();
+ }
+
+ void end()
+ {
+ states.clear();
+ currentState = 0;
+ renderingTarget->EndDraw();
+ renderingTarget->CheckWindowState();
+ }
+
+ bool isVectorDevice() const { return false; }
+
+ void setOrigin (int x, int y)
+ {
+ currentState->origin.addXY (x, y);
+ }
+
+ bool clipToRectangle (const Rectangle& r)
+ {
+ currentState->clipToRectangle (r);
+ return ! isClipEmpty();
+ }
+
+ bool clipToRectangleList (const RectangleList& clipRegion)
+ {
+ currentState->clipToRectList (rectListToPathGeometry (clipRegion));
+ return ! isClipEmpty();
+ }
+
+ void excludeClipRectangle (const Rectangle&)
+ {
+ //xxx
+ }
+
+ void clipToPath (const Path& path, const AffineTransform& transform)
+ {
+ currentState->clipToPath (pathToPathGeometry (path, transform, currentState->origin));
+ }
+
+ void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform)
+ {
+ currentState->clipToImage (sourceImage,transform);
+ }
+
+ bool clipRegionIntersects (const Rectangle& r)
+ {
+ const Rectangle r2 (r + currentState->origin);
+ return currentState->clipRect.intersects (r2);
+ }
+
+ const Rectangle getClipBounds() const
+ {
+ // xxx could this take into account complex clip regions?
+ return currentState->clipRect - currentState->origin;
+ }
+
+ bool isClipEmpty() const
+ {
+ return currentState->clipRect.isEmpty();
+ }
+
+ void saveState()
+ {
+ states.add (new SavedState (*this));
+ currentState = states.getLast();
+ }
+
+ void restoreState()
+ {
+ jassert (states.size() > 1) //you should never pop the last state!
+ states.removeLast (1);
+ currentState = states.getLast();
+ }
+
+ void setFill (const FillType& fillType)
+ {
+ currentState->setFill (fillType);
+ }
+
+ void setOpacity (float newOpacity)
+ {
+ currentState->setOpacity (newOpacity);
+ }
+
+ void setInterpolationQuality (Graphics::ResamplingQuality /*quality*/)
+ {
+ }
+
+ void fillRect (const Rectangle& r, bool replaceExistingContents)
+ {
+ currentState->createBrush();
+ renderingTarget->FillRectangle (rectangleToRectF (r + currentState->origin), currentState->currentBrush);
+ }
+
+ void fillPath (const Path& p, const AffineTransform& transform)
+ {
+ currentState->createBrush();
+ ComSmartPtr geometry (pathToPathGeometry (p, transform, currentState->origin));
+
+ if (renderingTarget != 0)
+ renderingTarget->FillGeometry (geometry, currentState->currentBrush);
+ }
+
+ void drawImage (const Image& image, const AffineTransform& transform, bool fillEntireClipAsTiles)
+ {
+ const int x = currentState->origin.getX();
+ const int y = currentState->origin.getY();
+
+ renderingTarget->SetTransform (transfromToMatrix (transform) * D2D1::Matrix3x2F::Translation (x, y));
+
+ D2D1_SIZE_U size;
+ size.width = image.getWidth();
+ size.height = image.getHeight();
+
+ D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties();
+
+ Image img (image.convertedToFormat (Image::ARGB));
+ Image::BitmapData bd (img, false);
+ bp.pixelFormat = renderingTarget->GetPixelFormat();
+ bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
+
+ {
+ ComSmartPtr tempBitmap;
+ renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, &tempBitmap);
+ if (tempBitmap != 0)
+ renderingTarget->DrawBitmap (tempBitmap);
+ }
+
+ renderingTarget->SetTransform (D2D1::IdentityMatrix());
+ }
+
+ void drawLine (const Line & line)
+ {
+ // xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour
+ const Line l (line.getStart() + currentState->origin.toFloat(),
+ line.getEnd() + currentState->origin.toFloat());
+
+ currentState->createBrush();
+
+ renderingTarget->DrawLine (D2D1::Point2F (l.getStartX(), l.getStartY()),
+ D2D1::Point2F (l.getEndX(), l.getEndY()),
+ currentState->currentBrush);
+ }
+
+ void drawVerticalLine (int x, float top, float bottom)
+ {
+ // xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour
+ currentState->createBrush();
+
+ x += currentState->origin.getX();
+ const int y = currentState->origin.getY();
+
+ renderingTarget->DrawLine (D2D1::Point2F (x, y + top),
+ D2D1::Point2F (x, y + bottom),
+ currentState->currentBrush);
+ }
+
+ void drawHorizontalLine (int y, float left, float right)
+ {
+ // xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour
+ currentState->createBrush();
+
+ y += currentState->origin.getY();
+ const int x = currentState->origin.getX();
+
+ renderingTarget->DrawLine (D2D1::Point2F (x + left, y),
+ D2D1::Point2F (x + right, y),
+ currentState->currentBrush);
+ }
+
+ void setFont (const Font& newFont)
+ {
+ currentState->setFont (newFont);
+ }
+
+ const Font getFont()
+ {
+ return currentState->font;
+ }
+
+ void drawGlyph (int glyphNumber, const AffineTransform& transform)
+ {
+ const float x = currentState->origin.getX();
+ const float y = currentState->origin.getY();
+
+ currentState->createBrush();
+ currentState->createFont();
+
+ float kerning = currentState->font.getExtraKerningFactor(); // xxx why does removing this line mess up the kerning??
+ float hScale = currentState->font.getHorizontalScale();
+
+ renderingTarget->SetTransform (D2D1::Matrix3x2F::Scale (hScale, 1) * transfromToMatrix (transform) * D2D1::Matrix3x2F::Translation (x, y));
+
+ float dpiX = 0, dpiY = 0;
+ SharedD2DFactory::getInstance()->d2dFactory->GetDesktopDpi (&dpiX, &dpiY);
+
+ UINT32 glyphNum = glyphNumber;
+ UINT16 glyphNum1 = 0; // xxx needs a better name - what is this for?
+ currentState->currentFontFace->GetGlyphIndices (&glyphNum, 1, &glyphNum1);
+
+ DWRITE_GLYPH_OFFSET offset;
+ offset.advanceOffset = 0;
+ offset.ascenderOffset = 0;
+ float glyphAdvances = 0;
+
+ DWRITE_GLYPH_RUN glyph;
+ glyph.fontFace = currentState->currentFontFace;
+ glyph.glyphCount = 1;
+ glyph.glyphIndices = &glyphNum1;
+ glyph.isSideways = FALSE;
+ glyph.glyphAdvances = &glyphAdvances;
+ glyph.glyphOffsets = &offset;
+ glyph.fontEmSize = (float) currentState->font.getHeight() * dpiX / 96.0f * (1 + currentState->fontScaling) / 2;
+
+ renderingTarget->DrawGlyphRun (D2D1::Point2F (0, 0), &glyph, currentState->currentBrush);
+ renderingTarget->SetTransform (D2D1::IdentityMatrix());
+ }
+
+ class SavedState
+ {
+ public:
+ SavedState (Direct2DLowLevelGraphicsContext& owner_)
+ : owner (owner_), currentBrush (0),
+ fontScaling (1.0f), currentFontFace (0),
+ clipsRect (false), shouldClipRect (false),
+ clipsRectList (false), shouldClipRectList (false),
+ clipsComplex (false), shouldClipComplex (false),
+ clipsBitmap (false), shouldClipBitmap (false)
+ {
+ if (owner.currentState != 0)
+ {
+ // xxx seems like a very slow way to create one of these, and this is a performance
+ // bottleneck.. Can the same internal objects be shared by multiple state objects, maybe using copy-on-write?
+ setFill (owner.currentState->fillType);
+ currentBrush = owner.currentState->currentBrush;
+ origin = owner.currentState->origin;
+ clipRect = owner.currentState->clipRect;
+
+ font = owner.currentState->font;
+ currentFontFace = owner.currentState->currentFontFace;
+ }
+ else
+ {
+ const D2D1_SIZE_U size (owner.renderingTarget->GetPixelSize());
+ clipRect.setSize (size.width, size.height);
+ setFill (FillType (Colours::black));
+ }
+ }
+
+ ~SavedState()
+ {
+ clearClip();
+ clearFont();
+ clearFill();
+ clearPathClip();
+ clearImageClip();
+ complexClipLayer = 0;
+ bitmapMaskLayer = 0;
+ }
+
+ void clearClip()
+ {
+ popClips();
+ shouldClipRect = false;
+ }
+
+ void clipToRectangle (const Rectangle& r)
+ {
+ clearClip();
+ clipRect = r + origin;
+ shouldClipRect = true;
+ pushClips();
+ }
+
+ void clearPathClip()
+ {
+ popClips();
+
+ if (shouldClipComplex)
+ {
+ complexClipGeometry = 0;
+ shouldClipComplex = false;
+ }
+ }
+
+ void clipToPath (ID2D1Geometry* geometry)
+ {
+ clearPathClip();
+
+ if (complexClipLayer == 0)
+ owner.renderingTarget->CreateLayer (&complexClipLayer);
+
+ complexClipGeometry = geometry;
+ shouldClipComplex = true;
+ pushClips();
+ }
+
+ void clearRectListClip()
+ {
+ popClips();
+
+ if (shouldClipRectList)
+ {
+ rectListGeometry = 0;
+ shouldClipRectList = false;
+ }
+ }
+
+ void clipToRectList (ID2D1Geometry* geometry)
+ {
+ clearRectListClip();
+
+ if (rectListLayer == 0)
+ owner.renderingTarget->CreateLayer (&rectListLayer);
+
+ rectListGeometry = geometry;
+ shouldClipRectList = true;
+ pushClips();
+ }
+
+ void clearImageClip()
+ {
+ popClips();
+
+ if (shouldClipBitmap)
+ {
+ maskBitmap = 0;
+ bitmapMaskBrush = 0;
+ shouldClipBitmap = false;
+ }
+ }
+
+ void clipToImage (const Image& image, const AffineTransform& transform)
+ {
+ clearImageClip();
+
+ if (bitmapMaskLayer == 0)
+ owner.renderingTarget->CreateLayer (&bitmapMaskLayer);
+
+ D2D1_BRUSH_PROPERTIES brushProps;
+ brushProps.opacity = 1;
+ brushProps.transform = transfromToMatrix (transform);
+
+ D2D1_BITMAP_BRUSH_PROPERTIES bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP);
+
+ D2D1_SIZE_U size;
+ size.width = image.getWidth();
+ size.height = image.getHeight();
+
+ D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties();
+
+ maskImage = image.convertedToFormat (Image::ARGB);
+ Image::BitmapData bd (this->image, false); // xxx should be maskImage?
+ bp.pixelFormat = owner.renderingTarget->GetPixelFormat();
+ bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
+
+ HRESULT hr = owner.renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, &maskBitmap);
+ hr = owner.renderingTarget->CreateBitmapBrush (maskBitmap, bmProps, brushProps, &bitmapMaskBrush);
+
+ imageMaskLayerParams = D2D1::LayerParameters();
+ imageMaskLayerParams.opacityBrush = bitmapMaskBrush;
+
+ shouldClipBitmap = true;
+ pushClips();
+ }
+
+ void popClips()
+ {
+ if (clipsBitmap)
+ {
+ owner.renderingTarget->PopLayer();
+ clipsBitmap = false;
+ }
+
+ if (clipsComplex)
+ {
+ owner.renderingTarget->PopLayer();
+ clipsComplex = false;
+ }
+
+ if (clipsRectList)
+ {
+ owner.renderingTarget->PopLayer();
+ clipsRectList = false;
+ }
+
+ if (clipsRect)
+ {
+ owner.renderingTarget->PopAxisAlignedClip();
+ clipsRect = false;
+ }
+ }
+
+ void pushClips()
+ {
+ if (shouldClipRect && ! clipsRect)
+ {
+ owner.renderingTarget->PushAxisAlignedClip (rectangleToRectF (clipRect), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
+ clipsRect = true;
+ }
+
+ if (shouldClipRectList && ! clipsRectList)
+ {
+ D2D1_LAYER_PARAMETERS layerParams = D2D1::LayerParameters();
+ rectListGeometry->GetBounds (D2D1::IdentityMatrix(), &layerParams.contentBounds);
+ layerParams.geometricMask = rectListGeometry;
+ owner.renderingTarget->PushLayer (layerParams, rectListLayer);
+ clipsRectList = true;
+ }
+
+ if (shouldClipComplex && ! clipsComplex)
+ {
+ D2D1_LAYER_PARAMETERS layerParams = D2D1::LayerParameters();
+ complexClipGeometry->GetBounds (D2D1::IdentityMatrix(), &layerParams.contentBounds);
+ layerParams.geometricMask = complexClipGeometry;
+ owner.renderingTarget->PushLayer (layerParams, complexClipLayer);
+ clipsComplex = true;
+ }
+
+ if (shouldClipBitmap && ! clipsBitmap)
+ {
+ owner.renderingTarget->PushLayer (imageMaskLayerParams, bitmapMaskLayer);
+ clipsBitmap = true;
+ }
+ }
+
+ void setFill (const FillType& newFillType)
+ {
+ if (fillType != newFillType)
+ {
+ fillType = newFillType;
+ clearFill();
+ }
+ }
+
+ void clearFont()
+ {
+ currentFontFace = localFontFace = 0;
+ }
+
+ void setFont (const Font& newFont)
+ {
+ if (font != newFont)
+ {
+ font = newFont;
+ clearFont();
+ }
+ }
+
+ void createFont()
+ {
+ // xxx The font shouldn't be managed by the graphics context.
+ // The correct way to handle font lifetimes is to use a subclass of Typeface - see
+ // MacTypeface and WindowsTypeface classes. D2D support could probably just be added to the
+ // WindowsTypeface class.
+
+ if (currentFontFace == 0)
+ {
+ WindowsTypeface* systemType = dynamic_cast (font.getTypeface());
+ fontScaling = systemType->getAscent();
+
+ BOOL fontFound;
+ uint32 fontIndex;
+
+ IDWriteFontCollection* fonts = SharedD2DFactory::getInstance()->systemFonts;
+
+ fonts->FindFamilyName (systemType->getName(), &fontIndex, &fontFound);
+ if (! fontFound)
+ fontIndex = 0;
+
+ ComSmartPtr fontFam;
+ fonts->GetFontFamily (fontIndex, &fontFam);
+
+ ComSmartPtr font;
+ DWRITE_FONT_WEIGHT weight = this->font.isBold() ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL;
+ DWRITE_FONT_STYLE style = this->font.isItalic() ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
+ fontFam->GetFirstMatchingFont (weight, DWRITE_FONT_STRETCH_NORMAL, style, &font);
+
+ font->CreateFontFace (&localFontFace);
+ currentFontFace = localFontFace;
+ }
+ }
+
+ void setOpacity (float newOpacity)
+ {
+ fillType.setOpacity (newOpacity);
+
+ if (currentBrush != 0)
+ currentBrush->SetOpacity (newOpacity);
+ }
+
+ void clearFill()
+ {
+ gradientStops = 0;
+ linearGradient = 0;
+ radialGradient = 0;
+ bitmap = 0;
+ bitmapBrush = 0;
+ currentBrush = 0;
+ }
+
+ void createBrush()
+ {
+ if (currentBrush == 0)
+ {
+ const int x = origin.getX();
+ const int y = origin.getY();
+
+ if (fillType.isColour())
+ {
+ D2D1_COLOR_F colour = colourToD2D (fillType.colour);
+ owner.colourBrush->SetColor (colour);
+ currentBrush = owner.colourBrush;
+ }
+ else if (fillType.isTiledImage())
+ {
+ D2D1_BRUSH_PROPERTIES brushProps;
+ brushProps.opacity = fillType.getOpacity();
+ brushProps.transform = transfromToMatrix (fillType.transform);
+
+ D2D1_BITMAP_BRUSH_PROPERTIES bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP,D2D1_EXTEND_MODE_WRAP);
+
+ image = fillType.image;
+
+ D2D1_SIZE_U size;
+ size.width = image.getWidth();
+ size.height = image.getHeight();
+
+ D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties();
+
+ this->image = image.convertedToFormat (Image::ARGB);
+ Image::BitmapData bd (this->image, false);
+ bp.pixelFormat = owner.renderingTarget->GetPixelFormat();
+ bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
+
+ HRESULT hr = owner.renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, &bitmap);
+ hr = owner.renderingTarget->CreateBitmapBrush (bitmap, bmProps, brushProps, &bitmapBrush);
+
+ currentBrush = bitmapBrush;
+ }
+ else if (fillType.isGradient())
+ {
+ gradientStops = 0;
+
+ D2D1_BRUSH_PROPERTIES brushProps;
+ brushProps.opacity = fillType.getOpacity();
+ brushProps.transform = transfromToMatrix (fillType.transform);
+
+ const int numColors = fillType.gradient->getNumColours();
+
+ HeapBlock stops (numColors);
+
+ for (int i = fillType.gradient->getNumColours(); --i >= 0;)
+ {
+ stops[i].color = colourToD2D (fillType.gradient->getColour(i));
+ stops[i].position = fillType.gradient->getColourPosition(i);
+ }
+
+ owner.renderingTarget->CreateGradientStopCollection (stops.getData(), numColors, &gradientStops);
+
+ if (fillType.gradient->isRadial)
+ {
+ radialGradient = 0;
+
+ const Point& p1 = fillType.gradient->point1;
+ const Point& p2 = fillType.gradient->point2;
+ float r = p1.getDistanceFrom (p2);
+
+ D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES props =
+ D2D1::RadialGradientBrushProperties (D2D1::Point2F (p1.getX() + x, p1.getY() + y),
+ D2D1::Point2F (0, 0),
+ r, r);
+
+ owner.renderingTarget->CreateRadialGradientBrush (props, brushProps, gradientStops, &radialGradient);
+ currentBrush = radialGradient;
+ }
+ else
+ {
+ linearGradient = 0;
+
+ const Point& p1 = fillType.gradient->point1;
+ const Point& p2 = fillType.gradient->point2;
+
+ D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES props =
+ D2D1::LinearGradientBrushProperties (D2D1::Point2F (p1.getX() + x, p1.getY() + y),
+ D2D1::Point2F (p2.getX() + x, p2.getY() + y));
+
+ owner.renderingTarget->CreateLinearGradientBrush (props, brushProps, gradientStops, &linearGradient);
+
+ currentBrush = linearGradient;
+ }
+ }
+ }
+ }
+
+ juce_UseDebuggingNewOperator
+
+ //xxx most of these members should probably be private...
+
+ Direct2DLowLevelGraphicsContext& owner;
+
+ Point origin;
+
+ Font font;
+ float fontScaling;
+ IDWriteFontFace* currentFontFace;
+ ComSmartPtr localFontFace;
+
+ FillType fillType;
+
+ Image image;
+ ComSmartPtr bitmap; // xxx needs a better name - what is this for??
+
+ Rectangle clipRect;
+ bool clipsRect, shouldClipRect;
+
+ ComSmartPtr complexClipGeometry;
+ D2D1_LAYER_PARAMETERS complexClipLayerParams;
+ ComSmartPtr complexClipLayer;
+ bool clipsComplex, shouldClipComplex;
+
+ ComSmartPtr rectListGeometry;
+ D2D1_LAYER_PARAMETERS rectListLayerParams;
+ ComSmartPtr rectListLayer;
+ bool clipsRectList, shouldClipRectList;
+
+ Image maskImage;
+ D2D1_LAYER_PARAMETERS imageMaskLayerParams;
+ ComSmartPtr bitmapMaskLayer;
+ ComSmartPtr maskBitmap;
+ ComSmartPtr bitmapMaskBrush;
+ bool clipsBitmap, shouldClipBitmap;
+
+ ID2D1Brush* currentBrush;
+ ComSmartPtr bitmapBrush;
+ ComSmartPtr linearGradient;
+ ComSmartPtr radialGradient;
+ ComSmartPtr gradientStops;
+
+ private:
+ SavedState (const SavedState&);
+ SavedState& operator= (const SavedState& other);
+ };
+
+ juce_UseDebuggingNewOperator
+
+private:
+ HWND hwnd;
+ ComSmartPtr renderingTarget;
+ ComSmartPtr colourBrush;
+ Rectangle bounds;
+
+ SavedState* currentState;
+ OwnedArray states;
+
+ static D2D1_RECT_F rectangleToRectF (const Rectangle& r)
+ {
+ return D2D1::RectF ((float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom());
+ }
+
+ static const D2D1_COLOR_F colourToD2D (const Colour& c)
+ {
+ return D2D1::ColorF::ColorF (c.getFloatRed(), c.getFloatGreen(), c.getFloatBlue(), c.getFloatAlpha());
+ }
+
+ static const D2D1_POINT_2F pointTransformed (int x, int y, const AffineTransform& transform = AffineTransform::identity)
+ {
+ transform.transformPoint (x, y);
+ return D2D1::Point2F (x, y);
+ }
+
+ static void rectToGeometrySink (const Rectangle& rect, ID2D1GeometrySink* sink)
+ {
+ sink->BeginFigure (pointTransformed (rect.getX(), rect.getY()), D2D1_FIGURE_BEGIN_FILLED);
+ sink->AddLine (pointTransformed (rect.getRight(), rect.getY()));
+ sink->AddLine (pointTransformed (rect.getRight(), rect.getBottom()));
+ sink->AddLine (pointTransformed (rect.getX(), rect.getBottom()));
+ sink->EndFigure (D2D1_FIGURE_END_CLOSED);
+ }
+
+ static ID2D1PathGeometry* rectListToPathGeometry (const RectangleList& clipRegion)
+ {
+ ID2D1PathGeometry* p = 0;
+ SharedD2DFactory::getInstance()->d2dFactory->CreatePathGeometry (&p);
+
+ ComSmartPtr sink;
+ HRESULT hr = p->Open (&sink); // xxx handle error
+ sink->SetFillMode (D2D1_FILL_MODE_WINDING);
+
+ for (int i = clipRegion.getNumRectangles(); --i >= 0;)
+ rectToGeometrySink (clipRegion.getRectangle(i), sink);
+
+ hr = sink->Close();
+ return p;
+ }
+
+ static void pathToGeometrySink (const Path& path, ID2D1GeometrySink* sink, const AffineTransform& transform, int x, int y)
+ {
+ Path::Iterator it (path);
+
+ while (it.next())
+ {
+ switch (it.elementType)
+ {
+ case Path::Iterator::cubicTo:
+ {
+ D2D1_BEZIER_SEGMENT seg;
+
+ transform.transformPoint (it.x1, it.y1);
+ seg.point1 = D2D1::Point2F (it.x1 + x, it.y1 + y);
+
+ transform.transformPoint (it.x2, it.y2);
+ seg.point2 = D2D1::Point2F (it.x2 + x, it.y2 + y);
+
+ transform.transformPoint(it.x3, it.y3);
+ seg.point3 = D2D1::Point2F (it.x3 + x, it.y3 + y);
+
+ sink->AddBezier (seg);
+ break;
+ }
+
+ case Path::Iterator::lineTo:
+ {
+ transform.transformPoint (it.x1, it.y1);
+ sink->AddLine (D2D1::Point2F (it.x1 + x, it.y1 + y));
+ break;
+ }
+
+ case Path::Iterator::quadraticTo:
+ {
+ D2D1_QUADRATIC_BEZIER_SEGMENT seg;
+
+ transform.transformPoint (it.x1, it.y1);
+ seg.point1 = D2D1::Point2F (it.x1 + x, it.y1 + y);
+
+ transform.transformPoint (it.x2, it.y2);
+ seg.point2 = D2D1::Point2F (it.x2 + x, it.y2 + y);
+
+ sink->AddQuadraticBezier (seg);
+ break;
+ }
+
+ case Path::Iterator::closePath:
+ {
+ sink->EndFigure (D2D1_FIGURE_END_CLOSED);
+ break;
+ }
+
+ case Path::Iterator::startNewSubPath:
+ {
+ transform.transformPoint (it.x1, it.y1);
+ sink->BeginFigure (D2D1::Point2F (it.x1 + x, it.y1 + y), D2D1_FIGURE_BEGIN_FILLED);
+ break;
+ }
+ }
+ }
+ }
+
+ static ID2D1PathGeometry* pathToPathGeometry (const Path& path, const AffineTransform& transform, const Point& point)
+ {
+ ID2D1PathGeometry* p = 0;
+ SharedD2DFactory::getInstance()->d2dFactory->CreatePathGeometry (&p);
+
+ ComSmartPtr sink;
+ HRESULT hr = p->Open (&sink);
+ sink->SetFillMode (D2D1_FILL_MODE_WINDING); // xxx need to check Path::isUsingNonZeroWinding()
+
+ pathToGeometrySink (path, sink, transform, point.getX(), point.getY());
+
+ hr = sink->Close();
+ return p;
+ }
+
+ static const D2D1::Matrix3x2F transfromToMatrix (const AffineTransform& transform)
+ {
+ D2D1::Matrix3x2F matrix;
+ matrix._11 = transform.mat00;
+ matrix._12 = transform.mat10;
+ matrix._21 = transform.mat01;
+ matrix._22 = transform.mat11;
+ matrix._31 = transform.mat02;
+ matrix._32 = transform.mat12;
+ return matrix;
+ }
+};
+
+#endif
+/*** End of inlined file: juce_win32_Direct2DGraphicsContext.cpp ***/
+
+
/*** Start of inlined file: juce_win32_Windowing.cpp ***/
// (This file gets included by juce_win32_NativeCode.cpp, rather than being
// compiled on its own).
@@ -240236,11 +241482,21 @@ static void* callFunctionIfNotLocked (MessageCallbackFunction* callback, void* u
class Win32ComponentPeer : public ComponentPeer
{
public:
+ enum RenderingEngineType
+ {
+ softwareRenderingEngine = 0,
+ direct2DRenderingEngine
+ };
Win32ComponentPeer (Component* const component,
const int windowStyleFlags)
: ComponentPeer (component, windowStyleFlags),
dontRepaint (false),
+ #if JUCE_DIRECT2D
+ currentRenderingEngine (direct2DRenderingEngine),
+ #else
+ currentRenderingEngine (softwareRenderingEngine),
+ #endif
fullScreen (false),
isDragging (false),
isMouseOver (false),
@@ -240281,6 +241537,10 @@ public:
dropTarget->Release();
dropTarget = 0;
}
+
+ #if JUCE_DIRECT2D
+ direct2DContext = 0;
+ #endif
}
void* getNativeHandle() const
@@ -240331,6 +241591,11 @@ public:
info.rcWindow.bottom - info.rcClient.bottom,
info.rcWindow.right - info.rcClient.right);
}
+
+ #if JUCE_DIRECT2D
+ if (direct2DContext != 0)
+ direct2DContext->resized();
+ #endif
}
void setSize (int w, int h)
@@ -240691,6 +241956,10 @@ public:
private:
HWND hwnd;
ScopedPointer shadower;
+ RenderingEngineType currentRenderingEngine;
+ #if JUCE_DIRECT2D
+ ScopedPointer direct2DContext;
+ #endif
bool fullScreen, isDragging, isMouseOver, hasCreatedCaret;
BorderSize windowBorder;
HICON currentWindowIcon;
@@ -240832,6 +242101,10 @@ private:
hwnd = CreateWindowEx (exstyle, WindowClassHolder::getInstance()->windowClassName, L"", type, 0, 0, 0, 0, 0, 0, 0, 0);
+ #if JUCE_DIRECT2D
+ updateDirect2DContext();
+ #endif
+
if (hwnd != 0)
{
SetWindowLongPtr (hwnd, 0, 0);
@@ -240926,129 +242199,146 @@ private:
void handlePaintMessage()
{
- HRGN rgn = CreateRectRgn (0, 0, 0, 0);
- const int regionType = GetUpdateRgn (hwnd, rgn, false);
-
- PAINTSTRUCT paintStruct;
- HDC dc = BeginPaint (hwnd, &paintStruct); // Note this can immediately generate a WM_NCPAINT
- // message and become re-entrant, but that's OK
-
- // if something in a paint handler calls, e.g. a message box, this can become reentrant and
- // corrupt the image it's using to paint into, so do a check here.
- static bool reentrant = false;
- if (reentrant)
+#if JUCE_DIRECT2D
+ if (direct2DContext != 0)
{
- DeleteObject (rgn);
- EndPaint (hwnd, &paintStruct);
- return;
+ RECT r;
+
+ if (GetUpdateRect (hwnd, &r, false))
+ {
+ direct2DContext->start();
+ direct2DContext->clipToRectangle (Rectangle (r.left, r.top, r.right - r.left, r.bottom - r.top));
+ handlePaint (*direct2DContext);
+ direct2DContext->end();
+ }
}
+ else
+#endif
+ {
+ HRGN rgn = CreateRectRgn (0, 0, 0, 0);
+ const int regionType = GetUpdateRgn (hwnd, rgn, false);
- reentrant = true;
+ PAINTSTRUCT paintStruct;
+ HDC dc = BeginPaint (hwnd, &paintStruct); // Note this can immediately generate a WM_NCPAINT
+ // message and become re-entrant, but that's OK
- // this is the rectangle to update..
- int x = paintStruct.rcPaint.left;
- int y = paintStruct.rcPaint.top;
- int w = paintStruct.rcPaint.right - x;
- int h = paintStruct.rcPaint.bottom - y;
+ // if something in a paint handler calls, e.g. a message box, this can become reentrant and
+ // corrupt the image it's using to paint into, so do a check here.
+ static bool reentrant = false;
+ if (reentrant)
+ {
+ DeleteObject (rgn);
+ EndPaint (hwnd, &paintStruct);
+ return;
+ }
- const bool transparent = isTransparent();
+ reentrant = true;
- if (transparent)
- {
- // it's not possible to have a transparent window with a title bar at the moment!
- jassert (! hasTitleBar());
+ // this is the rectangle to update..
+ int x = paintStruct.rcPaint.left;
+ int y = paintStruct.rcPaint.top;
+ int w = paintStruct.rcPaint.right - x;
+ int h = paintStruct.rcPaint.bottom - y;
- RECT r;
- GetWindowRect (hwnd, &r);
- x = y = 0;
- w = r.right - r.left;
- h = r.bottom - r.top;
- }
+ const bool transparent = isTransparent();
- if (w > 0 && h > 0)
- {
- clearMaskedRegion();
+ if (transparent)
+ {
+ // it's not possible to have a transparent window with a title bar at the moment!
+ jassert (! hasTitleBar());
- Image offscreenImage (offscreenImageGenerator.getImage (transparent, w, h));
+ RECT r;
+ GetWindowRect (hwnd, &r);
+ x = y = 0;
+ w = r.right - r.left;
+ h = r.bottom - r.top;
+ }
- RectangleList contextClip;
- const Rectangle clipBounds (0, 0, w, h);
+ if (w > 0 && h > 0)
+ {
+ clearMaskedRegion();
- bool needToPaintAll = true;
+ Image offscreenImage (offscreenImageGenerator.getImage (transparent, w, h));
- if (regionType == COMPLEXREGION && ! transparent)
- {
- HRGN clipRgn = CreateRectRgnIndirect (&paintStruct.rcPaint);
- CombineRgn (rgn, rgn, clipRgn, RGN_AND);
- DeleteObject (clipRgn);
+ RectangleList contextClip;
+ const Rectangle clipBounds (0, 0, w, h);
- char rgnData [8192];
- const DWORD res = GetRegionData (rgn, sizeof (rgnData), (RGNDATA*) rgnData);
+ bool needToPaintAll = true;
- if (res > 0 && res <= sizeof (rgnData))
+ if (regionType == COMPLEXREGION && ! transparent)
{
- const RGNDATAHEADER* const hdr = &(((const RGNDATA*) rgnData)->rdh);
+ HRGN clipRgn = CreateRectRgnIndirect (&paintStruct.rcPaint);
+ CombineRgn (rgn, rgn, clipRgn, RGN_AND);
+ DeleteObject (clipRgn);
- if (hdr->iType == RDH_RECTANGLES
- && hdr->rcBound.right - hdr->rcBound.left >= w
- && hdr->rcBound.bottom - hdr->rcBound.top >= h)
- {
- needToPaintAll = false;
+ char rgnData [8192];
+ const DWORD res = GetRegionData (rgn, sizeof (rgnData), (RGNDATA*) rgnData);
- const RECT* rects = (const RECT*) (rgnData + sizeof (RGNDATAHEADER));
- int num = ((RGNDATA*) rgnData)->rdh.nCount;
+ if (res > 0 && res <= sizeof (rgnData))
+ {
+ const RGNDATAHEADER* const hdr = &(((const RGNDATA*) rgnData)->rdh);
- while (--num >= 0)
+ if (hdr->iType == RDH_RECTANGLES
+ && hdr->rcBound.right - hdr->rcBound.left >= w
+ && hdr->rcBound.bottom - hdr->rcBound.top >= h)
{
- if (rects->right <= x + w && rects->bottom <= y + h)
- {
- // (need to move this one pixel to the left because of a win32 bug)
- const int cx = jmax (x, (int) rects->left - 1);
- contextClip.addWithoutMerging (Rectangle (cx - x, rects->top - y, rects->right - cx, rects->bottom - rects->top)
- .getIntersection (clipBounds));
- }
- else
+ needToPaintAll = false;
+
+ const RECT* rects = (const RECT*) (rgnData + sizeof (RGNDATAHEADER));
+ int num = ((RGNDATA*) rgnData)->rdh.nCount;
+
+ while (--num >= 0)
{
- needToPaintAll = true;
- break;
- }
+ if (rects->right <= x + w && rects->bottom <= y + h)
+ {
+ // (need to move this one pixel to the left because of a win32 bug)
+ const int cx = jmax (x, (int) rects->left - 1);
+ contextClip.addWithoutMerging (Rectangle (cx - x, rects->top - y, rects->right - cx, rects->bottom - rects->top)
+ .getIntersection (clipBounds));
+ }
+ else
+ {
+ needToPaintAll = true;
+ break;
+ }
- ++rects;
+ ++rects;
+ }
}
}
}
- }
- if (needToPaintAll)
- {
- contextClip.clear();
- contextClip.addWithoutMerging (Rectangle (w, h));
- }
+ if (needToPaintAll)
+ {
+ contextClip.clear();
+ contextClip.addWithoutMerging (Rectangle (w, h));
+ }
- if (transparent)
- {
- RectangleList::Iterator i (contextClip);
+ if (transparent)
+ {
+ RectangleList::Iterator i (contextClip);
- while (i.next())
- offscreenImage.clear (*i.getRectangle());
- }
+ while (i.next())
+ offscreenImage.clear (*i.getRectangle());
+ }
- // if the component's not opaque, this won't draw properly unless the platform can support this
- jassert (Desktop::canUseSemiTransparentWindows() || component->isOpaque());
+ // if the component's not opaque, this won't draw properly unless the platform can support this
+ jassert (Desktop::canUseSemiTransparentWindows() || component->isOpaque());
- updateCurrentModifiers();
+ updateCurrentModifiers();
- LowLevelGraphicsSoftwareRenderer context (offscreenImage, -x, -y, contextClip);
- handlePaint (context);
+ LowLevelGraphicsSoftwareRenderer context (offscreenImage, -x, -y, contextClip);
+ handlePaint (context);
- if (! dontRepaint)
- static_cast (offscreenImage.getSharedImage())
- ->blitToWindow (hwnd, dc, transparent, x, y, maskedRegion);
- }
+ if (! dontRepaint)
+ static_cast (offscreenImage.getSharedImage())
+ ->blitToWindow (hwnd, dc, transparent, x, y, maskedRegion);
+ }
- DeleteObject (rgn);
- EndPaint (hwnd, &paintStruct);
- reentrant = false;
+ DeleteObject (rgn);
+ EndPaint (hwnd, &paintStruct);
+ reentrant = false;
+ }
#ifndef JUCE_GCC //xxx should add this fn for gcc..
_fpreset(); // because some graphics cards can unmask FP exceptions
@@ -241062,6 +242352,48 @@ private:
handleMouseEvent (0, position, currentModifiers, getMouseEventTime());
}
+ const StringArray getAvailableRenderingEngines()
+ {
+ StringArray s (ComponentPeer::getAvailableRenderingEngines());
+
+#if JUCE_DIRECT2D
+ // xxx is this correct? Seems to enable it on Vista too??
+ OSVERSIONINFO info;
+ zerostruct (info);
+ info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+ GetVersionEx (&info);
+ if (info.dwMajorVersion >= 6)
+ s.add ("Direct2D");
+#endif
+ return s;
+ }
+
+ int getCurrentRenderingEngine() throw()
+ {
+ return currentRenderingEngine;
+ }
+
+#if JUCE_DIRECT2D
+ void updateDirect2DContext()
+ {
+ if (currentRenderingEngine != direct2DRenderingEngine)
+ direct2DContext = 0;
+ else if (direct2DContext == 0)
+ direct2DContext = new Direct2DLowLevelGraphicsContext (hwnd);
+ }
+#endif
+
+ void setCurrentRenderingEngine (int index)
+ {
+ (void) index;
+
+#if JUCE_DIRECT2D
+ currentRenderingEngine = index == 1 ? direct2DRenderingEngine : softwareRenderingEngine;
+ updateDirect2DContext();
+ repaint (component->getLocalBounds());
+#endif
+ }
+
void doMouseMove (const Point& position)
{
if (! isMouseOver)
@@ -242628,371 +243960,6 @@ bool DragAndDropContainer::performExternalDragDropOfText (const String& text)
/*** End of inlined file: juce_win32_Windowing.cpp ***/
-/*** Start of inlined file: juce_win32_Fonts.cpp ***/
-// (This file gets included by juce_win32_NativeCode.cpp, rather than being
-// compiled on its own).
-#if JUCE_INCLUDED_FILE
-
-static int CALLBACK wfontEnum2 (ENUMLOGFONTEXW* lpelfe,
- NEWTEXTMETRICEXW*,
- int type,
- LPARAM lParam)
-{
- if (lpelfe != 0 && (type & RASTER_FONTTYPE) == 0)
- {
- const String fontName (lpelfe->elfLogFont.lfFaceName);
-
- ((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters ("@"));
- }
-
- return 1;
-}
-
-static int CALLBACK wfontEnum1 (ENUMLOGFONTEXW* lpelfe,
- NEWTEXTMETRICEXW*,
- int type,
- LPARAM lParam)
-{
- if (lpelfe != 0 && (type & RASTER_FONTTYPE) == 0)
- {
- LOGFONTW lf;
- zerostruct (lf);
-
- 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.copyToUnicode (lf.lfFaceName, LF_FACESIZE - 1);
-
- HDC dc = CreateCompatibleDC (0);
- EnumFontFamiliesEx (dc, &lf,
- (FONTENUMPROCW) &wfontEnum2,
- lParam, 0);
- DeleteDC (dc);
- }
-
- return 1;
-}
-
-const StringArray Font::findAllTypefaceNames()
-{
- StringArray results;
- HDC dc = CreateCompatibleDC (0);
-
- {
- LOGFONTW lf;
- zerostruct (lf);
-
- 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;
- lf.lfFaceName[0] = 0;
-
- EnumFontFamiliesEx (dc, &lf,
- (FONTENUMPROCW) &wfontEnum1,
- (LPARAM) &results, 0);
- }
-
- DeleteDC (dc);
-
- results.sort (true);
- return results;
-}
-
-extern bool juce_IsRunningInWine();
-
-void Font::getPlatformDefaultFontNames (String& defaultSans, String& defaultSerif, String& defaultFixed)
-{
- if (juce_IsRunningInWine())
- {
- // If we're running in Wine, then use fonts that might be available on Linux..
- defaultSans = "Bitstream Vera Sans";
- defaultSerif = "Bitstream Vera Serif";
- defaultFixed = "Bitstream Vera Sans Mono";
- }
- else
- {
- defaultSans = "Verdana";
- defaultSerif = "Times";
- defaultFixed = "Lucida Console";
- }
-}
-
-class FontDCHolder : private DeletedAtShutdown
-{
-public:
-
- FontDCHolder()
- : dc (0), numKPs (0), size (0),
- bold (false), italic (false)
- {
- }
-
- ~FontDCHolder()
- {
- if (dc != 0)
- {
- DeleteDC (dc);
- DeleteObject (fontH);
- }
-
- 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_;
-
- if (dc != 0)
- {
- DeleteDC (dc);
- DeleteObject (fontH);
- kps.free();
- }
-
- fontH = 0;
-
- dc = CreateCompatibleDC (0);
- SetMapperFlags (dc, 0);
- SetMapMode (dc, MM_TEXT);
-
- LOGFONTW lfw;
- zerostruct (lfw);
-
- lfw.lfCharSet = DEFAULT_CHARSET;
- lfw.lfClipPrecision = CLIP_DEFAULT_PRECIS;
- lfw.lfOutPrecision = OUT_OUTLINE_PRECIS;
- lfw.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
- lfw.lfQuality = PROOF_QUALITY;
- lfw.lfItalic = (BYTE) (italic ? TRUE : FALSE);
- lfw.lfWeight = bold ? FW_BOLD : FW_NORMAL;
- fontName.copyToUnicode (lfw.lfFaceName, LF_FACESIZE - 1);
-
- lfw.lfHeight = size > 0 ? size : -256;
- HFONT standardSizedFont = CreateFontIndirect (&lfw);
-
- if (standardSizedFont != 0)
- {
- if (SelectObject (dc, standardSizedFont) != 0)
- {
- fontH = standardSizedFont;
-
- if (size == 0)
- {
- OUTLINETEXTMETRIC otm;
- if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0)
- {
- lfw.lfHeight = -(int) otm.otmEMSquare;
- fontH = CreateFontIndirect (&lfw);
-
- SelectObject (dc, fontH);
- DeleteObject (standardSizedFont);
- }
- }
- }
- else
- {
- jassertfalse;
- }
- }
- else
- {
- jassertfalse;
- }
- }
-
- return dc;
- }
-
- KERNINGPAIR* getKerningPairs (int& numKPs_)
- {
- if (kps == 0)
- {
- numKPs = GetKerningPairs (dc, 0, 0);
- kps.calloc (numKPs);
- GetKerningPairs (dc, numKPs, kps);
- }
-
- numKPs_ = numKPs;
- return kps;
- }
-
-private:
-
- HFONT fontH;
- HDC dc;
- String fontName;
- HeapBlock kps;
- int numKPs, size;
- bool bold, italic;
-
- FontDCHolder (const FontDCHolder&);
- FontDCHolder& operator= (const FontDCHolder&);
-};
-
-juce_ImplementSingleton_SingleThreaded (FontDCHolder);
-
-class WindowsTypeface : public CustomTypeface
-{
-public:
- WindowsTypeface (const Font& font)
- {
- HDC dc = FontDCHolder::getInstance()->loadFont (font.getTypefaceName(),
- font.isBold(), font.isItalic(), 0);
-
- TEXTMETRIC tm;
- tm.tmAscent = tm.tmHeight = 1;
- tm.tmDefaultChar = 0;
- GetTextMetrics (dc, &tm);
-
- setCharacteristics (font.getTypefaceName(),
- tm.tmAscent / (float) tm.tmHeight,
- font.isBold(), font.isItalic(),
- tm.tmDefaultChar);
- }
-
- bool loadGlyphIfPossible (juce_wchar character)
- {
- HDC dc = FontDCHolder::getInstance()->loadFont (name, isBold, isItalic, 0);
-
- GLYPHMETRICS gm;
-
- {
- const WCHAR charToTest[] = { (WCHAR) character, 0 };
- WORD index = 0;
-
- if (GetGlyphIndices (dc, charToTest, 1, &index, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR
- && index == 0xffff)
- {
- return false;
- }
- }
-
- Path glyphPath;
-
- TEXTMETRIC tm;
- if (! GetTextMetrics (dc, &tm))
- {
- addGlyph (character, glyphPath, 0);
- return true;
- }
-
- const float height = (float) tm.tmHeight;
- static const MAT2 identityMatrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
-
- const int bufSize = GetGlyphOutline (dc, character, GGO_NATIVE,
- &gm, 0, 0, &identityMatrix);
-
- if (bufSize > 0)
- {
- HeapBlock data (bufSize);
-
- GetGlyphOutline (dc, character, GGO_NATIVE, &gm,
- bufSize, data, &identityMatrix);
-
- const TTPOLYGONHEADER* pheader = reinterpret_cast (data.getData());
-
- const float scaleX = 1.0f / height;
- const float scaleY = -1.0f / height;
-
- while ((char*) pheader < data + bufSize)
- {
- float x = scaleX * pheader->pfxStart.x.value;
- float y = scaleY * pheader->pfxStart.y.value;
-
- glyphPath.startNewSubPath (x, y);
-
- const TTPOLYCURVE* curve = (const TTPOLYCURVE*) ((const char*) pheader + sizeof (TTPOLYGONHEADER));
- const char* const curveEnd = ((const char*) pheader) + pheader->cb;
-
- while ((const char*) curve < curveEnd)
- {
- 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);
- }
- }
- else if (curve->wType == TT_PRIM_QSPLINE)
- {
- for (int i = 0; i < curve->cpfx - 1; ++i)
- {
- const float x2 = scaleX * curve->apfx[i].x.value;
- const float y2 = scaleY * curve->apfx[i].y.value;
- float x3, y3;
-
- 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;
- }
-
- glyphPath.quadraticTo (x2, y2, x3, y3);
-
- x = x3;
- y = y3;
- }
- }
-
- curve = (const TTPOLYCURVE*) &(curve->apfx [curve->cpfx]);
- }
-
- pheader = (const TTPOLYGONHEADER*) curve;
-
- glyphPath.closeSubPath();
- }
- }
-
- addGlyph (character, glyphPath, gm.gmCellIncX / height);
-
- int numKPs;
- const KERNINGPAIR* const kps = FontDCHolder::getInstance()->getKerningPairs (numKPs);
-
- for (int i = 0; i < numKPs; ++i)
- {
- if (kps[i].wFirst == character)
- addKerningPair (kps[i].wFirst, kps[i].wSecond,
- kps[i].iKernAmount / height);
- }
-
- return true;
- }
-
- juce_UseDebuggingNewOperator
-};
-
-const Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
-{
- return new WindowsTypeface (font);
-}
-
-#endif
-/*** End of inlined file: juce_win32_Fonts.cpp ***/
-
-
/*** Start of inlined file: juce_win32_FileChooser.cpp ***/
// (This file gets included by juce_win32_NativeCode.cpp, rather than being
// compiled on its own).
@@ -253388,6 +254355,11 @@ CameraDevice* CameraDevice::openDevice (int index,
#pragma comment (lib, "Strmiids.lib")
#pragma comment (lib, "wmvcore.lib")
#endif
+
+#if JUCE_DIRECT2D
+ #pragma comment (lib, "Dwrite.lib")
+ #pragma comment (lib, "D2d1.lib")
+#endif
/*** End of inlined file: juce_win32_AutoLinkLibraries.h ***/
@@ -270792,9 +271764,9 @@ public:
void toFront (bool makeActiveWindow);
void toBehind (ComponentPeer* other);
void setIcon (const Image& newIcon);
- const StringArray getAvailableRenderingEngines() throw();
+ const StringArray getAvailableRenderingEngines();
int getCurrentRenderingEngine() throw();
- void setCurrentRenderingEngine (int index) throw();
+ void setCurrentRenderingEngine (int index);
/* When you use multiple DLLs which share similarly-named obj-c classes - like
for example having more than one juce plugin loaded into a host, then when a
@@ -272169,10 +273141,9 @@ void NSViewComponentPeer::drawRect (NSRect r)
}
}
-const StringArray NSViewComponentPeer::getAvailableRenderingEngines() throw()
+const StringArray NSViewComponentPeer::getAvailableRenderingEngines()
{
- StringArray s;
- s.add ("Software Renderer");
+ StringArray s (ComponentPeer::getAvailableRenderingEngines());
#if USE_COREGRAPHICS_RENDERING
s.add ("CoreGraphics Renderer");
@@ -272186,7 +273157,7 @@ int NSViewComponentPeer::getCurrentRenderingEngine() throw()
return usingCoreGraphics ? 1 : 0;
}
-void NSViewComponentPeer::setCurrentRenderingEngine (int index) throw()
+void NSViewComponentPeer::setCurrentRenderingEngine (int index)
{
#if USE_COREGRAPHICS_RENDERING
if (usingCoreGraphics != (index > 0))
diff --git a/juce_amalgamated.h b/juce_amalgamated.h
index 5fd3de12a1..e8eed827c5 100644
--- a/juce_amalgamated.h
+++ b/juce_amalgamated.h
@@ -64,7 +64,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
-#define JUCE_BUILDNUMBER 54
+#define JUCE_BUILDNUMBER 55
/** Current Juce version number.
@@ -309,6 +309,13 @@
#define JUCE_OPENGL 1
#endif
+/** JUCE_DIRECT2D: Enables the Windows 7 Direct2D renderer.
+ If you're building on a platform older than Vista, you won't be able to compile with this feature.
+*/
+#ifndef JUCE_DIRECT2D
+ #define JUCE_DIRECT2D 0
+#endif
+
/** JUCE_USE_FLAC: Enables the FLAC audio codec classes (available on all platforms).
If your app doesn't need to read FLAC files, you might want to disable this to
reduce the size of your codebase and build time.
@@ -29733,7 +29740,7 @@ public:
*/
float** getArrayOfChannels() const throw() { return channels; }
- /** Chages the buffer's size or number of channels.
+ /** Changes the buffer's size or number of channels.
This can expand or contract the buffer's length, and add or remove channels.
@@ -58136,9 +58143,9 @@ public:
static void bringModalComponentToFront();
- virtual const StringArray getAvailableRenderingEngines() throw();
+ virtual const StringArray getAvailableRenderingEngines();
virtual int getCurrentRenderingEngine() throw();
- virtual void setCurrentRenderingEngine (int index) throw();
+ virtual void setCurrentRenderingEngine (int index);
juce_UseDebuggingNewOperator
@@ -61392,6 +61399,11 @@ END_JUCE_NAMESPACE
#pragma comment (lib, "Strmiids.lib")
#pragma comment (lib, "wmvcore.lib")
#endif
+
+#if JUCE_DIRECT2D
+ #pragma comment (lib, "Dwrite.lib")
+ #pragma comment (lib, "D2d1.lib")
+#endif
/*** End of inlined file: juce_win32_AutoLinkLibraries.h ***/
diff --git a/src/audio/dsp/juce_AudioSampleBuffer.h b/src/audio/dsp/juce_AudioSampleBuffer.h
index 75c0050545..23f28e51ce 100644
--- a/src/audio/dsp/juce_AudioSampleBuffer.h
+++ b/src/audio/dsp/juce_AudioSampleBuffer.h
@@ -135,7 +135,7 @@ public:
float** getArrayOfChannels() const throw() { return channels; }
//==============================================================================
- /** Chages the buffer's size or number of channels.
+ /** Changes the buffer's size or number of channels.
This can expand or contract the buffer's length, and add or remove channels.
diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h
index 97a09052a5..c2e47d8a4a 100644
--- a/src/core/juce_StandardHeader.h
+++ b/src/core/juce_StandardHeader.h
@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
-#define JUCE_BUILDNUMBER 54
+#define JUCE_BUILDNUMBER 55
/** Current Juce version number.
diff --git a/src/gui/components/windows/juce_ComponentPeer.cpp b/src/gui/components/windows/juce_ComponentPeer.cpp
index 3c8d3ba700..c78fb96afa 100644
--- a/src/gui/components/windows/juce_ComponentPeer.cpp
+++ b/src/gui/components/windows/juce_ComponentPeer.cpp
@@ -521,7 +521,7 @@ void ComponentPeer::addMaskedRegion (int x, int y, int w, int h)
}
//==============================================================================
-const StringArray ComponentPeer::getAvailableRenderingEngines() throw()
+const StringArray ComponentPeer::getAvailableRenderingEngines()
{
StringArray s;
s.add ("Software Renderer");
@@ -533,7 +533,7 @@ int ComponentPeer::getCurrentRenderingEngine() throw()
return 0;
}
-void ComponentPeer::setCurrentRenderingEngine (int /*index*/) throw()
+void ComponentPeer::setCurrentRenderingEngine (int /*index*/)
{
}
diff --git a/src/gui/components/windows/juce_ComponentPeer.h b/src/gui/components/windows/juce_ComponentPeer.h
index 753544c9b3..5a9903897f 100644
--- a/src/gui/components/windows/juce_ComponentPeer.h
+++ b/src/gui/components/windows/juce_ComponentPeer.h
@@ -345,9 +345,9 @@ public:
static void bringModalComponentToFront();
//==============================================================================
- virtual const StringArray getAvailableRenderingEngines() throw();
+ virtual const StringArray getAvailableRenderingEngines();
virtual int getCurrentRenderingEngine() throw();
- virtual void setCurrentRenderingEngine (int index) throw();
+ virtual void setCurrentRenderingEngine (int index);
//==============================================================================
juce_UseDebuggingNewOperator
diff --git a/src/native/juce_win32_NativeCode.cpp b/src/native/juce_win32_NativeCode.cpp
index 9222f925e0..bbb4760559 100644
--- a/src/native/juce_win32_NativeCode.cpp
+++ b/src/native/juce_win32_NativeCode.cpp
@@ -97,8 +97,9 @@ BEGIN_JUCE_NAMESPACE
#if ! JUCE_ONLY_BUILD_CORE_LIBRARY
#include "windows/juce_win32_Messaging.cpp"
- #include "windows/juce_win32_Windowing.cpp"
#include "windows/juce_win32_Fonts.cpp"
+ #include "windows/juce_win32_Direct2DGraphicsContext.cpp"
+ #include "windows/juce_win32_Windowing.cpp"
#include "windows/juce_win32_FileChooser.cpp"
#include "windows/juce_win32_Misc.cpp"
#include "windows/juce_win32_ActiveXComponent.cpp"
diff --git a/src/native/mac/juce_mac_NSViewComponentPeer.mm b/src/native/mac/juce_mac_NSViewComponentPeer.mm
index d76bb14ccc..eda1759600 100644
--- a/src/native/mac/juce_mac_NSViewComponentPeer.mm
+++ b/src/native/mac/juce_mac_NSViewComponentPeer.mm
@@ -170,9 +170,9 @@ public:
void toFront (bool makeActiveWindow);
void toBehind (ComponentPeer* other);
void setIcon (const Image& newIcon);
- const StringArray getAvailableRenderingEngines() throw();
+ const StringArray getAvailableRenderingEngines();
int getCurrentRenderingEngine() throw();
- void setCurrentRenderingEngine (int index) throw();
+ void setCurrentRenderingEngine (int index);
/* When you use multiple DLLs which share similarly-named obj-c classes - like
for example having more than one juce plugin loaded into a host, then when a
@@ -1567,10 +1567,9 @@ void NSViewComponentPeer::drawRect (NSRect r)
}
}
-const StringArray NSViewComponentPeer::getAvailableRenderingEngines() throw()
+const StringArray NSViewComponentPeer::getAvailableRenderingEngines()
{
- StringArray s;
- s.add ("Software Renderer");
+ StringArray s (ComponentPeer::getAvailableRenderingEngines());
#if USE_COREGRAPHICS_RENDERING
s.add ("CoreGraphics Renderer");
@@ -1584,7 +1583,7 @@ int NSViewComponentPeer::getCurrentRenderingEngine() throw()
return usingCoreGraphics ? 1 : 0;
}
-void NSViewComponentPeer::setCurrentRenderingEngine (int index) throw()
+void NSViewComponentPeer::setCurrentRenderingEngine (int index)
{
#if USE_COREGRAPHICS_RENDERING
if (usingCoreGraphics != (index > 0))
diff --git a/src/native/windows/juce_win32_AutoLinkLibraries.h b/src/native/windows/juce_win32_AutoLinkLibraries.h
index a2e439861b..a1f9b1e96c 100644
--- a/src/native/windows/juce_win32_AutoLinkLibraries.h
+++ b/src/native/windows/juce_win32_AutoLinkLibraries.h
@@ -28,3 +28,8 @@
#pragma comment (lib, "Strmiids.lib")
#pragma comment (lib, "wmvcore.lib")
#endif
+
+#if JUCE_DIRECT2D
+ #pragma comment (lib, "Dwrite.lib")
+ #pragma comment (lib, "D2d1.lib")
+#endif
diff --git a/src/native/windows/juce_win32_Direct2DGraphicsContext.cpp b/src/native/windows/juce_win32_Direct2DGraphicsContext.cpp
new file mode 100644
index 0000000000..740ef17718
--- /dev/null
+++ b/src/native/windows/juce_win32_Direct2DGraphicsContext.cpp
@@ -0,0 +1,897 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library - "Jules' Utility Class Extensions"
+ Copyright 2004-10 by Raw Material Software Ltd.
+
+ ------------------------------------------------------------------------------
+
+ JUCE can be redistributed and/or modified under the terms of the GNU General
+ Public License (Version 2), as published by the Free Software Foundation.
+ A copy of the license is included in the JUCE distribution, or can be found
+ online at www.gnu.org/licenses.
+
+ JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ ------------------------------------------------------------------------------
+
+ To release a closed-source product which uses JUCE, commercial licenses are
+ available: visit www.rawmaterialsoftware.com/juce for more information.
+
+ ==============================================================================
+*/
+
+// (This file gets included by juce_win32_NativeCode.cpp, rather than being
+// compiled on its own).
+#if JUCE_INCLUDED_FILE && JUCE_DIRECT2D
+
+
+//==============================================================================
+class SharedD2DFactory : public DeletedAtShutdown
+{
+public:
+ SharedD2DFactory()
+ {
+ D2D1CreateFactory (D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2dFactory);
+ DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory), (IUnknown**) &directWriteFactory);
+
+ if (directWriteFactory != 0)
+ directWriteFactory->GetSystemFontCollection (&systemFonts);
+ }
+
+ ~SharedD2DFactory()
+ {
+ clearSingletonInstance();
+ }
+
+ juce_DeclareSingleton (SharedD2DFactory, false);
+
+ ComSmartPtr d2dFactory;
+ ComSmartPtr directWriteFactory;
+ ComSmartPtr systemFonts;
+};
+
+juce_ImplementSingleton (SharedD2DFactory)
+
+
+//==============================================================================
+class Direct2DLowLevelGraphicsContext : public LowLevelGraphicsContext
+{
+public:
+ Direct2DLowLevelGraphicsContext (HWND hwnd_)
+ : hwnd (hwnd_),
+ currentState (0)
+ {
+ RECT windowRect;
+ GetClientRect (hwnd, &windowRect);
+ D2D1_SIZE_U size = { windowRect.right - windowRect.left, windowRect.bottom - windowRect.top };
+ bounds.setSize (size.width, size.height);
+
+ D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties();
+ D2D1_HWND_RENDER_TARGET_PROPERTIES propsHwnd = D2D1::HwndRenderTargetProperties (hwnd, size);
+
+ HRESULT hr = SharedD2DFactory::getInstance()->d2dFactory->CreateHwndRenderTarget (props, propsHwnd, &renderingTarget);
+ // xxx check for error
+
+ hr = renderingTarget->CreateSolidColorBrush (D2D1::ColorF::ColorF (0.0f, 0.0f, 0.0f, 1.0f), &colourBrush);
+ }
+
+ ~Direct2DLowLevelGraphicsContext()
+ {
+ states.clear();
+ }
+
+ void resized()
+ {
+ RECT windowRect;
+ GetClientRect (hwnd, &windowRect);
+ D2D1_SIZE_U size = { windowRect.right - windowRect.left, windowRect.bottom - windowRect.top };
+
+ renderingTarget->Resize (size);
+ bounds.setSize (size.width, size.height);
+ }
+
+ void clear()
+ {
+ renderingTarget->Clear (D2D1::ColorF (D2D1::ColorF::White, 0.0f)); // xxx why white and not black?
+ }
+
+ void start()
+ {
+ renderingTarget->BeginDraw();
+ saveState();
+ }
+
+ void end()
+ {
+ states.clear();
+ currentState = 0;
+ renderingTarget->EndDraw();
+ renderingTarget->CheckWindowState();
+ }
+
+ bool isVectorDevice() const { return false; }
+
+ void setOrigin (int x, int y)
+ {
+ currentState->origin.addXY (x, y);
+ }
+
+ bool clipToRectangle (const Rectangle& r)
+ {
+ currentState->clipToRectangle (r);
+ return ! isClipEmpty();
+ }
+
+ bool clipToRectangleList (const RectangleList& clipRegion)
+ {
+ currentState->clipToRectList (rectListToPathGeometry (clipRegion));
+ return ! isClipEmpty();
+ }
+
+ void excludeClipRectangle (const Rectangle&)
+ {
+ //xxx
+ }
+
+ void clipToPath (const Path& path, const AffineTransform& transform)
+ {
+ currentState->clipToPath (pathToPathGeometry (path, transform, currentState->origin));
+ }
+
+ void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform)
+ {
+ currentState->clipToImage (sourceImage,transform);
+ }
+
+ bool clipRegionIntersects (const Rectangle& r)
+ {
+ const Rectangle r2 (r + currentState->origin);
+ return currentState->clipRect.intersects (r2);
+ }
+
+ const Rectangle getClipBounds() const
+ {
+ // xxx could this take into account complex clip regions?
+ return currentState->clipRect - currentState->origin;
+ }
+
+ bool isClipEmpty() const
+ {
+ return currentState->clipRect.isEmpty();
+ }
+
+ void saveState()
+ {
+ states.add (new SavedState (*this));
+ currentState = states.getLast();
+ }
+
+ void restoreState()
+ {
+ jassert (states.size() > 1) //you should never pop the last state!
+ states.removeLast (1);
+ currentState = states.getLast();
+ }
+
+ void setFill (const FillType& fillType)
+ {
+ currentState->setFill (fillType);
+ }
+
+ void setOpacity (float newOpacity)
+ {
+ currentState->setOpacity (newOpacity);
+ }
+
+ void setInterpolationQuality (Graphics::ResamplingQuality /*quality*/)
+ {
+ }
+
+ void fillRect (const Rectangle& r, bool replaceExistingContents)
+ {
+ currentState->createBrush();
+ renderingTarget->FillRectangle (rectangleToRectF (r + currentState->origin), currentState->currentBrush);
+ }
+
+ void fillPath (const Path& p, const AffineTransform& transform)
+ {
+ currentState->createBrush();
+ ComSmartPtr geometry (pathToPathGeometry (p, transform, currentState->origin));
+
+ if (renderingTarget != 0)
+ renderingTarget->FillGeometry (geometry, currentState->currentBrush);
+ }
+
+ void drawImage (const Image& image, const AffineTransform& transform, bool fillEntireClipAsTiles)
+ {
+ const int x = currentState->origin.getX();
+ const int y = currentState->origin.getY();
+
+ renderingTarget->SetTransform (transfromToMatrix (transform) * D2D1::Matrix3x2F::Translation (x, y));
+
+ D2D1_SIZE_U size;
+ size.width = image.getWidth();
+ size.height = image.getHeight();
+
+ D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties();
+
+ Image img (image.convertedToFormat (Image::ARGB));
+ Image::BitmapData bd (img, false);
+ bp.pixelFormat = renderingTarget->GetPixelFormat();
+ bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
+
+ {
+ ComSmartPtr tempBitmap;
+ renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, &tempBitmap);
+ if (tempBitmap != 0)
+ renderingTarget->DrawBitmap (tempBitmap);
+ }
+
+ renderingTarget->SetTransform (D2D1::IdentityMatrix());
+ }
+
+ void drawLine (const Line & line)
+ {
+ // xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour
+ const Line l (line.getStart() + currentState->origin.toFloat(),
+ line.getEnd() + currentState->origin.toFloat());
+
+ currentState->createBrush();
+
+ renderingTarget->DrawLine (D2D1::Point2F (l.getStartX(), l.getStartY()),
+ D2D1::Point2F (l.getEndX(), l.getEndY()),
+ currentState->currentBrush);
+ }
+
+ void drawVerticalLine (int x, float top, float bottom)
+ {
+ // xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour
+ currentState->createBrush();
+
+ x += currentState->origin.getX();
+ const int y = currentState->origin.getY();
+
+ renderingTarget->DrawLine (D2D1::Point2F (x, y + top),
+ D2D1::Point2F (x, y + bottom),
+ currentState->currentBrush);
+ }
+
+ void drawHorizontalLine (int y, float left, float right)
+ {
+ // xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour
+ currentState->createBrush();
+
+ y += currentState->origin.getY();
+ const int x = currentState->origin.getX();
+
+ renderingTarget->DrawLine (D2D1::Point2F (x + left, y),
+ D2D1::Point2F (x + right, y),
+ currentState->currentBrush);
+ }
+
+ void setFont (const Font& newFont)
+ {
+ currentState->setFont (newFont);
+ }
+
+ const Font getFont()
+ {
+ return currentState->font;
+ }
+
+ void drawGlyph (int glyphNumber, const AffineTransform& transform)
+ {
+ const float x = currentState->origin.getX();
+ const float y = currentState->origin.getY();
+
+ currentState->createBrush();
+ currentState->createFont();
+
+ float kerning = currentState->font.getExtraKerningFactor(); // xxx why does removing this line mess up the kerning??
+ float hScale = currentState->font.getHorizontalScale();
+
+ renderingTarget->SetTransform (D2D1::Matrix3x2F::Scale (hScale, 1) * transfromToMatrix (transform) * D2D1::Matrix3x2F::Translation (x, y));
+
+ float dpiX = 0, dpiY = 0;
+ SharedD2DFactory::getInstance()->d2dFactory->GetDesktopDpi (&dpiX, &dpiY);
+
+ UINT32 glyphNum = glyphNumber;
+ UINT16 glyphNum1 = 0; // xxx needs a better name - what is this for?
+ currentState->currentFontFace->GetGlyphIndices (&glyphNum, 1, &glyphNum1);
+
+ DWRITE_GLYPH_OFFSET offset;
+ offset.advanceOffset = 0;
+ offset.ascenderOffset = 0;
+ float glyphAdvances = 0;
+
+ DWRITE_GLYPH_RUN glyph;
+ glyph.fontFace = currentState->currentFontFace;
+ glyph.glyphCount = 1;
+ glyph.glyphIndices = &glyphNum1;
+ glyph.isSideways = FALSE;
+ glyph.glyphAdvances = &glyphAdvances;
+ glyph.glyphOffsets = &offset;
+ glyph.fontEmSize = (float) currentState->font.getHeight() * dpiX / 96.0f * (1 + currentState->fontScaling) / 2;
+
+ renderingTarget->DrawGlyphRun (D2D1::Point2F (0, 0), &glyph, currentState->currentBrush);
+ renderingTarget->SetTransform (D2D1::IdentityMatrix());
+ }
+
+ //==============================================================================
+ class SavedState
+ {
+ public:
+ SavedState (Direct2DLowLevelGraphicsContext& owner_)
+ : owner (owner_), currentBrush (0),
+ fontScaling (1.0f), currentFontFace (0),
+ clipsRect (false), shouldClipRect (false),
+ clipsRectList (false), shouldClipRectList (false),
+ clipsComplex (false), shouldClipComplex (false),
+ clipsBitmap (false), shouldClipBitmap (false)
+ {
+ if (owner.currentState != 0)
+ {
+ // xxx seems like a very slow way to create one of these, and this is a performance
+ // bottleneck.. Can the same internal objects be shared by multiple state objects, maybe using copy-on-write?
+ setFill (owner.currentState->fillType);
+ currentBrush = owner.currentState->currentBrush;
+ origin = owner.currentState->origin;
+ clipRect = owner.currentState->clipRect;
+
+ font = owner.currentState->font;
+ currentFontFace = owner.currentState->currentFontFace;
+ }
+ else
+ {
+ const D2D1_SIZE_U size (owner.renderingTarget->GetPixelSize());
+ clipRect.setSize (size.width, size.height);
+ setFill (FillType (Colours::black));
+ }
+ }
+
+ ~SavedState()
+ {
+ clearClip();
+ clearFont();
+ clearFill();
+ clearPathClip();
+ clearImageClip();
+ complexClipLayer = 0;
+ bitmapMaskLayer = 0;
+ }
+
+ void clearClip()
+ {
+ popClips();
+ shouldClipRect = false;
+ }
+
+ void clipToRectangle (const Rectangle& r)
+ {
+ clearClip();
+ clipRect = r + origin;
+ shouldClipRect = true;
+ pushClips();
+ }
+
+ void clearPathClip()
+ {
+ popClips();
+
+ if (shouldClipComplex)
+ {
+ complexClipGeometry = 0;
+ shouldClipComplex = false;
+ }
+ }
+
+ void clipToPath (ID2D1Geometry* geometry)
+ {
+ clearPathClip();
+
+ if (complexClipLayer == 0)
+ owner.renderingTarget->CreateLayer (&complexClipLayer);
+
+ complexClipGeometry = geometry;
+ shouldClipComplex = true;
+ pushClips();
+ }
+
+ void clearRectListClip()
+ {
+ popClips();
+
+ if (shouldClipRectList)
+ {
+ rectListGeometry = 0;
+ shouldClipRectList = false;
+ }
+ }
+
+ void clipToRectList (ID2D1Geometry* geometry)
+ {
+ clearRectListClip();
+
+ if (rectListLayer == 0)
+ owner.renderingTarget->CreateLayer (&rectListLayer);
+
+ rectListGeometry = geometry;
+ shouldClipRectList = true;
+ pushClips();
+ }
+
+ void clearImageClip()
+ {
+ popClips();
+
+ if (shouldClipBitmap)
+ {
+ maskBitmap = 0;
+ bitmapMaskBrush = 0;
+ shouldClipBitmap = false;
+ }
+ }
+
+ void clipToImage (const Image& image, const AffineTransform& transform)
+ {
+ clearImageClip();
+
+ if (bitmapMaskLayer == 0)
+ owner.renderingTarget->CreateLayer (&bitmapMaskLayer);
+
+ D2D1_BRUSH_PROPERTIES brushProps;
+ brushProps.opacity = 1;
+ brushProps.transform = transfromToMatrix (transform);
+
+ D2D1_BITMAP_BRUSH_PROPERTIES bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP);
+
+ D2D1_SIZE_U size;
+ size.width = image.getWidth();
+ size.height = image.getHeight();
+
+ D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties();
+
+ maskImage = image.convertedToFormat (Image::ARGB);
+ Image::BitmapData bd (this->image, false); // xxx should be maskImage?
+ bp.pixelFormat = owner.renderingTarget->GetPixelFormat();
+ bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
+
+ HRESULT hr = owner.renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, &maskBitmap);
+ hr = owner.renderingTarget->CreateBitmapBrush (maskBitmap, bmProps, brushProps, &bitmapMaskBrush);
+
+ imageMaskLayerParams = D2D1::LayerParameters();
+ imageMaskLayerParams.opacityBrush = bitmapMaskBrush;
+
+ shouldClipBitmap = true;
+ pushClips();
+ }
+
+ void popClips()
+ {
+ if (clipsBitmap)
+ {
+ owner.renderingTarget->PopLayer();
+ clipsBitmap = false;
+ }
+
+ if (clipsComplex)
+ {
+ owner.renderingTarget->PopLayer();
+ clipsComplex = false;
+ }
+
+ if (clipsRectList)
+ {
+ owner.renderingTarget->PopLayer();
+ clipsRectList = false;
+ }
+
+ if (clipsRect)
+ {
+ owner.renderingTarget->PopAxisAlignedClip();
+ clipsRect = false;
+ }
+ }
+
+ void pushClips()
+ {
+ if (shouldClipRect && ! clipsRect)
+ {
+ owner.renderingTarget->PushAxisAlignedClip (rectangleToRectF (clipRect), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
+ clipsRect = true;
+ }
+
+ if (shouldClipRectList && ! clipsRectList)
+ {
+ D2D1_LAYER_PARAMETERS layerParams = D2D1::LayerParameters();
+ rectListGeometry->GetBounds (D2D1::IdentityMatrix(), &layerParams.contentBounds);
+ layerParams.geometricMask = rectListGeometry;
+ owner.renderingTarget->PushLayer (layerParams, rectListLayer);
+ clipsRectList = true;
+ }
+
+ if (shouldClipComplex && ! clipsComplex)
+ {
+ D2D1_LAYER_PARAMETERS layerParams = D2D1::LayerParameters();
+ complexClipGeometry->GetBounds (D2D1::IdentityMatrix(), &layerParams.contentBounds);
+ layerParams.geometricMask = complexClipGeometry;
+ owner.renderingTarget->PushLayer (layerParams, complexClipLayer);
+ clipsComplex = true;
+ }
+
+ if (shouldClipBitmap && ! clipsBitmap)
+ {
+ owner.renderingTarget->PushLayer (imageMaskLayerParams, bitmapMaskLayer);
+ clipsBitmap = true;
+ }
+ }
+
+ void setFill (const FillType& newFillType)
+ {
+ if (fillType != newFillType)
+ {
+ fillType = newFillType;
+ clearFill();
+ }
+ }
+
+ void clearFont()
+ {
+ currentFontFace = localFontFace = 0;
+ }
+
+ void setFont (const Font& newFont)
+ {
+ if (font != newFont)
+ {
+ font = newFont;
+ clearFont();
+ }
+ }
+
+ void createFont()
+ {
+ // xxx The font shouldn't be managed by the graphics context.
+ // The correct way to handle font lifetimes is to use a subclass of Typeface - see
+ // MacTypeface and WindowsTypeface classes. D2D support could probably just be added to the
+ // WindowsTypeface class.
+
+ if (currentFontFace == 0)
+ {
+ WindowsTypeface* systemType = dynamic_cast (font.getTypeface());
+ fontScaling = systemType->getAscent();
+
+ BOOL fontFound;
+ uint32 fontIndex;
+
+ IDWriteFontCollection* fonts = SharedD2DFactory::getInstance()->systemFonts;
+
+ fonts->FindFamilyName (systemType->getName(), &fontIndex, &fontFound);
+ if (! fontFound)
+ fontIndex = 0;
+
+ ComSmartPtr fontFam;
+ fonts->GetFontFamily (fontIndex, &fontFam);
+
+ ComSmartPtr font;
+ DWRITE_FONT_WEIGHT weight = this->font.isBold() ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL;
+ DWRITE_FONT_STYLE style = this->font.isItalic() ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
+ fontFam->GetFirstMatchingFont (weight, DWRITE_FONT_STRETCH_NORMAL, style, &font);
+
+ font->CreateFontFace (&localFontFace);
+ currentFontFace = localFontFace;
+ }
+ }
+
+ void setOpacity (float newOpacity)
+ {
+ fillType.setOpacity (newOpacity);
+
+ if (currentBrush != 0)
+ currentBrush->SetOpacity (newOpacity);
+ }
+
+ void clearFill()
+ {
+ gradientStops = 0;
+ linearGradient = 0;
+ radialGradient = 0;
+ bitmap = 0;
+ bitmapBrush = 0;
+ currentBrush = 0;
+ }
+
+ void createBrush()
+ {
+ if (currentBrush == 0)
+ {
+ const int x = origin.getX();
+ const int y = origin.getY();
+
+ if (fillType.isColour())
+ {
+ D2D1_COLOR_F colour = colourToD2D (fillType.colour);
+ owner.colourBrush->SetColor (colour);
+ currentBrush = owner.colourBrush;
+ }
+ else if (fillType.isTiledImage())
+ {
+ D2D1_BRUSH_PROPERTIES brushProps;
+ brushProps.opacity = fillType.getOpacity();
+ brushProps.transform = transfromToMatrix (fillType.transform);
+
+ D2D1_BITMAP_BRUSH_PROPERTIES bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP,D2D1_EXTEND_MODE_WRAP);
+
+ image = fillType.image;
+
+ D2D1_SIZE_U size;
+ size.width = image.getWidth();
+ size.height = image.getHeight();
+
+ D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties();
+
+ this->image = image.convertedToFormat (Image::ARGB);
+ Image::BitmapData bd (this->image, false);
+ bp.pixelFormat = owner.renderingTarget->GetPixelFormat();
+ bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
+
+ HRESULT hr = owner.renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, &bitmap);
+ hr = owner.renderingTarget->CreateBitmapBrush (bitmap, bmProps, brushProps, &bitmapBrush);
+
+ currentBrush = bitmapBrush;
+ }
+ else if (fillType.isGradient())
+ {
+ gradientStops = 0;
+
+ D2D1_BRUSH_PROPERTIES brushProps;
+ brushProps.opacity = fillType.getOpacity();
+ brushProps.transform = transfromToMatrix (fillType.transform);
+
+ const int numColors = fillType.gradient->getNumColours();
+
+ HeapBlock stops (numColors);
+
+ for (int i = fillType.gradient->getNumColours(); --i >= 0;)
+ {
+ stops[i].color = colourToD2D (fillType.gradient->getColour(i));
+ stops[i].position = fillType.gradient->getColourPosition(i);
+ }
+
+ owner.renderingTarget->CreateGradientStopCollection (stops.getData(), numColors, &gradientStops);
+
+ if (fillType.gradient->isRadial)
+ {
+ radialGradient = 0;
+
+ const Point& p1 = fillType.gradient->point1;
+ const Point& p2 = fillType.gradient->point2;
+ float r = p1.getDistanceFrom (p2);
+
+ D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES props =
+ D2D1::RadialGradientBrushProperties (D2D1::Point2F (p1.getX() + x, p1.getY() + y),
+ D2D1::Point2F (0, 0),
+ r, r);
+
+ owner.renderingTarget->CreateRadialGradientBrush (props, brushProps, gradientStops, &radialGradient);
+ currentBrush = radialGradient;
+ }
+ else
+ {
+ linearGradient = 0;
+
+ const Point& p1 = fillType.gradient->point1;
+ const Point& p2 = fillType.gradient->point2;
+
+ D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES props =
+ D2D1::LinearGradientBrushProperties (D2D1::Point2F (p1.getX() + x, p1.getY() + y),
+ D2D1::Point2F (p2.getX() + x, p2.getY() + y));
+
+ owner.renderingTarget->CreateLinearGradientBrush (props, brushProps, gradientStops, &linearGradient);
+
+ currentBrush = linearGradient;
+ }
+ }
+ }
+ }
+
+ //==============================================================================
+ juce_UseDebuggingNewOperator
+
+ //==============================================================================
+ //xxx most of these members should probably be private...
+
+ Direct2DLowLevelGraphicsContext& owner;
+
+ Point origin;
+
+ Font font;
+ float fontScaling;
+ IDWriteFontFace* currentFontFace;
+ ComSmartPtr localFontFace;
+
+ FillType fillType;
+
+ Image image;
+ ComSmartPtr bitmap; // xxx needs a better name - what is this for??
+
+ Rectangle clipRect;
+ bool clipsRect, shouldClipRect;
+
+ ComSmartPtr complexClipGeometry;
+ D2D1_LAYER_PARAMETERS complexClipLayerParams;
+ ComSmartPtr complexClipLayer;
+ bool clipsComplex, shouldClipComplex;
+
+ ComSmartPtr rectListGeometry;
+ D2D1_LAYER_PARAMETERS rectListLayerParams;
+ ComSmartPtr rectListLayer;
+ bool clipsRectList, shouldClipRectList;
+
+ Image maskImage;
+ D2D1_LAYER_PARAMETERS imageMaskLayerParams;
+ ComSmartPtr bitmapMaskLayer;
+ ComSmartPtr maskBitmap;
+ ComSmartPtr bitmapMaskBrush;
+ bool clipsBitmap, shouldClipBitmap;
+
+ ID2D1Brush* currentBrush;
+ ComSmartPtr bitmapBrush;
+ ComSmartPtr linearGradient;
+ ComSmartPtr radialGradient;
+ ComSmartPtr gradientStops;
+
+ private:
+ SavedState (const SavedState&);
+ SavedState& operator= (const SavedState& other);
+ };
+
+ //==============================================================================
+ juce_UseDebuggingNewOperator
+
+private:
+ HWND hwnd;
+ ComSmartPtr renderingTarget;
+ ComSmartPtr colourBrush;
+ Rectangle bounds;
+
+ SavedState* currentState;
+ OwnedArray states;
+
+ //==============================================================================
+ static D2D1_RECT_F rectangleToRectF (const Rectangle& r)
+ {
+ return D2D1::RectF ((float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom());
+ }
+
+ static const D2D1_COLOR_F colourToD2D (const Colour& c)
+ {
+ return D2D1::ColorF::ColorF (c.getFloatRed(), c.getFloatGreen(), c.getFloatBlue(), c.getFloatAlpha());
+ }
+
+ static const D2D1_POINT_2F pointTransformed (int x, int y, const AffineTransform& transform = AffineTransform::identity)
+ {
+ transform.transformPoint (x, y);
+ return D2D1::Point2F (x, y);
+ }
+
+ static void rectToGeometrySink (const Rectangle& rect, ID2D1GeometrySink* sink)
+ {
+ sink->BeginFigure (pointTransformed (rect.getX(), rect.getY()), D2D1_FIGURE_BEGIN_FILLED);
+ sink->AddLine (pointTransformed (rect.getRight(), rect.getY()));
+ sink->AddLine (pointTransformed (rect.getRight(), rect.getBottom()));
+ sink->AddLine (pointTransformed (rect.getX(), rect.getBottom()));
+ sink->EndFigure (D2D1_FIGURE_END_CLOSED);
+ }
+
+ static ID2D1PathGeometry* rectListToPathGeometry (const RectangleList& clipRegion)
+ {
+ ID2D1PathGeometry* p = 0;
+ SharedD2DFactory::getInstance()->d2dFactory->CreatePathGeometry (&p);
+
+ ComSmartPtr sink;
+ HRESULT hr = p->Open (&sink); // xxx handle error
+ sink->SetFillMode (D2D1_FILL_MODE_WINDING);
+
+ for (int i = clipRegion.getNumRectangles(); --i >= 0;)
+ rectToGeometrySink (clipRegion.getRectangle(i), sink);
+
+ hr = sink->Close();
+ return p;
+ }
+
+ static void pathToGeometrySink (const Path& path, ID2D1GeometrySink* sink, const AffineTransform& transform, int x, int y)
+ {
+ Path::Iterator it (path);
+
+ while (it.next())
+ {
+ switch (it.elementType)
+ {
+ case Path::Iterator::cubicTo:
+ {
+ D2D1_BEZIER_SEGMENT seg;
+
+ transform.transformPoint (it.x1, it.y1);
+ seg.point1 = D2D1::Point2F (it.x1 + x, it.y1 + y);
+
+ transform.transformPoint (it.x2, it.y2);
+ seg.point2 = D2D1::Point2F (it.x2 + x, it.y2 + y);
+
+ transform.transformPoint(it.x3, it.y3);
+ seg.point3 = D2D1::Point2F (it.x3 + x, it.y3 + y);
+
+ sink->AddBezier (seg);
+ break;
+ }
+
+ case Path::Iterator::lineTo:
+ {
+ transform.transformPoint (it.x1, it.y1);
+ sink->AddLine (D2D1::Point2F (it.x1 + x, it.y1 + y));
+ break;
+ }
+
+ case Path::Iterator::quadraticTo:
+ {
+ D2D1_QUADRATIC_BEZIER_SEGMENT seg;
+
+ transform.transformPoint (it.x1, it.y1);
+ seg.point1 = D2D1::Point2F (it.x1 + x, it.y1 + y);
+
+ transform.transformPoint (it.x2, it.y2);
+ seg.point2 = D2D1::Point2F (it.x2 + x, it.y2 + y);
+
+ sink->AddQuadraticBezier (seg);
+ break;
+ }
+
+ case Path::Iterator::closePath:
+ {
+ sink->EndFigure (D2D1_FIGURE_END_CLOSED);
+ break;
+ }
+
+ case Path::Iterator::startNewSubPath:
+ {
+ transform.transformPoint (it.x1, it.y1);
+ sink->BeginFigure (D2D1::Point2F (it.x1 + x, it.y1 + y), D2D1_FIGURE_BEGIN_FILLED);
+ break;
+ }
+ }
+ }
+ }
+
+ static ID2D1PathGeometry* pathToPathGeometry (const Path& path, const AffineTransform& transform, const Point& point)
+ {
+ ID2D1PathGeometry* p = 0;
+ SharedD2DFactory::getInstance()->d2dFactory->CreatePathGeometry (&p);
+
+ ComSmartPtr sink;
+ HRESULT hr = p->Open (&sink);
+ sink->SetFillMode (D2D1_FILL_MODE_WINDING); // xxx need to check Path::isUsingNonZeroWinding()
+
+ pathToGeometrySink (path, sink, transform, point.getX(), point.getY());
+
+ hr = sink->Close();
+ return p;
+ }
+
+ static const D2D1::Matrix3x2F transfromToMatrix (const AffineTransform& transform)
+ {
+ D2D1::Matrix3x2F matrix;
+ matrix._11 = transform.mat00;
+ matrix._12 = transform.mat10;
+ matrix._21 = transform.mat01;
+ matrix._22 = transform.mat11;
+ matrix._31 = transform.mat02;
+ matrix._32 = transform.mat12;
+ return matrix;
+ }
+};
+
+
+#endif
diff --git a/src/native/windows/juce_win32_NativeIncludes.h b/src/native/windows/juce_win32_NativeIncludes.h
index 5e7ad5bb02..6fbb7ac041 100644
--- a/src/native/windows/juce_win32_NativeIncludes.h
+++ b/src/native/windows/juce_win32_NativeIncludes.h
@@ -183,6 +183,11 @@
#pragma warning (pop)
#endif
+#if JUCE_DIRECT2D
+ #include
+ #include
+#endif
+
//==============================================================================
/** A simple COM smart pointer.
Avoids having to include ATL just to get one of these.
@@ -237,7 +242,10 @@ public:
HRESULT __stdcall QueryInterface (REFIID refId, void __RPC_FAR* __RPC_FAR* result)
{
+ #ifndef __MINGW32__
if (refId == __uuidof (ComClass)) { AddRef(); *result = dynamic_cast (this); return S_OK; }
+ #endif
+
if (refId == IID_IUnknown) { AddRef(); *result = dynamic_cast (this); return S_OK; }
*result = 0;
diff --git a/src/native/windows/juce_win32_Windowing.cpp b/src/native/windows/juce_win32_Windowing.cpp
index 34f8159745..cacc062f32 100644
--- a/src/native/windows/juce_win32_Windowing.cpp
+++ b/src/native/windows/juce_win32_Windowing.cpp
@@ -382,11 +382,22 @@ static void* callFunctionIfNotLocked (MessageCallbackFunction* callback, void* u
class Win32ComponentPeer : public ComponentPeer
{
public:
+ enum RenderingEngineType
+ {
+ softwareRenderingEngine = 0,
+ direct2DRenderingEngine
+ };
+
//==============================================================================
Win32ComponentPeer (Component* const component,
const int windowStyleFlags)
: ComponentPeer (component, windowStyleFlags),
dontRepaint (false),
+ #if JUCE_DIRECT2D
+ currentRenderingEngine (direct2DRenderingEngine),
+ #else
+ currentRenderingEngine (softwareRenderingEngine),
+ #endif
fullScreen (false),
isDragging (false),
isMouseOver (false),
@@ -427,6 +438,10 @@ public:
dropTarget->Release();
dropTarget = 0;
}
+
+ #if JUCE_DIRECT2D
+ direct2DContext = 0;
+ #endif
}
//==============================================================================
@@ -478,6 +493,11 @@ public:
info.rcWindow.bottom - info.rcClient.bottom,
info.rcWindow.right - info.rcClient.right);
}
+
+ #if JUCE_DIRECT2D
+ if (direct2DContext != 0)
+ direct2DContext->resized();
+ #endif
}
void setSize (int w, int h)
@@ -842,6 +862,10 @@ public:
private:
HWND hwnd;
ScopedPointer shadower;
+ RenderingEngineType currentRenderingEngine;
+ #if JUCE_DIRECT2D
+ ScopedPointer direct2DContext;
+ #endif
bool fullScreen, isDragging, isMouseOver, hasCreatedCaret;
BorderSize windowBorder;
HICON currentWindowIcon;
@@ -988,6 +1012,10 @@ private:
hwnd = CreateWindowEx (exstyle, WindowClassHolder::getInstance()->windowClassName, L"", type, 0, 0, 0, 0, 0, 0, 0, 0);
+ #if JUCE_DIRECT2D
+ updateDirect2DContext();
+ #endif
+
if (hwnd != 0)
{
SetWindowLongPtr (hwnd, 0, 0);
@@ -1084,129 +1112,146 @@ private:
//==============================================================================
void handlePaintMessage()
{
- HRGN rgn = CreateRectRgn (0, 0, 0, 0);
- const int regionType = GetUpdateRgn (hwnd, rgn, false);
-
- PAINTSTRUCT paintStruct;
- HDC dc = BeginPaint (hwnd, &paintStruct); // Note this can immediately generate a WM_NCPAINT
- // message and become re-entrant, but that's OK
-
- // if something in a paint handler calls, e.g. a message box, this can become reentrant and
- // corrupt the image it's using to paint into, so do a check here.
- static bool reentrant = false;
- if (reentrant)
+#if JUCE_DIRECT2D
+ if (direct2DContext != 0)
{
- DeleteObject (rgn);
- EndPaint (hwnd, &paintStruct);
- return;
- }
+ RECT r;
- reentrant = true;
+ if (GetUpdateRect (hwnd, &r, false))
+ {
+ direct2DContext->start();
+ direct2DContext->clipToRectangle (Rectangle (r.left, r.top, r.right - r.left, r.bottom - r.top));
+ handlePaint (*direct2DContext);
+ direct2DContext->end();
+ }
+ }
+ else
+#endif
+ {
+ HRGN rgn = CreateRectRgn (0, 0, 0, 0);
+ const int regionType = GetUpdateRgn (hwnd, rgn, false);
- // this is the rectangle to update..
- int x = paintStruct.rcPaint.left;
- int y = paintStruct.rcPaint.top;
- int w = paintStruct.rcPaint.right - x;
- int h = paintStruct.rcPaint.bottom - y;
+ PAINTSTRUCT paintStruct;
+ HDC dc = BeginPaint (hwnd, &paintStruct); // Note this can immediately generate a WM_NCPAINT
+ // message and become re-entrant, but that's OK
- const bool transparent = isTransparent();
+ // if something in a paint handler calls, e.g. a message box, this can become reentrant and
+ // corrupt the image it's using to paint into, so do a check here.
+ static bool reentrant = false;
+ if (reentrant)
+ {
+ DeleteObject (rgn);
+ EndPaint (hwnd, &paintStruct);
+ return;
+ }
- if (transparent)
- {
- // it's not possible to have a transparent window with a title bar at the moment!
- jassert (! hasTitleBar());
+ reentrant = true;
- RECT r;
- GetWindowRect (hwnd, &r);
- x = y = 0;
- w = r.right - r.left;
- h = r.bottom - r.top;
- }
+ // this is the rectangle to update..
+ int x = paintStruct.rcPaint.left;
+ int y = paintStruct.rcPaint.top;
+ int w = paintStruct.rcPaint.right - x;
+ int h = paintStruct.rcPaint.bottom - y;
- if (w > 0 && h > 0)
- {
- clearMaskedRegion();
+ const bool transparent = isTransparent();
- Image offscreenImage (offscreenImageGenerator.getImage (transparent, w, h));
+ if (transparent)
+ {
+ // it's not possible to have a transparent window with a title bar at the moment!
+ jassert (! hasTitleBar());
+
+ RECT r;
+ GetWindowRect (hwnd, &r);
+ x = y = 0;
+ w = r.right - r.left;
+ h = r.bottom - r.top;
+ }
- RectangleList contextClip;
- const Rectangle clipBounds (0, 0, w, h);
+ if (w > 0 && h > 0)
+ {
+ clearMaskedRegion();
- bool needToPaintAll = true;
+ Image offscreenImage (offscreenImageGenerator.getImage (transparent, w, h));
- if (regionType == COMPLEXREGION && ! transparent)
- {
- HRGN clipRgn = CreateRectRgnIndirect (&paintStruct.rcPaint);
- CombineRgn (rgn, rgn, clipRgn, RGN_AND);
- DeleteObject (clipRgn);
+ RectangleList contextClip;
+ const Rectangle clipBounds (0, 0, w, h);
- char rgnData [8192];
- const DWORD res = GetRegionData (rgn, sizeof (rgnData), (RGNDATA*) rgnData);
+ bool needToPaintAll = true;
- if (res > 0 && res <= sizeof (rgnData))
+ if (regionType == COMPLEXREGION && ! transparent)
{
- const RGNDATAHEADER* const hdr = &(((const RGNDATA*) rgnData)->rdh);
+ HRGN clipRgn = CreateRectRgnIndirect (&paintStruct.rcPaint);
+ CombineRgn (rgn, rgn, clipRgn, RGN_AND);
+ DeleteObject (clipRgn);
- if (hdr->iType == RDH_RECTANGLES
- && hdr->rcBound.right - hdr->rcBound.left >= w
- && hdr->rcBound.bottom - hdr->rcBound.top >= h)
- {
- needToPaintAll = false;
+ char rgnData [8192];
+ const DWORD res = GetRegionData (rgn, sizeof (rgnData), (RGNDATA*) rgnData);
- const RECT* rects = (const RECT*) (rgnData + sizeof (RGNDATAHEADER));
- int num = ((RGNDATA*) rgnData)->rdh.nCount;
+ if (res > 0 && res <= sizeof (rgnData))
+ {
+ const RGNDATAHEADER* const hdr = &(((const RGNDATA*) rgnData)->rdh);
- while (--num >= 0)
+ if (hdr->iType == RDH_RECTANGLES
+ && hdr->rcBound.right - hdr->rcBound.left >= w
+ && hdr->rcBound.bottom - hdr->rcBound.top >= h)
{
- if (rects->right <= x + w && rects->bottom <= y + h)
- {
- // (need to move this one pixel to the left because of a win32 bug)
- const int cx = jmax (x, (int) rects->left - 1);
- contextClip.addWithoutMerging (Rectangle (cx - x, rects->top - y, rects->right - cx, rects->bottom - rects->top)
- .getIntersection (clipBounds));
- }
- else
+ needToPaintAll = false;
+
+ const RECT* rects = (const RECT*) (rgnData + sizeof (RGNDATAHEADER));
+ int num = ((RGNDATA*) rgnData)->rdh.nCount;
+
+ while (--num >= 0)
{
- needToPaintAll = true;
- break;
+ if (rects->right <= x + w && rects->bottom <= y + h)
+ {
+ // (need to move this one pixel to the left because of a win32 bug)
+ const int cx = jmax (x, (int) rects->left - 1);
+ contextClip.addWithoutMerging (Rectangle (cx - x, rects->top - y, rects->right - cx, rects->bottom - rects->top)
+ .getIntersection (clipBounds));
+ }
+ else
+ {
+ needToPaintAll = true;
+ break;
+ }
+
+ ++rects;
}
-
- ++rects;
}
}
}
- }
- if (needToPaintAll)
- {
- contextClip.clear();
- contextClip.addWithoutMerging (Rectangle (w, h));
- }
+ if (needToPaintAll)
+ {
+ contextClip.clear();
+ contextClip.addWithoutMerging (Rectangle (w, h));
+ }
- if (transparent)
- {
- RectangleList::Iterator i (contextClip);
+ if (transparent)
+ {
+ RectangleList::Iterator i (contextClip);
- while (i.next())
- offscreenImage.clear (*i.getRectangle());
- }
+ while (i.next())
+ offscreenImage.clear (*i.getRectangle());
+ }
- // if the component's not opaque, this won't draw properly unless the platform can support this
- jassert (Desktop::canUseSemiTransparentWindows() || component->isOpaque());
+ // if the component's not opaque, this won't draw properly unless the platform can support this
+ jassert (Desktop::canUseSemiTransparentWindows() || component->isOpaque());
- updateCurrentModifiers();
+ updateCurrentModifiers();
- LowLevelGraphicsSoftwareRenderer context (offscreenImage, -x, -y, contextClip);
- handlePaint (context);
+ LowLevelGraphicsSoftwareRenderer context (offscreenImage, -x, -y, contextClip);
+ handlePaint (context);
- if (! dontRepaint)
- static_cast (offscreenImage.getSharedImage())
- ->blitToWindow (hwnd, dc, transparent, x, y, maskedRegion);
- }
+ if (! dontRepaint)
+ static_cast (offscreenImage.getSharedImage())
+ ->blitToWindow (hwnd, dc, transparent, x, y, maskedRegion);
+ }
- DeleteObject (rgn);
- EndPaint (hwnd, &paintStruct);
- reentrant = false;
+ DeleteObject (rgn);
+ EndPaint (hwnd, &paintStruct);
+ reentrant = false;
+ }
#ifndef JUCE_GCC //xxx should add this fn for gcc..
_fpreset(); // because some graphics cards can unmask FP exceptions
@@ -1221,6 +1266,48 @@ private:
handleMouseEvent (0, position, currentModifiers, getMouseEventTime());
}
+ const StringArray getAvailableRenderingEngines()
+ {
+ StringArray s (ComponentPeer::getAvailableRenderingEngines());
+
+#if JUCE_DIRECT2D
+ // xxx is this correct? Seems to enable it on Vista too??
+ OSVERSIONINFO info;
+ zerostruct (info);
+ info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+ GetVersionEx (&info);
+ if (info.dwMajorVersion >= 6)
+ s.add ("Direct2D");
+#endif
+ return s;
+ }
+
+ int getCurrentRenderingEngine() throw()
+ {
+ return currentRenderingEngine;
+ }
+
+#if JUCE_DIRECT2D
+ void updateDirect2DContext()
+ {
+ if (currentRenderingEngine != direct2DRenderingEngine)
+ direct2DContext = 0;
+ else if (direct2DContext == 0)
+ direct2DContext = new Direct2DLowLevelGraphicsContext (hwnd);
+ }
+#endif
+
+ void setCurrentRenderingEngine (int index)
+ {
+ (void) index;
+
+#if JUCE_DIRECT2D
+ currentRenderingEngine = index == 1 ? direct2DRenderingEngine : softwareRenderingEngine;
+ updateDirect2DContext();
+ repaint (component->getLocalBounds());
+#endif
+ }
+
void doMouseMove (const Point& position)
{
if (! isMouseOver)