storage/mozStorageAsyncStatementJSHelper.cpp
author Kartikaya Gupta <kgupta@mozilla.com>
Tue, 08 May 2018 09:16:29 -0400
changeset 417340 0bb3414bd6af644addd5ea6c4b349c88e3a4a7b9
parent 376569 df5b4f5fe775d341647f85abcf9a0ca0aa573a67
child 448947 6f3709b3878117466168c40affa7bca0b60cf75b
permissions -rw-r--r--
Bug 1458598 - Override scrollframes with their descendant reference frames. r=mstange The test case has a fixed item A inside a scrollframe B which is inside a reference frame C which is inside the root scrollframe D. The ClipManager code currently uses D's scrollid as the scrolling ancestor for A, because the gecko display list's ASR is set up that way. However, we really want to set C as the scrolling ancestor, because otherwise the item A gets hoisted out of C and the transform from C doesn't get applied to it. This patch ensures that when we enter C, we install an override so that anything that would have used D's scrollid ends up using C's, which results in the correct behaviour. MozReview-Commit-ID: 31tscfT4xWW

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "nsIXPConnect.h"
#include "mozStorageAsyncStatement.h"
#include "mozStorageService.h"

#include "nsMemory.h"
#include "nsString.h"
#include "nsServiceManagerUtils.h"

#include "mozStorageAsyncStatementJSHelper.h"

#include "mozStorageAsyncStatementParams.h"

#include "jsapi.h"

#include "xpc_make_class.h"

namespace mozilla {
namespace storage {

////////////////////////////////////////////////////////////////////////////////
//// AsyncStatementJSHelper

nsresult
AsyncStatementJSHelper::getParams(AsyncStatement *aStatement,
                                  JSContext *aCtx,
                                  JSObject *aScopeObj,
                                  JS::Value *_params)
{
  MOZ_ASSERT(NS_IsMainThread());

#ifdef DEBUG
  int32_t state;
  (void)aStatement->GetState(&state);
  NS_ASSERTION(state == mozIStorageAsyncStatement::MOZ_STORAGE_STATEMENT_READY,
               "Invalid state to get the params object - all calls will fail!");
#endif

  JS::RootedObject scope(aCtx, aScopeObj);

  if (!aStatement->mStatementParamsHolder) {
    dom::GlobalObject global(aCtx, scope);
    if (global.Failed()) {
      return NS_ERROR_UNEXPECTED;
    }

    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports());

    RefPtr<AsyncStatementParams> params(new AsyncStatementParams(window, aStatement));
    NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);

    RefPtr<AsyncStatementParamsHolder> paramsHolder = new AsyncStatementParamsHolder(params);
    NS_ENSURE_TRUE(paramsHolder, NS_ERROR_OUT_OF_MEMORY);

    aStatement->mStatementParamsHolder =
      new nsMainThreadPtrHolder<AsyncStatementParamsHolder>(
        "Statement::mStatementParamsHolder", paramsHolder);
  }

  RefPtr<AsyncStatementParams> params(aStatement->mStatementParamsHolder->Get());
  JSObject* obj = params->WrapObject(aCtx, nullptr);
  if (!obj) {
    return NS_ERROR_UNEXPECTED;
  }

  _params->setObject(*obj);
  return NS_OK;
}

NS_IMETHODIMP_(MozExternalRefCountType) AsyncStatementJSHelper::AddRef() { return 2; }
NS_IMETHODIMP_(MozExternalRefCountType) AsyncStatementJSHelper::Release() { return 1; }
NS_INTERFACE_MAP_BEGIN(AsyncStatementJSHelper)
  NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

////////////////////////////////////////////////////////////////////////////////
//// nsIXPCScriptable

#define XPC_MAP_CLASSNAME         AsyncStatementJSHelper
#define XPC_MAP_QUOTED_CLASSNAME "AsyncStatementJSHelper"
#define XPC_MAP_FLAGS (XPC_SCRIPTABLE_WANT_RESOLVE | \
                       XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
#include "xpc_map_end.h"

NS_IMETHODIMP
AsyncStatementJSHelper::Resolve(nsIXPConnectWrappedNative *aWrapper,
                                JSContext *aCtx,
                                JSObject *aScopeObj,
                                jsid aId,
                                bool *resolvedp,
                                bool *_retval)
{
  if (!JSID_IS_STRING(aId))
    return NS_OK;

  // Cast to async via mozI* since direct from nsISupports is ambiguous.
  JS::RootedObject scope(aCtx, aScopeObj);
  JS::RootedId id(aCtx, aId);
  mozIStorageAsyncStatement *iAsyncStmt =
    static_cast<mozIStorageAsyncStatement *>(aWrapper->Native());
  AsyncStatement *stmt = static_cast<AsyncStatement *>(iAsyncStmt);

#ifdef DEBUG
  {
    nsISupports *supp = aWrapper->Native();
    nsCOMPtr<mozIStorageAsyncStatement> isStatement(do_QueryInterface(supp));
    NS_ASSERTION(isStatement, "How is this not an async statement?!");
  }
#endif

  if (::JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "params")) {
    JS::RootedValue val(aCtx);
    nsresult rv = getParams(stmt, aCtx, scope, val.address());
    NS_ENSURE_SUCCESS(rv, rv);
    *_retval = ::JS_DefinePropertyById(aCtx, scope, id, val, JSPROP_RESOLVING);
    *resolvedp = true;
    return NS_OK;
  }

  return NS_OK;
}

////////////////////////////////////////////////////////////////////////////////
//// AsyncStatementParamsHolder

NS_IMPL_ISUPPORTS0(AsyncStatementParamsHolder);

AsyncStatementParamsHolder::~AsyncStatementParamsHolder()
{
  MOZ_ASSERT(NS_IsMainThread());
  // We are considered dead at this point, so any wrappers for row or params
  // need to lose their reference to the statement.
  mParams->mStatement = nullptr;
}

} // namespace storage
} // namespace mozilla