fix macOS build (following Projucer changes made in Windows, which removed /Applications/JUCE/modules from its headers). move JUCE headers under source control, so that Windows and macOS can both build against same version of JUCE. remove AUv3 target (I think it's an iOS thing, so it will never work with this macOS fluidsynth dylib).

This commit is contained in:
Alex Birch
2018-06-17 13:34:53 +01:00
parent a2be47c887
commit dff4d13a1d
1563 changed files with 601601 additions and 3466 deletions

View File

@ -0,0 +1,608 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "(Landroid/content/Context;)V") \
METHOD (getSettings, "getSettings", "()Landroid/webkit/WebSettings;") \
METHOD (goBack, "goBack", "()V") \
METHOD (goForward, "goForward", "()V") \
METHOD (loadDataWithBaseURL, "loadDataWithBaseURL", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V") \
METHOD (loadUrl, "loadUrl", "(Ljava/lang/String;Ljava/util/Map;)V") \
METHOD (postUrl, "postUrl", "(Ljava/lang/String;[B)V") \
METHOD (reload, "reload", "()V") \
METHOD (setWebChromeClient, "setWebChromeClient", "(Landroid/webkit/WebChromeClient;)V") \
METHOD (setWebViewClient, "setWebViewClient", "(Landroid/webkit/WebViewClient;)V") \
METHOD (stopLoading, "stopLoading", "()V")
DECLARE_JNI_CLASS (AndroidWebView, "android/webkit/WebView")
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "()V")
DECLARE_JNI_CLASS (AndroidWebChromeClient, "android/webkit/WebChromeClient");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "()V")
DECLARE_JNI_CLASS (AndroidWebViewClient, "android/webkit/WebViewClient");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
STATICMETHOD (getInstance, "getInstance", "()Landroid/webkit/CookieManager;")
DECLARE_JNI_CLASS (AndroidCookieManager, "android/webkit/CookieManager");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "(L" JUCE_ANDROID_ACTIVITY_CLASSPATH ";J)V")
DECLARE_JNI_CLASS (JuceWebChromeClient, JUCE_ANDROID_ACTIVITY_CLASSPATH "$JuceWebChromeClient");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "(L" JUCE_ANDROID_ACTIVITY_CLASSPATH ";J)V") \
METHOD (hostDeleted, "hostDeleted", "()V")
DECLARE_JNI_CLASS (JuceWebViewClient, JUCE_ANDROID_ACTIVITY_CLASSPATH "$JuceWebViewClient");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (setBuiltInZoomControls, "setBuiltInZoomControls", "(Z)V") \
METHOD (setDisplayZoomControls, "setDisplayZoomControls", "(Z)V") \
METHOD (setJavaScriptEnabled, "setJavaScriptEnabled", "(Z)V") \
METHOD (setSupportMultipleWindows, "setSupportMultipleWindows", "(Z)V")
DECLARE_JNI_CLASS (WebSettings, "android/webkit/WebSettings");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (toString, "toString", "()Ljava/lang/String;")
DECLARE_JNI_CLASS (SslError, "android/net/http/SslError")
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
STATICMETHOD (encode, "encode", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")
DECLARE_JNI_CLASS (URLEncoder, "java/net/URLEncoder")
#undef JNI_CLASS_MEMBERS
//==============================================================================
class WebBrowserComponent::Pimpl : public AndroidViewComponent,
public AsyncUpdater
{
public:
Pimpl (WebBrowserComponent& o)
: AndroidViewComponent (true),
owner (o)
{
auto* env = getEnv();
setView (env->NewObject (AndroidWebView, AndroidWebView.constructor, android.activity.get()));
auto settings = LocalRef<jobject> (env->CallObjectMethod ((jobject) getView(), AndroidWebView.getSettings));
env->CallVoidMethod (settings, WebSettings.setJavaScriptEnabled, true);
env->CallVoidMethod (settings, WebSettings.setBuiltInZoomControls, true);
env->CallVoidMethod (settings, WebSettings.setDisplayZoomControls, false);
env->CallVoidMethod (settings, WebSettings.setSupportMultipleWindows, true);
juceWebChromeClient = GlobalRef (LocalRef<jobject> (env->NewObject (JuceWebChromeClient, JuceWebChromeClient.constructor,
android.activity.get(),
reinterpret_cast<jlong>(&owner))));
env->CallVoidMethod ((jobject) getView(), AndroidWebView.setWebChromeClient, juceWebChromeClient.get());
juceWebViewClient = GlobalRef (LocalRef<jobject> (env->NewObject (JuceWebViewClient, JuceWebViewClient.constructor,
android.activity.get(),
reinterpret_cast<jlong>(&owner))));
env->CallVoidMethod ((jobject) getView(), AndroidWebView.setWebViewClient, juceWebViewClient.get());
}
~Pimpl()
{
auto* env = getEnv();
env->CallVoidMethod ((jobject) getView(), AndroidWebView.stopLoading);
auto defaultChromeClient = LocalRef<jobject> (env->NewObject (AndroidWebChromeClient, AndroidWebChromeClient.constructor));
auto defaultViewClient = LocalRef<jobject> (env->NewObject (AndroidWebViewClient, AndroidWebViewClient .constructor));
env->CallVoidMethod ((jobject) getView(), AndroidWebView.setWebChromeClient, defaultChromeClient.get());
env->CallVoidMethod ((jobject) getView(), AndroidWebView.setWebViewClient, defaultViewClient .get());
masterReference.clear();
// if other Java thread is waiting for us to respond to page load request
// wake it up immediately (false answer will be sent), so that it releases
// the lock we need when calling hostDeleted.
responseReadyEvent.signal();
env->CallVoidMethod (juceWebViewClient, JuceWebViewClient.hostDeleted);
}
void goToURL (const String& url,
const StringArray* headers,
const MemoryBlock* postData)
{
auto* env = getEnv();
if (headers == nullptr && postData == nullptr)
{
env->CallVoidMethod ((jobject) getView(), AndroidWebView.loadUrl, javaString (url).get(), 0);
}
else if (headers != nullptr && postData == nullptr)
{
auto headersMap = LocalRef<jobject> (env->NewObject (JavaHashMap,
JavaHashMap.constructorWithCapacity,
headers->size()));
for (const auto& header : *headers)
{
auto name = header.upToFirstOccurrenceOf (":", false, false).trim();
auto value = header.fromFirstOccurrenceOf (":", false, false).trim();
env->CallObjectMethod (headersMap, JavaMap.put,
javaString (name).get(),
javaString (value).get());
}
env->CallVoidMethod ((jobject) getView(), AndroidWebView.loadUrl,
javaString (url).get(), headersMap.get());
}
else if (headers == nullptr && postData != nullptr)
{
auto dataStringJuce = postData->toString();
auto dataStringJava = javaString (dataStringJuce);
auto encodingString = LocalRef<jobject> (env->CallStaticObjectMethod (URLEncoder, URLEncoder.encode,
dataStringJava.get(), javaString ("utf-8").get()));
auto bytes = LocalRef<jbyteArray> ((jbyteArray) env->CallObjectMethod (encodingString, JavaString.getBytes));
env->CallVoidMethod ((jobject) getView(), AndroidWebView.postUrl,
javaString (url).get(), bytes.get());
}
else if (headers != nullptr && postData != nullptr)
{
// There is no support for both extra headers and post data in Android WebView, so
// we need to open URL manually.
URL urlToUse = URL (url).withPOSTData (*postData);
connectionThread.reset (new ConnectionThread (*this, urlToUse, *headers));
}
}
void stop()
{
connectionThread = nullptr;
getEnv()->CallVoidMethod ((jobject) getView(), AndroidWebView.stopLoading);
}
void goBack()
{
connectionThread = nullptr;
getEnv()->CallVoidMethod ((jobject) getView(), AndroidWebView.goBack);
}
void goForward()
{
connectionThread = nullptr;
getEnv()->CallVoidMethod ((jobject) getView(), AndroidWebView.goForward);
}
void refresh()
{
connectionThread = nullptr;
getEnv()->CallVoidMethod ((jobject) getView(), AndroidWebView.reload);
}
void handleAsyncUpdate()
{
jassert (connectionThread != nullptr);
if (connectionThread == nullptr)
return;
auto& result = connectionThread->getResult();
if (result.statusCode >= 200 && result.statusCode < 300)
{
auto url = javaString (result.url);
auto data = javaString (result.data);
auto mimeType = javaString ("text/html");
auto encoding = javaString ("utf-8");
getEnv()->CallVoidMethod ((jobject) getView(), AndroidWebView.loadDataWithBaseURL,
url.get(), data.get(), mimeType.get(),
encoding.get(), 0);
}
else
{
owner.pageLoadHadNetworkError (result.description);
}
}
bool handlePageAboutToLoad (const String& url)
{
if (MessageManager::getInstance()->isThisTheMessageThread())
return owner.pageAboutToLoad (url);
WeakReference<Pimpl> weakRef (this);
if (weakRef == nullptr)
return false;
responseReadyEvent.reset();
bool shouldLoad = false;
MessageManager::callAsync ([weakRef, url, &shouldLoad]
{
if (weakRef == nullptr)
return;
shouldLoad = weakRef->owner.pageAboutToLoad (url);
weakRef->responseReadyEvent.signal();
});
responseReadyEvent.wait (-1);
return shouldLoad;
}
private:
class ConnectionThread : private Thread
{
public:
struct Result
{
String url;
int statusCode = 0;
String description;
String data;
};
ConnectionThread (Pimpl& ownerToUse,
URL& url,
const StringArray& headers)
: Thread ("WebBrowserComponent::Pimpl::ConnectionThread"),
owner (ownerToUse),
webInputStream (new WebInputStream (url, true))
{
webInputStream->withExtraHeaders (headers.joinIntoString ("\n"));
webInputStream->withConnectionTimeout (10000);
result.url = url.toString (true);
startThread();
}
~ConnectionThread()
{
webInputStream->cancel();
signalThreadShouldExit();
waitForThreadToExit (10000);
webInputStream = nullptr;
}
void run() override
{
if (! webInputStream->connect (nullptr))
{
result.description = "Could not establish connection";
owner.triggerAsyncUpdate();
return;
}
result.statusCode = webInputStream->getStatusCode();
result.description = "Status code: " + String (result.statusCode);
readFromInputStream();
owner.triggerAsyncUpdate();
}
const Result& getResult() { return result; }
private:
void readFromInputStream()
{
MemoryOutputStream ostream;
while (true)
{
if (threadShouldExit())
return;
char buffer [8192];
const int num = webInputStream->read (buffer, sizeof (buffer));
if (num <= 0)
break;
ostream.write (buffer, (size_t) num);
}
result.data = ostream.toUTF8();
}
Pimpl& owner;
std::unique_ptr<WebInputStream> webInputStream;
Result result;
};
WebBrowserComponent& owner;
GlobalRef juceWebChromeClient;
GlobalRef juceWebViewClient;
std::unique_ptr<ConnectionThread> connectionThread;
WaitableEvent responseReadyEvent;
WeakReference<Pimpl>::Master masterReference;
friend class WeakReference<Pimpl>;
};
//==============================================================================
WebBrowserComponent::WebBrowserComponent (const bool unloadWhenHidden)
: blankPageShown (false),
unloadPageWhenBrowserIsHidden (unloadWhenHidden)
{
setOpaque (true);
browser.reset (new Pimpl (*this));
addAndMakeVisible (browser.get());
}
WebBrowserComponent::~WebBrowserComponent()
{
}
//==============================================================================
void WebBrowserComponent::goToURL (const String& url,
const StringArray* headers,
const MemoryBlock* postData)
{
lastURL = url;
if (headers != nullptr)
lastHeaders = *headers;
else
lastHeaders.clear();
if (postData != nullptr)
lastPostData = *postData;
else
lastPostData.reset();
blankPageShown = false;
browser->goToURL (url, headers, postData);
}
void WebBrowserComponent::stop()
{
browser->stop();
}
void WebBrowserComponent::goBack()
{
lastURL.clear();
blankPageShown = false;
browser->goBack();
}
void WebBrowserComponent::goForward()
{
lastURL.clear();
browser->goForward();
}
void WebBrowserComponent::refresh()
{
browser->refresh();
}
//==============================================================================
void WebBrowserComponent::paint (Graphics& g)
{
g.fillAll (Colours::white);
}
void WebBrowserComponent::checkWindowAssociation()
{
if (isShowing())
{
if (blankPageShown)
goBack();
}
else
{
if (unloadPageWhenBrowserIsHidden && ! blankPageShown)
{
// when the component becomes invisible, some stuff like flash
// carries on playing audio, so we need to force it onto a blank
// page to avoid this, (and send it back when it's made visible again).
blankPageShown = true;
browser->goToURL ("about:blank", 0, 0);
}
}
}
void WebBrowserComponent::reloadLastURL()
{
if (lastURL.isNotEmpty())
{
goToURL (lastURL, &lastHeaders, lastPostData.getSize() == 0 ? nullptr : &lastPostData);
lastURL.clear();
}
}
void WebBrowserComponent::parentHierarchyChanged()
{
checkWindowAssociation();
}
void WebBrowserComponent::resized()
{
browser->setSize (getWidth(), getHeight());
}
void WebBrowserComponent::visibilityChanged()
{
checkWindowAssociation();
}
void WebBrowserComponent::focusGained (FocusChangeType)
{
}
void WebBrowserComponent::clearCookies()
{
auto* env = getEnv();
auto cookieManager = LocalRef<jobject> (env->CallStaticObjectMethod (AndroidCookieManager,
AndroidCookieManager.getInstance));
const bool apiAtLeast21 = env->CallStaticIntMethod (JuceAppActivity, JuceAppActivity.getAndroidSDKVersion) >= 21;
jmethodID clearCookiesMethod = 0;
if (apiAtLeast21)
{
clearCookiesMethod = env->GetMethodID (AndroidCookieManager, "removeAllCookies", "(Landroid/webkit/ValueCallback;)V");
env->CallVoidMethod (cookieManager, clearCookiesMethod, 0);
}
else
{
clearCookiesMethod = env->GetMethodID (AndroidCookieManager, "removeAllCookie", "()V");
env->CallVoidMethod (cookieManager, clearCookiesMethod);
}
}
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, webViewPageLoadStarted, bool, (JNIEnv* env, jobject /*activity*/, jlong host, jobject /*webView*/, jobject url))
{
setEnv (env);
return juce_webViewPageLoadStarted (reinterpret_cast<WebBrowserComponent*> (host),
juceString (static_cast<jstring> (url)));
}
bool juce_webViewPageLoadStarted (WebBrowserComponent* browserComponent, const String& url)
{
return browserComponent->browser->handlePageAboutToLoad (url);
}
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, webViewPageLoadFinished, void, (JNIEnv* env, jobject /*activity*/, jlong host, jobject /*webView*/, jobject url))
{
setEnv (env);
reinterpret_cast<WebBrowserComponent*> (host)->pageFinishedLoading (juceString (static_cast<jstring> (url)));
}
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, webViewReceivedError, void, (JNIEnv* env, jobject /*activity*/, jlong host, jobject /*webView*/, jobject /*request*/, jobject error))
{
setEnv (env);
jclass errorClass = env->FindClass ("android/webkit/WebResourceError");
if (errorClass != 0)
{
jmethodID method = env->GetMethodID (errorClass, "getDescription", "()Ljava/lang/CharSequence;");
if (method != 0)
{
auto sequence = LocalRef<jobject> (env->CallObjectMethod (error, method));
auto errorString = LocalRef<jstring> ((jstring) env->CallObjectMethod (sequence, JavaCharSequence.toString));
reinterpret_cast<WebBrowserComponent*> (host)->pageLoadHadNetworkError (juceString (errorString));
return;
}
}
// Should never get here!
jassertfalse;
reinterpret_cast<WebBrowserComponent*> (host)->pageLoadHadNetworkError ({});
}
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, webViewReceivedHttpError, void, (JNIEnv* env, jobject /*activity*/, jlong host, jobject /*webView*/, jobject /*request*/, jobject errorResponse))
{
setEnv (env);
jclass responseClass = env->FindClass ("android/webkit/WebResourceResponse");
if (responseClass != 0)
{
jmethodID method = env->GetMethodID (responseClass, "getReasonPhrase", "()Ljava/lang/String;");
if (method != 0)
{
auto errorString = LocalRef<jstring> ((jstring) env->CallObjectMethod (errorResponse, method));
reinterpret_cast<WebBrowserComponent*> (host)->pageLoadHadNetworkError (juceString (errorString));
return;
}
}
// Should never get here!
jassertfalse;
reinterpret_cast<WebBrowserComponent*> (host)->pageLoadHadNetworkError ({});
}
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, webViewReceivedSslError, void, (JNIEnv* env, jobject /*activity*/, jlong host, jobject /*webView*/, jobject /*sslErrorHandler*/, jobject sslError))
{
setEnv (env);
auto errorString = LocalRef<jstring> ((jstring) env->CallObjectMethod (sslError, SslError.toString));
reinterpret_cast<WebBrowserComponent*> (host)->pageLoadHadNetworkError (juceString (errorString));
}
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, webViewCloseWindowRequest, void, (JNIEnv* env, jobject /*activity*/, jlong host, jobject /*webView*/))
{
setEnv (env);
reinterpret_cast<WebBrowserComponent*> (host)->windowCloseRequest();
}
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, webViewCreateWindowRequest, void, (JNIEnv* env, jobject /*activity*/, jlong host, jobject /*webView*/))
{
setEnv (env);
reinterpret_cast<WebBrowserComponent*> (host)->newWindowAttemptingToLoad ({});
}
} // namespace juce