Skip to content

Commit

Permalink
[embedlite] Introduce explicit top level window object into EmbedLite…
Browse files Browse the repository at this point in the history
… API.

This change allows the embedder to manage internal gecko widget tree in
more efficient manner. In current API when the embedder creates
EmbedLiteView object it automatically creates new gecko widget tree.
Each new view introduces a new widget tree that is not connected with
other trees in any way. The problem is that the top level widget in the
tree always needs to have a compositor associated with it. As a result
mulit tabbed browser based on EmbedLite will end up having multiple
compositors. Apart from the fact this configuration is not tested at all
in upstream products it's also extremely inefficient. Each compositor
ends up having it's own LayerManager which in turn has it's own set of
layer caches. Also, gecko compositor assumes it has exclusive control
over it's GLContext which fails miserably in configurations where the
embedders wants multiple EmbedLiteViews share the same compositing
surface/context (QOpenGLWebPage).

This patch introduces a concept of a window into EmbedLite API. The
window is supposed to be a top level widget shared by multiple views.
It is responsible for creating exactly one compositor instance that can
be shared between multiple EmbedLiteViews.

Signed-off-by: Piotr Tworek <piotr.tworek@jollamobile.com>
  • Loading branch information
tworaz committed Sep 29, 2015
1 parent cf674d1 commit dc89a06
Show file tree
Hide file tree
Showing 47 changed files with 1,570 additions and 774 deletions.
62 changes: 54 additions & 8 deletions embedding/embedlite/EmbedLiteApp.cpp
Expand Up @@ -22,6 +22,7 @@
#include "EmbedLiteAppThreadParent.h"
#include "EmbedLiteAppThreadChild.h"
#include "EmbedLiteView.h"
#include "EmbedLiteWindow.h"
#include "nsXULAppAPI.h"
#include "EmbedLiteMessagePump.h"

Expand Down Expand Up @@ -55,7 +56,6 @@ EmbedLiteApp::EmbedLiteApp()
, mAppParent(NULL)
, mAppChild(NULL)
, mEmbedType(EMBED_INVALID)
, mViewCreateID(0)
, mState(STOPPED)
, mRenderType(RENDER_AUTO)
, mProfilePath(strdup("mozembed"))
Expand Down Expand Up @@ -432,18 +432,36 @@ void EmbedLiteApp::RemoveObservers(nsTArray<nsCString>& observersList)
}

EmbedLiteView*
EmbedLiteApp::CreateView(uint32_t aParent, bool aIsPrivateWindow)
EmbedLiteApp::CreateView(EmbedLiteWindow* aWindow, uint32_t aParent, bool aIsPrivateWindow)
{
LOGT();
NS_ASSERTION(mState == INITIALIZED, "The app must be up and runnning by now");
mViewCreateID++;

PEmbedLiteViewParent* viewParent = static_cast<PEmbedLiteViewParent*>(mAppParent->SendPEmbedLiteViewConstructor(mViewCreateID, aParent, aIsPrivateWindow));
EmbedLiteView* view = new EmbedLiteView(this, viewParent, mViewCreateID);
mViews[mViewCreateID] = view;
static uint32_t sViewCreateID = 0;
sViewCreateID++;

PEmbedLiteViewParent* viewParent = static_cast<PEmbedLiteViewParent*>(
mAppParent->SendPEmbedLiteViewConstructor(aWindow->GetUniqueID(), sViewCreateID,
aParent, aIsPrivateWindow));
EmbedLiteView* view = new EmbedLiteView(this, aWindow, viewParent, sViewCreateID);
mViews[sViewCreateID] = view;
return view;
}

EmbedLiteWindow*
EmbedLiteApp::CreateWindow()
{
LOGT();
NS_ASSERTION(mState == INITIALIZED, "The app must be up and runnning by now");
static uint32_t sWindowCreateID = 0;
sWindowCreateID++;

PEmbedLiteWindowParent* windowParent = static_cast<PEmbedLiteWindowParent*>(
mAppParent->SendPEmbedLiteWindowConstructor(sWindowCreateID));
EmbedLiteWindow* window = new EmbedLiteWindow(this, windowParent, sWindowCreateID);
mWindows[sWindowCreateID] = window;
return window;
}

EmbedLiteView* EmbedLiteApp::GetViewByID(uint32_t id)
{
std::map<uint32_t, EmbedLiteView*>::iterator it = mViews.find(id);
Expand All @@ -454,6 +472,16 @@ EmbedLiteView* EmbedLiteApp::GetViewByID(uint32_t id)
return it->second;
}

EmbedLiteWindow* EmbedLiteApp::GetWindowByID(uint32_t id)
{
std::map<uint32_t, EmbedLiteWindow*>::iterator it = mWindows.find(id);
if (it == mWindows.end()) {
NS_ERROR("Window not found!");
return nullptr;
}
return it->second;
}

void
EmbedLiteApp::ChildReadyToDestroy()
{
Expand Down Expand Up @@ -508,9 +536,27 @@ void EmbedLiteApp::DestroyView(EmbedLiteView* aView)
delete view;
it->second = nullptr;
mViews.erase(it);
break;
return;
}
}
MOZ_ASSERT(false, "Invalid EmbedLiteView pointer!");
}

void EmbedLiteApp::DestroyWindow(EmbedLiteWindow* aWindow)
{
LOGT();
NS_ASSERTION(mState == INITIALIZED, "Wrong timing");
std::map<uint32_t, EmbedLiteWindow*>::iterator it;
for (it = mWindows.begin(); it != mWindows.end(); it++) {
if (it->second == aWindow) {
EmbedLiteWindow* window = it->second;
delete window;
it->second = nullptr;
mWindows.erase(it);
return;
}
}
MOZ_ASSERT(false, "Invalid EmbedLiteWindow pointer!");
}

void
Expand Down
15 changes: 10 additions & 5 deletions embedding/embedlite/EmbedLiteApp.h
Expand Up @@ -27,6 +27,7 @@ class EmbedLiteSubThread;
class EmbedLiteSubProcess;
class EmbedLiteAppProcessParent;
class EmbedLiteView;
class EmbedLiteWindow;
class PEmbedLiteAppParent;
class EmbedLiteAppListener
{
Expand Down Expand Up @@ -107,8 +108,10 @@ class EmbedLiteApp
// Must be called from same thread as StartChildThread, and before Stop()
virtual bool StopChildThread();

virtual EmbedLiteView* CreateView(uint32_t aParent = 0, bool aIsPrivateWindow = false);
virtual EmbedLiteView* CreateView(EmbedLiteWindow* aWindow, uint32_t aParent = 0, bool aIsPrivateWindow = false);
virtual EmbedLiteWindow* CreateWindow();
virtual void DestroyView(EmbedLiteView* aView);
virtual void DestroyWindow(EmbedLiteWindow* aWindow);

virtual void SetIsAccelerated(bool aIsAccelerated);
virtual bool IsAccelerated() {
Expand Down Expand Up @@ -168,14 +171,16 @@ class EmbedLiteApp
static void StartChild(EmbedLiteApp* aApp);
void Initialized();

friend class EmbedLiteAppThreadParent;
friend class EmbedLiteViewThreadParent;
friend class EmbedLiteAppProcessParent;
friend class EmbedLiteViewBaseParent;
friend class EmbedLiteAppThreadParent;
friend class EmbedLiteCompositorParent;
friend class EmbedLitePuppetWidget;
friend class EmbedLiteViewBaseChild;
friend class EmbedLiteViewBaseParent;
friend class EmbedLiteViewThreadParent;

EmbedLiteView* GetViewByID(uint32_t id);
EmbedLiteWindow* GetWindowByID(uint32_t id);
void ViewDestroyed(uint32_t id);
void ChildReadyToDestroy();
uint32_t CreateWindowRequested(const uint32_t& chromeFlags, const char* uri, const uint32_t& contextFlags, const uint32_t& parentId);
Expand All @@ -193,7 +198,7 @@ class EmbedLiteApp

EmbedType mEmbedType;
std::map<uint32_t, EmbedLiteView*> mViews;
uint32_t mViewCreateID;
std::map<uint32_t, EmbedLiteWindow*> mWindows;
State mState;
RenderType mRenderType;
char* mProfilePath;
Expand Down
132 changes: 13 additions & 119 deletions embedding/embedlite/EmbedLiteView.cpp
Expand Up @@ -25,8 +25,9 @@ namespace embedlite {
class FakeListener : public EmbedLiteViewListener {};
static FakeListener sFakeListener;

EmbedLiteView::EmbedLiteView(EmbedLiteApp* aApp, PEmbedLiteViewParent* aViewImpl, uint32_t aViewId)
EmbedLiteView::EmbedLiteView(EmbedLiteApp* aApp, EmbedLiteWindow* aWindow, PEmbedLiteViewParent* aViewImpl, uint32_t aViewId)
: mApp(aApp)
, mWindow(aWindow)
, mListener(NULL)
, mViewImpl(dynamic_cast<EmbedLiteViewIface*>(aViewImpl))
, mViewParent(aViewImpl)
Expand All @@ -39,7 +40,7 @@ EmbedLiteView::EmbedLiteView(EmbedLiteApp* aApp, PEmbedLiteViewParent* aViewImpl
EmbedLiteView::~EmbedLiteView()
{
LOGT("impl:%p", mViewImpl);
if (mViewImpl) {
if (mViewParent) {
unused << mViewParent->SendDestroy();
} else {
LOGNI();
Expand Down Expand Up @@ -192,136 +193,34 @@ EmbedLiteView::SendAsyncMessage(const char16_t* aMessageName, const char16_t* aM

// Render interface

bool
EmbedLiteView::RenderToImage(unsigned char* aData, int imgW, int imgH, int stride, int depth)
{
LOGF("data:%p, sz[%i,%i], stride:%i, depth:%i", aData, imgW, imgH, stride, depth);
NS_ENSURE_TRUE(mViewImpl, false);
return NS_SUCCEEDED(mViewImpl->RenderToImage(aData, imgW, imgH, stride, depth));
}

char*
EmbedLiteView::GetImageAsURL(int aWidth, int aHeight)
{
// copy from gfxASurface::WriteAsPNG_internal
NS_ENSURE_TRUE(mViewImpl, nullptr);
nsRefPtr<gfxImageSurface> img =
new gfxImageSurface(gfxIntSize(aWidth, aHeight), gfxImageFormat::RGB24);
mViewImpl->RenderToImage(img->Data(), img->Width(), img->Height(), img->Stride(), 24);
nsCOMPtr<imgIEncoder> encoder =
do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png");
NS_ENSURE_TRUE(encoder, nullptr);
gfxIntSize size = img->GetSize();
nsresult rv = encoder->InitFromData(img->Data(),
size.width * size.height * 4,
size.width,
size.height,
img->Stride(),
imgIEncoder::INPUT_FORMAT_HOSTARGB,
NS_LITERAL_STRING(""));
if (NS_FAILED(rv)) {
return nullptr;
}
nsCOMPtr<nsIInputStream> imgStream;
CallQueryInterface(encoder.get(), getter_AddRefs(imgStream));

if (!imgStream) {
return nullptr;
}

uint64_t bufSize64;
rv = imgStream->Available(&bufSize64);
if (NS_FAILED(rv)) {
return nullptr;
}

if (bufSize64 > UINT32_MAX - 16) {
return nullptr;
}

uint32_t bufSize = (uint32_t)bufSize64;

// ...leave a little extra room so we can call read again and make sure we
// got everything. 16 bytes for better padding (maybe)
bufSize += 16;
uint32_t imgSize = 0;
char* imgData = (char*)moz_malloc(bufSize);
if (!imgData) {
return nullptr;
}
uint32_t numReadThisTime = 0;
while ((rv = imgStream->Read(&imgData[imgSize],
bufSize - imgSize,
&numReadThisTime)) == NS_OK && numReadThisTime > 0) {
imgSize += numReadThisTime;
if (imgSize == bufSize) {
// need a bigger buffer, just double
bufSize *= 2;
char* newImgData = (char*)moz_realloc(imgData, bufSize);
if (!newImgData) {
moz_free(imgData);
return nullptr;
}
imgData = newImgData;
}
}

// base 64, result will be NULL terminated
nsCString encodedImg;
rv = Base64Encode(Substring(imgData, imgSize), encodedImg);
moz_free(imgData);
if (NS_FAILED(rv)) { // not sure why this would fail
return nullptr;
}

nsCString string("data:image/png;base64,");
string.Append(encodedImg);

return ToNewCString(string);
return mWindow->GetImageAsURL(aWidth, aHeight);
}

void
EmbedLiteView::SetViewSize(int width, int height)
bool
EmbedLiteView::RenderToImage(unsigned char* aData, int imgW, int imgH, int stride, int depth)
{
LOGNI("sz[%i,%i]", width, height);
NS_ENSURE_TRUE(mViewImpl, );
mViewImpl->SetViewSize(width, height);
return mWindow->RenderToImage(aData, imgW, imgH, stride, depth);
}

void
EmbedLiteView::SetGLViewPortSize(int width, int height)
EmbedLiteView::SetViewSize(int width, int height)
{
LOGNI("sz[%i,%i]", width, height);
NS_ENSURE_TRUE(mViewImpl, );
mViewImpl->SetGLViewPortSize(width, height);
mWindow->SetSize(width, height);
}

void
EmbedLiteView::SetScreenRotation(mozilla::ScreenRotation rotation)
{
NS_ENSURE_TRUE(mViewImpl, );
mViewImpl->SetScreenRotation(rotation);
mWindow->SetContentOrientation(rotation);
}

void
EmbedLiteView::ScheduleUpdate()
{
NS_ENSURE_TRUE(mViewImpl, );
mViewImpl->ScheduleUpdate();
}

void
EmbedLiteView::SuspendRendering()
{
NS_ENSURE_TRUE(mViewImpl, );
mViewImpl->SuspendRendering();
}

void
EmbedLiteView::ResumeRendering()
{
NS_ENSURE_TRUE(mViewImpl, );
mViewImpl->ResumeRendering();
mWindow->ScheduleUpdate();
}

void
Expand Down Expand Up @@ -398,19 +297,14 @@ EmbedLiteView::GetUniqueID()
NS_ENSURE_TRUE(mViewImpl, 0);
uint32_t id;
mViewImpl->GetUniqueID(&id);
if (id != mUniqueID) {
NS_ERROR("Something went wrong");
}
MOZ_ASSERT(id == mUniqueID);
return mUniqueID;
}

void*
EmbedLiteView::GetPlatformImage(int* width, int* height)
{
NS_ENSURE_TRUE(mViewImpl, nullptr);
void* aImage = 0;
mViewImpl->GetPlatformImage(&aImage, width, height);
return aImage;
return mWindow->GetPlatformImage(width, height);
}

} // namespace embedlite
Expand Down

0 comments on commit dc89a06

Please sign in to comment.