import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

1186
widget/BasicEvents.h Normal file

File diff suppressed because it is too large Load diff

52
widget/CommandList.h Normal file
View file

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
* Define NS_DEFIVE_COMMAND(aName, aCommandStr) before including this.
* @param aName The name useful in C++ of the command.
* @param aCommandStr The command string in JS.
*/
NS_DEFINE_COMMAND(BeginLine, cmd_beginLine)
NS_DEFINE_COMMAND(CharNext, cmd_charNext)
NS_DEFINE_COMMAND(CharPrevious, cmd_charPrevious)
NS_DEFINE_COMMAND(Copy, cmd_copy)
NS_DEFINE_COMMAND(Cut, cmd_cut)
NS_DEFINE_COMMAND(Delete, cmd_delete)
NS_DEFINE_COMMAND(DeleteCharBackward, cmd_deleteCharBackward)
NS_DEFINE_COMMAND(DeleteCharForward, cmd_deleteCharForward)
NS_DEFINE_COMMAND(DeleteToBeginningOfLine, cmd_deleteToBeginningOfLine)
NS_DEFINE_COMMAND(DeleteToEndOfLine, cmd_deleteToEndOfLine)
NS_DEFINE_COMMAND(DeleteWordBackward, cmd_deleteWordBackward)
NS_DEFINE_COMMAND(DeleteWordForward, cmd_deleteWordForward)
NS_DEFINE_COMMAND(EndLine, cmd_endLine)
NS_DEFINE_COMMAND(LineNext, cmd_lineNext)
NS_DEFINE_COMMAND(LinePrevious, cmd_linePrevious)
NS_DEFINE_COMMAND(MoveBottom, cmd_moveBottom)
NS_DEFINE_COMMAND(MovePageDown, cmd_movePageDown)
NS_DEFINE_COMMAND(MovePageUp, cmd_movePageUp)
NS_DEFINE_COMMAND(MoveTop, cmd_moveTop)
NS_DEFINE_COMMAND(Paste, cmd_paste)
NS_DEFINE_COMMAND(ScrollBottom, cmd_scrollBottom)
NS_DEFINE_COMMAND(ScrollLineDown, cmd_scrollLineDown)
NS_DEFINE_COMMAND(ScrollLineUp, cmd_scrollLineUp)
NS_DEFINE_COMMAND(ScrollPageDown, cmd_scrollPageDown)
NS_DEFINE_COMMAND(ScrollPageUp, cmd_scrollPageUp)
NS_DEFINE_COMMAND(ScrollTop, cmd_scrollTop)
NS_DEFINE_COMMAND(SelectAll, cmd_selectAll)
NS_DEFINE_COMMAND(SelectBeginLine, cmd_selectBeginLine)
NS_DEFINE_COMMAND(SelectBottom, cmd_selectBottom)
NS_DEFINE_COMMAND(SelectCharNext, cmd_selectCharNext)
NS_DEFINE_COMMAND(SelectCharPrevious, cmd_selectCharPrevious)
NS_DEFINE_COMMAND(SelectEndLine, cmd_selectEndLine)
NS_DEFINE_COMMAND(SelectLineNext, cmd_selectLineNext)
NS_DEFINE_COMMAND(SelectLinePrevious, cmd_selectLinePrevious)
NS_DEFINE_COMMAND(SelectPageDown, cmd_selectPageDown)
NS_DEFINE_COMMAND(SelectPageUp, cmd_selectPageUp)
NS_DEFINE_COMMAND(SelectTop, cmd_selectTop)
NS_DEFINE_COMMAND(SelectWordNext, cmd_selectWordNext)
NS_DEFINE_COMMAND(SelectWordPrevious, cmd_selectWordPrevious)
NS_DEFINE_COMMAND(WordNext, cmd_wordNext)
NS_DEFINE_COMMAND(WordPrevious, cmd_wordPrevious)

View file

@ -0,0 +1,84 @@
/* 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 "CompositorWidget.h"
#include "GLConsts.h"
#include "nsBaseWidget.h"
#include "VsyncDispatcher.h"
namespace mozilla {
namespace widget {
CompositorWidget::~CompositorWidget()
{
}
already_AddRefed<gfx::DrawTarget>
CompositorWidget::StartRemoteDrawing()
{
return nullptr;
}
void
CompositorWidget::CleanupRemoteDrawing()
{
mLastBackBuffer = nullptr;
}
already_AddRefed<gfx::DrawTarget>
CompositorWidget::GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
const LayoutDeviceIntRect& aRect,
const LayoutDeviceIntRect& aClearRect)
{
MOZ_ASSERT(aScreenTarget);
gfx::SurfaceFormat format =
aScreenTarget->GetFormat() == gfx::SurfaceFormat::B8G8R8X8 ? gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::B8G8R8A8;
gfx::IntSize size = aRect.ToUnknownRect().Size();
gfx::IntSize clientSize(GetClientSize().ToUnknownSize());
RefPtr<gfx::DrawTarget> target;
// Re-use back buffer if possible
if (mLastBackBuffer &&
mLastBackBuffer->GetBackendType() == aScreenTarget->GetBackendType() &&
mLastBackBuffer->GetFormat() == format &&
size <= mLastBackBuffer->GetSize() &&
mLastBackBuffer->GetSize() <= clientSize) {
target = mLastBackBuffer;
target->SetTransform(gfx::Matrix());
if (!aClearRect.IsEmpty()) {
gfx::IntRect clearRect = aClearRect.ToUnknownRect() - aRect.ToUnknownRect().TopLeft();
target->ClearRect(gfx::Rect(clearRect.x, clearRect.y, clearRect.width, clearRect.height));
}
} else {
target = aScreenTarget->CreateSimilarDrawTarget(size, format);
mLastBackBuffer = target;
}
return target.forget();
}
already_AddRefed<gfx::SourceSurface>
CompositorWidget::EndBackBufferDrawing()
{
RefPtr<gfx::SourceSurface> surface = mLastBackBuffer ? mLastBackBuffer->Snapshot() : nullptr;
return surface.forget();
}
uint32_t
CompositorWidget::GetGLFrameBufferFormat()
{
return LOCAL_GL_RGBA;
}
RefPtr<VsyncObserver>
CompositorWidget::GetVsyncObserver() const
{
// This should only used when the widget is in the GPU process, and should be
// implemented by IPDL-enabled CompositorWidgets.
// GPU process does not have a CompositorVsyncDispatcher.
MOZ_ASSERT_UNREACHABLE("Must be implemented by derived class");
return nullptr;
}
} // namespace widget
} // namespace mozilla

286
widget/CompositorWidget.h Normal file
View file

@ -0,0 +1,286 @@
/* 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/. */
#ifndef mozilla_widget_CompositorWidget_h__
#define mozilla_widget_CompositorWidget_h__
#include "nsISupports.h"
#include "mozilla/RefPtr.h"
#include "Units.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/layers/LayersTypes.h"
class nsIWidget;
class nsBaseWidget;
namespace mozilla {
class VsyncObserver;
namespace layers {
class Compositor;
class LayerManagerComposite;
class Compositor;
class Composer2D;
} // namespace layers
namespace gfx {
class DrawTarget;
class SourceSurface;
} // namespace gfx
namespace widget {
class WinCompositorWidget;
class X11CompositorWidget;
class AndroidCompositorWidget;
class CompositorWidgetInitData;
// Gecko widgets usually need to communicate with the CompositorWidget with
// platform-specific messages (for example to update the window size or
// transparency). This functionality is controlled through a "host". Since
// this functionality is platform-dependent, it is only forward declared
// here.
class CompositorWidgetDelegate;
// Platforms that support out-of-process widgets.
#if defined(XP_WIN) || defined(MOZ_X11)
// CompositorWidgetParent should implement CompositorWidget and
// PCompositorWidgetParent.
class CompositorWidgetParent;
// CompositorWidgetChild should implement CompositorWidgetDelegate and
// PCompositorWidgetChild.
class CompositorWidgetChild;
# define MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
#endif
class WidgetRenderingContext
{
public:
#if defined(XP_MACOSX)
WidgetRenderingContext() : mLayerManager(nullptr) {}
layers::LayerManagerComposite* mLayerManager;
#elif defined(MOZ_WIDGET_ANDROID)
WidgetRenderingContext() : mCompositor(nullptr) {}
layers::Compositor* mCompositor;
#endif
};
/**
* Access to a widget from the compositor is restricted to these methods.
*/
class CompositorWidget
{
public:
NS_INLINE_DECL_REFCOUNTING(mozilla::widget::CompositorWidget)
/**
* Create an in-process compositor widget. aWidget may be ignored if the
* platform does not require it.
*/
static RefPtr<CompositorWidget> CreateLocal(const CompositorWidgetInitData& aInitData, nsIWidget* aWidget);
/**
* Called before rendering using OMTC. Returns false when the widget is
* not ready to be rendered (for example while the window is closed).
*
* Always called from the compositing thread, which may be the main-thread if
* OMTC is not enabled.
*/
virtual bool PreRender(WidgetRenderingContext* aContext) {
return true;
}
/**
* Called after rendering using OMTC. Not called when rendering was
* cancelled by a negative return value from PreRender.
*
* Always called from the compositing thread, which may be the main-thread if
* OMTC is not enabled.
*/
virtual void PostRender(WidgetRenderingContext* aContext)
{}
/**
* Called before the LayerManager draws the layer tree.
*
* Always called from the compositing thread.
*/
virtual void DrawWindowUnderlay(WidgetRenderingContext* aContext,
LayoutDeviceIntRect aRect)
{}
/**
* Called after the LayerManager draws the layer tree
*
* Always called from the compositing thread.
*/
virtual void DrawWindowOverlay(WidgetRenderingContext* aContext,
LayoutDeviceIntRect aRect)
{}
/**
* Return a DrawTarget for the window which can be composited into.
*
* Called by BasicCompositor on the compositor thread for OMTC drawing
* before each composition.
*
* The window may specify its buffer mode. If unspecified, it is assumed
* to require double-buffering.
*/
virtual already_AddRefed<gfx::DrawTarget> StartRemoteDrawing();
virtual already_AddRefed<gfx::DrawTarget>
StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion,
layers::BufferMode* aBufferMode)
{
return StartRemoteDrawing();
}
/**
* Ensure that what was painted into the DrawTarget returned from
* StartRemoteDrawing reaches the screen.
*
* Called by BasicCompositor on the compositor thread for OMTC drawing
* after each composition.
*/
virtual void EndRemoteDrawing()
{}
virtual void EndRemoteDrawingInRegion(gfx::DrawTarget* aDrawTarget,
LayoutDeviceIntRegion& aInvalidRegion)
{
EndRemoteDrawing();
}
/**
* Return true when it is better to defer EndRemoteDrawing().
*
* Called by BasicCompositor on the compositor thread for OMTC drawing
* after each composition.
*/
virtual bool NeedsToDeferEndRemoteDrawing() {
return false;
}
/**
* Called when shutting down the LayerManager to clean-up any cached resources.
*
* Always called from the compositing thread.
*/
virtual void CleanupWindowEffects()
{}
/**
* A hook for the widget to prepare a Compositor, during the latter's initialization.
*
* If this method returns true, it means that the widget will be able to
* present frames from the compoositor.
*
* Returning false will cause the compositor's initialization to fail, and
* a different compositor backend will be used (if any).
*/
virtual bool InitCompositor(layers::Compositor* aCompositor) {
return true;
}
/**
* Return the size of the drawable area of the widget.
*/
virtual LayoutDeviceIntSize GetClientSize() = 0;
/**
* Return the internal format of the default framebuffer for this
* widget.
*/
virtual uint32_t GetGLFrameBufferFormat();
/**
* If this widget has a more efficient composer available for its
* native framebuffer, return it.
*
* This can be called from a non-main thread, but that thread must
* hold a strong reference to this.
*/
virtual layers::Composer2D* GetComposer2D() {
return nullptr;
}
/*
* Access the underlying nsIWidget. This method will be removed when the compositor no longer
* depends on nsIWidget on any platform.
*/
virtual nsIWidget* RealWidget() = 0;
/**
* Clean up any resources used by Start/EndRemoteDrawing.
*
* Called by BasicCompositor on the compositor thread for OMTC drawing
* when the compositor is destroyed.
*/
virtual void CleanupRemoteDrawing();
/**
* Return a key that can represent the widget object round-trip across the
* CompositorBridge channel. This only needs to be implemented on GTK and
* Windows.
*
* The key must be the nsIWidget pointer cast to a uintptr_t. See
* CompositorBridgeChild::RecvHideAllPlugins and
* CompositorBridgeParent::SendHideAllPlugins.
*/
virtual uintptr_t GetWidgetKey() {
return 0;
}
/**
* Create a backbuffer for the software compositor.
*/
virtual already_AddRefed<gfx::DrawTarget>
GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
const LayoutDeviceIntRect& aRect,
const LayoutDeviceIntRect& aClearRect);
/**
* Ensure end of composition to back buffer.
*
* Called by BasicCompositor on the compositor thread for OMTC drawing
* after each composition to back buffer.
*/
virtual already_AddRefed<gfx::SourceSurface> EndBackBufferDrawing();
/**
* Observe or unobserve vsync.
*/
virtual void ObserveVsync(VsyncObserver* aObserver) = 0;
/**
* This is only used by out-of-process compositors.
*/
virtual RefPtr<VsyncObserver> GetVsyncObserver() const;
virtual WinCompositorWidget* AsWindows() {
return nullptr;
}
virtual X11CompositorWidget* AsX11() {
return nullptr;
}
virtual AndroidCompositorWidget* AsAndroid() {
return nullptr;
}
/**
* Return the platform-specific delegate for the widget, if any.
*/
virtual CompositorWidgetDelegate* AsDelegate() {
return nullptr;
}
protected:
virtual ~CompositorWidget();
// Back buffer of BasicCompositor
RefPtr<gfx::DrawTarget> mLastBackBuffer;
};
} // namespace widget
} // namespace mozilla
#endif

1381
widget/ContentCache.cpp Normal file

File diff suppressed because it is too large Load diff

449
widget/ContentCache.h Normal file
View file

@ -0,0 +1,449 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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/. */
#ifndef mozilla_ContentCache_h
#define mozilla_ContentCache_h
#include <stdint.h>
#include "mozilla/Assertions.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/EventForwards.h"
#include "mozilla/WritingModes.h"
#include "nsIWidget.h"
#include "nsString.h"
#include "nsTArray.h"
#include "Units.h"
namespace mozilla {
class ContentCacheInParent;
/**
* ContentCache stores various information of the child content.
* This class has members which are necessary both in parent process and
* content process.
*/
class ContentCache
{
public:
typedef InfallibleTArray<LayoutDeviceIntRect> RectArray;
typedef widget::IMENotification IMENotification;
ContentCache();
protected:
// Whole text in the target
nsString mText;
// Start offset of the composition string.
uint32_t mCompositionStart;
enum
{
ePrevCharRect = 1,
eNextCharRect = 0
};
struct Selection final
{
// Following values are offset in "flat text".
uint32_t mAnchor;
uint32_t mFocus;
WritingMode mWritingMode;
// Character rects at previous and next character of mAnchor and mFocus.
// The reason why ContentCache needs to store each previous character of
// them is IME may query character rect of the last character of a line
// when caret is at the end of the line.
// Note that use ePrevCharRect and eNextCharRect for accessing each item.
LayoutDeviceIntRect mAnchorCharRects[2];
LayoutDeviceIntRect mFocusCharRects[2];
// Whole rect of selected text. This is empty if the selection is collapsed.
LayoutDeviceIntRect mRect;
Selection()
: mAnchor(UINT32_MAX)
, mFocus(UINT32_MAX)
{
}
void Clear()
{
mAnchor = mFocus = UINT32_MAX;
mWritingMode = WritingMode();
ClearAnchorCharRects();
ClearFocusCharRects();
mRect.SetEmpty();
}
void ClearAnchorCharRects()
{
for (size_t i = 0; i < ArrayLength(mAnchorCharRects); i++) {
mAnchorCharRects[i].SetEmpty();
}
}
void ClearFocusCharRects()
{
for (size_t i = 0; i < ArrayLength(mFocusCharRects); i++) {
mFocusCharRects[i].SetEmpty();
}
}
bool IsValid() const
{
return mAnchor != UINT32_MAX && mFocus != UINT32_MAX;
}
bool Collapsed() const
{
NS_ASSERTION(IsValid(),
"The caller should check if the selection is valid");
return mFocus == mAnchor;
}
bool Reversed() const
{
NS_ASSERTION(IsValid(),
"The caller should check if the selection is valid");
return mFocus < mAnchor;
}
uint32_t StartOffset() const
{
NS_ASSERTION(IsValid(),
"The caller should check if the selection is valid");
return Reversed() ? mFocus : mAnchor;
}
uint32_t EndOffset() const
{
NS_ASSERTION(IsValid(),
"The caller should check if the selection is valid");
return Reversed() ? mAnchor : mFocus;
}
uint32_t Length() const
{
NS_ASSERTION(IsValid(),
"The caller should check if the selection is valid");
return Reversed() ? mAnchor - mFocus : mFocus - mAnchor;
}
LayoutDeviceIntRect StartCharRect() const
{
NS_ASSERTION(IsValid(),
"The caller should check if the selection is valid");
return Reversed() ? mFocusCharRects[eNextCharRect] :
mAnchorCharRects[eNextCharRect];
}
LayoutDeviceIntRect EndCharRect() const
{
NS_ASSERTION(IsValid(),
"The caller should check if the selection is valid");
return Reversed() ? mAnchorCharRects[eNextCharRect] :
mFocusCharRects[eNextCharRect];
}
} mSelection;
bool IsSelectionValid() const
{
return mSelection.IsValid() && mSelection.EndOffset() <= mText.Length();
}
// Stores first char rect because Yosemite's Japanese IME sometimes tries
// to query it. If there is no text, this is caret rect.
LayoutDeviceIntRect mFirstCharRect;
struct Caret final
{
uint32_t mOffset;
LayoutDeviceIntRect mRect;
Caret()
: mOffset(UINT32_MAX)
{
}
void Clear()
{
mOffset = UINT32_MAX;
mRect.SetEmpty();
}
bool IsValid() const { return mOffset != UINT32_MAX; }
uint32_t Offset() const
{
NS_ASSERTION(IsValid(),
"The caller should check if the caret is valid");
return mOffset;
}
} mCaret;
struct TextRectArray final
{
uint32_t mStart;
RectArray mRects;
TextRectArray()
: mStart(UINT32_MAX)
{
}
void Clear()
{
mStart = UINT32_MAX;
mRects.Clear();
}
bool IsValid() const
{
if (mStart == UINT32_MAX) {
return false;
}
CheckedInt<uint32_t> endOffset =
CheckedInt<uint32_t>(mStart) + mRects.Length();
return endOffset.isValid();
}
bool HasRects() const
{
return IsValid() && !mRects.IsEmpty();
}
uint32_t StartOffset() const
{
NS_ASSERTION(IsValid(),
"The caller should check if the caret is valid");
return mStart;
}
uint32_t EndOffset() const
{
NS_ASSERTION(IsValid(),
"The caller should check if the caret is valid");
if (!IsValid()) {
return UINT32_MAX;
}
return mStart + mRects.Length();
}
bool InRange(uint32_t aOffset) const
{
return IsValid() &&
StartOffset() <= aOffset && aOffset < EndOffset();
}
bool InRange(uint32_t aOffset, uint32_t aLength) const
{
CheckedInt<uint32_t> endOffset =
CheckedInt<uint32_t>(aOffset) + aLength;
if (NS_WARN_IF(!endOffset.isValid())) {
return false;
}
return InRange(aOffset) && aOffset + aLength <= EndOffset();
}
bool IsOverlappingWith(uint32_t aOffset, uint32_t aLength) const
{
if (!HasRects() || aOffset == UINT32_MAX || !aLength) {
return false;
}
CheckedInt<uint32_t> endOffset =
CheckedInt<uint32_t>(aOffset) + aLength;
if (NS_WARN_IF(!endOffset.isValid())) {
return false;
}
return aOffset < EndOffset() && endOffset.value() > mStart;
}
LayoutDeviceIntRect GetRect(uint32_t aOffset) const;
LayoutDeviceIntRect GetUnionRect(uint32_t aOffset, uint32_t aLength) const;
LayoutDeviceIntRect GetUnionRectAsFarAsPossible(
uint32_t aOffset, uint32_t aLength,
bool aRoundToExistingOffset) const;
} mTextRectArray;
LayoutDeviceIntRect mEditorRect;
friend class ContentCacheInParent;
friend struct IPC::ParamTraits<ContentCache>;
};
class ContentCacheInChild final : public ContentCache
{
public:
ContentCacheInChild();
/**
* When IME loses focus, this should be called and making this forget the
* content for reducing footprint.
*/
void Clear();
/**
* Cache*() retrieves the latest content information and store them.
* Be aware, CacheSelection() calls CacheTextRects(), and also CacheText()
* calls CacheSelection(). So, related data is also retrieved automatically.
*/
bool CacheEditorRect(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
bool CacheSelection(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
bool CacheText(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
bool CacheAll(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
/**
* SetSelection() modifies selection with specified raw data. And also this
* tries to retrieve text rects too.
*/
void SetSelection(nsIWidget* aWidget,
uint32_t aStartOffset,
uint32_t aLength,
bool aReversed,
const WritingMode& aWritingMode);
private:
bool QueryCharRect(nsIWidget* aWidget,
uint32_t aOffset,
LayoutDeviceIntRect& aCharRect) const;
bool QueryCharRectArray(nsIWidget* aWidget,
uint32_t aOffset,
uint32_t aLength,
RectArray& aCharRectArray) const;
bool CacheCaret(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
bool CacheTextRects(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
};
class ContentCacheInParent final : public ContentCache
{
public:
ContentCacheInParent();
/**
* AssignContent() is called when TabParent receives ContentCache from
* the content process. This doesn't copy composition information because
* it's managed by TabParent itself.
*/
void AssignContent(const ContentCache& aOther,
nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
/**
* HandleQueryContentEvent() sets content data to aEvent.mReply.
*
* For eQuerySelectedText, fail if the cache doesn't contain the whole
* selected range. (This shouldn't happen because PuppetWidget should have
* already sent the whole selection.)
*
* For eQueryTextContent, fail only if the cache doesn't overlap with
* the queried range. Note the difference from above. We use
* this behavior because a normal eQueryTextContent event is allowed to
* have out-of-bounds offsets, so that widget can request content without
* knowing the exact length of text. It's up to widget to handle cases when
* the returned offset/length are different from the queried offset/length.
*
* For eQueryTextRect, fail if cached offset/length aren't equals to input.
* Cocoa widget always queries selected offset, so it works on it.
*
* For eQueryCaretRect, fail if cached offset isn't equals to input
*
* For eQueryEditorRect, always success
*/
bool HandleQueryContentEvent(WidgetQueryContentEvent& aEvent,
nsIWidget* aWidget) const;
/**
* OnCompositionEvent() should be called before sending composition string.
* This returns true if the event should be sent. Otherwise, false.
*/
bool OnCompositionEvent(const WidgetCompositionEvent& aCompositionEvent);
/**
* OnSelectionEvent() should be called before sending selection event.
*/
void OnSelectionEvent(const WidgetSelectionEvent& aSelectionEvent);
/**
* OnEventNeedingAckHandled() should be called after the child process
* handles a sent event which needs acknowledging.
*
* WARNING: This may send notifications to IME. That might cause destroying
* TabParent or aWidget. Therefore, the caller must not destroy
* this instance during a call of this method.
*/
void OnEventNeedingAckHandled(nsIWidget* aWidget, EventMessage aMessage);
/**
* RequestIMEToCommitComposition() requests aWidget to commit or cancel
* composition. If it's handled synchronously, this returns true.
*
* @param aWidget The widget to be requested to commit or cancel
* the composition.
* @param aCancel When the caller tries to cancel the composition, true.
* Otherwise, i.e., tries to commit the composition, false.
* @param aCommittedString The committed string (i.e., the last data of
* dispatched composition events during requesting
* IME to commit composition.
* @return Whether the composition is actually committed
* synchronously.
*/
bool RequestIMEToCommitComposition(nsIWidget* aWidget,
bool aCancel,
nsAString& aCommittedString);
/**
* MaybeNotifyIME() may notify IME of the notification. If child process
* hasn't been handled all sending events yet, this stores the notification
* and flush it later.
*/
void MaybeNotifyIME(nsIWidget* aWidget,
const IMENotification& aNotification);
private:
IMENotification mPendingSelectionChange;
IMENotification mPendingTextChange;
IMENotification mPendingLayoutChange;
IMENotification mPendingCompositionUpdate;
// This is not nullptr only while the instance is requesting IME to
// composition. Then, data value of dispatched composition events should
// be stored into the instance.
nsAString* mCommitStringByRequest;
// mPendingEventsNeedingAck is increased before sending a composition event or
// a selection event and decreased after they are received in the child
// process.
uint32_t mPendingEventsNeedingAck;
// mCompositionStartInChild stores current composition start offset in the
// remote process.
uint32_t mCompositionStartInChild;
// mPendingCompositionCount is number of compositions which started in widget
// but not yet handled in the child process.
uint8_t mPendingCompositionCount;
// mWidgetHasComposition is true when the widget in this process thinks that
// IME has composition. So, this is set to true when eCompositionStart is
// dispatched and set to false when eCompositionCommit(AsIs) is dispatched.
bool mWidgetHasComposition;
/**
* When following methods' aRoundToExistingOffset is true, even if specified
* offset or range is out of bounds, the result is computed with the existing
* cache forcibly.
*/
bool GetCaretRect(uint32_t aOffset,
bool aRoundToExistingOffset,
LayoutDeviceIntRect& aCaretRect) const;
bool GetTextRect(uint32_t aOffset,
bool aRoundToExistingOffset,
LayoutDeviceIntRect& aTextRect) const;
bool GetUnionTextRects(uint32_t aOffset,
uint32_t aLength,
bool aRoundToExistingOffset,
LayoutDeviceIntRect& aUnionTextRect) const;
void FlushPendingNotifications(nsIWidget* aWidget);
};
} // namespace mozilla
#endif // mozilla_ContentCache_h

388
widget/ContentEvents.h Normal file
View file

@ -0,0 +1,388 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_ContentEvents_h__
#define mozilla_ContentEvents_h__
#include <stdint.h>
#include "mozilla/BasicEvents.h"
#include "mozilla/dom/DataTransfer.h"
#include "mozilla/dom/EventTarget.h"
#include "nsCOMPtr.h"
#include "nsRect.h"
#include "nsStringGlue.h"
class nsIContent;
namespace mozilla {
/******************************************************************************
* mozilla::InternalScrollPortEvent
******************************************************************************/
class InternalScrollPortEvent : public WidgetGUIEvent
{
public:
virtual InternalScrollPortEvent* AsScrollPortEvent() override
{
return this;
}
enum OrientType
{
eVertical,
eHorizontal,
eBoth
};
InternalScrollPortEvent(bool aIsTrusted, EventMessage aMessage,
nsIWidget* aWidget)
: WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eScrollPortEventClass)
, mOrient(eVertical)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eScrollPortEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
InternalScrollPortEvent* result =
new InternalScrollPortEvent(false, mMessage, nullptr);
result->AssignScrollPortEventData(*this, true);
result->mFlags = mFlags;
return result;
}
OrientType mOrient;
void AssignScrollPortEventData(const InternalScrollPortEvent& aEvent,
bool aCopyTargets)
{
AssignGUIEventData(aEvent, aCopyTargets);
mOrient = aEvent.mOrient;
}
};
/******************************************************************************
* mozilla::InternalScrollPortEvent
******************************************************************************/
class InternalScrollAreaEvent : public WidgetGUIEvent
{
public:
virtual InternalScrollAreaEvent* AsScrollAreaEvent() override
{
return this;
}
InternalScrollAreaEvent(bool aIsTrusted, EventMessage aMessage,
nsIWidget* aWidget)
: WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eScrollAreaEventClass)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eScrollAreaEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
InternalScrollAreaEvent* result =
new InternalScrollAreaEvent(false, mMessage, nullptr);
result->AssignScrollAreaEventData(*this, true);
result->mFlags = mFlags;
return result;
}
nsRect mArea;
void AssignScrollAreaEventData(const InternalScrollAreaEvent& aEvent,
bool aCopyTargets)
{
AssignGUIEventData(aEvent, aCopyTargets);
mArea = aEvent.mArea;
}
};
/******************************************************************************
* mozilla::InternalFormEvent
*
* We hold the originating form control for form submit and reset events.
* mOriginator is a weak pointer (does not hold a strong reference).
******************************************************************************/
class InternalFormEvent : public WidgetEvent
{
public:
virtual InternalFormEvent* AsFormEvent() override { return this; }
InternalFormEvent(bool aIsTrusted, EventMessage aMessage)
: WidgetEvent(aIsTrusted, aMessage, eFormEventClass)
, mOriginator(nullptr)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eFormEventClass,
"Duplicate() must be overridden by sub class");
InternalFormEvent* result = new InternalFormEvent(false, mMessage);
result->AssignFormEventData(*this, true);
result->mFlags = mFlags;
return result;
}
nsIContent* mOriginator;
void AssignFormEventData(const InternalFormEvent& aEvent, bool aCopyTargets)
{
AssignEventData(aEvent, aCopyTargets);
// Don't copy mOriginator due to a weak pointer.
}
};
/******************************************************************************
* mozilla::InternalClipboardEvent
******************************************************************************/
class InternalClipboardEvent : public WidgetEvent
{
public:
virtual InternalClipboardEvent* AsClipboardEvent() override
{
return this;
}
InternalClipboardEvent(bool aIsTrusted, EventMessage aMessage)
: WidgetEvent(aIsTrusted, aMessage, eClipboardEventClass)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eClipboardEventClass,
"Duplicate() must be overridden by sub class");
InternalClipboardEvent* result =
new InternalClipboardEvent(false, mMessage);
result->AssignClipboardEventData(*this, true);
result->mFlags = mFlags;
return result;
}
nsCOMPtr<dom::DataTransfer> mClipboardData;
void AssignClipboardEventData(const InternalClipboardEvent& aEvent,
bool aCopyTargets)
{
AssignEventData(aEvent, aCopyTargets);
mClipboardData = aEvent.mClipboardData;
}
};
/******************************************************************************
* mozilla::InternalFocusEvent
******************************************************************************/
class InternalFocusEvent : public InternalUIEvent
{
public:
virtual InternalFocusEvent* AsFocusEvent() override { return this; }
InternalFocusEvent(bool aIsTrusted, EventMessage aMessage)
: InternalUIEvent(aIsTrusted, aMessage, eFocusEventClass)
, mFromRaise(false)
, mIsRefocus(false)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eFocusEventClass,
"Duplicate() must be overridden by sub class");
InternalFocusEvent* result = new InternalFocusEvent(false, mMessage);
result->AssignFocusEventData(*this, true);
result->mFlags = mFlags;
return result;
}
/// The possible related target
nsCOMPtr<dom::EventTarget> mRelatedTarget;
bool mFromRaise;
bool mIsRefocus;
void AssignFocusEventData(const InternalFocusEvent& aEvent, bool aCopyTargets)
{
AssignUIEventData(aEvent, aCopyTargets);
mRelatedTarget = aCopyTargets ? aEvent.mRelatedTarget : nullptr;
mFromRaise = aEvent.mFromRaise;
mIsRefocus = aEvent.mIsRefocus;
}
};
/******************************************************************************
* mozilla::InternalTransitionEvent
******************************************************************************/
class InternalTransitionEvent : public WidgetEvent
{
public:
virtual InternalTransitionEvent* AsTransitionEvent() override
{
return this;
}
InternalTransitionEvent(bool aIsTrusted, EventMessage aMessage)
: WidgetEvent(aIsTrusted, aMessage, eTransitionEventClass)
, mElapsedTime(0.0)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eTransitionEventClass,
"Duplicate() must be overridden by sub class");
InternalTransitionEvent* result =
new InternalTransitionEvent(false, mMessage);
result->AssignTransitionEventData(*this, true);
result->mFlags = mFlags;
return result;
}
nsString mPropertyName;
nsString mPseudoElement;
float mElapsedTime;
void AssignTransitionEventData(const InternalTransitionEvent& aEvent,
bool aCopyTargets)
{
AssignEventData(aEvent, aCopyTargets);
mPropertyName = aEvent.mPropertyName;
mElapsedTime = aEvent.mElapsedTime;
mPseudoElement = aEvent.mPseudoElement;
}
};
/******************************************************************************
* mozilla::InternalAnimationEvent
******************************************************************************/
class InternalAnimationEvent : public WidgetEvent
{
public:
virtual InternalAnimationEvent* AsAnimationEvent() override
{
return this;
}
InternalAnimationEvent(bool aIsTrusted, EventMessage aMessage)
: WidgetEvent(aIsTrusted, aMessage, eAnimationEventClass)
, mElapsedTime(0.0)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eAnimationEventClass,
"Duplicate() must be overridden by sub class");
InternalAnimationEvent* result =
new InternalAnimationEvent(false, mMessage);
result->AssignAnimationEventData(*this, true);
result->mFlags = mFlags;
return result;
}
nsString mAnimationName;
nsString mPseudoElement;
float mElapsedTime;
void AssignAnimationEventData(const InternalAnimationEvent& aEvent,
bool aCopyTargets)
{
AssignEventData(aEvent, aCopyTargets);
mAnimationName = aEvent.mAnimationName;
mElapsedTime = aEvent.mElapsedTime;
mPseudoElement = aEvent.mPseudoElement;
}
};
/******************************************************************************
* mozilla::InternalSVGZoomEvent
******************************************************************************/
class InternalSVGZoomEvent : public WidgetGUIEvent
{
public:
virtual InternalSVGZoomEvent* AsSVGZoomEvent() override { return this; }
InternalSVGZoomEvent(bool aIsTrusted, EventMessage aMessage)
: WidgetGUIEvent(aIsTrusted, aMessage, nullptr, eSVGZoomEventClass)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eSVGZoomEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
InternalSVGZoomEvent* result = new InternalSVGZoomEvent(false, mMessage);
result->AssignSVGZoomEventData(*this, true);
result->mFlags = mFlags;
return result;
}
void AssignSVGZoomEventData(const InternalSVGZoomEvent& aEvent,
bool aCopyTargets)
{
AssignGUIEventData(aEvent, aCopyTargets);
}
};
/******************************************************************************
* mozilla::InternalSMILTimeEvent
******************************************************************************/
class InternalSMILTimeEvent : public InternalUIEvent
{
public:
virtual InternalSMILTimeEvent* AsSMILTimeEvent() override
{
return this;
}
InternalSMILTimeEvent(bool aIsTrusted, EventMessage aMessage)
: InternalUIEvent(aIsTrusted, aMessage, eSMILTimeEventClass)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eSMILTimeEventClass,
"Duplicate() must be overridden by sub class");
InternalSMILTimeEvent* result = new InternalSMILTimeEvent(false, mMessage);
result->AssignSMILTimeEventData(*this, true);
result->mFlags = mFlags;
return result;
}
void AssignSMILTimeEventData(const InternalSMILTimeEvent& aEvent,
bool aCopyTargets)
{
AssignUIEventData(aEvent, aCopyTargets);
}
};
} // namespace mozilla
#endif // mozilla_ContentEvents_h__

61
widget/EventClassList.h Normal file
View file

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
* This header file lists up all event classes and related structs.
* Define NS_EVENT_CLASS(aPrefix, aName) and NS_ROOT_EVENT_CLASS(aPrefix, aName)
* before including this.
* If an event name is WidgetInputEvent, aPrefix is "Widget" and aName is
* "InputEvent". NS_ROOT_EVENT_CLASS() is only used for WidgetEvent for
* allowing special handling for it. If you don't need such special handling,
* you can define it as:
* #define NS_ROOT_EVENT_CLASS(aPrefix, aName) NS_EVENT_CLASS(aPrefix, aName)
*/
// BasicEvents.h
NS_ROOT_EVENT_CLASS(Widget, Event)
NS_EVENT_CLASS(Widget, GUIEvent)
NS_EVENT_CLASS(Widget, InputEvent)
NS_EVENT_CLASS(Internal, UIEvent)
// TextEvents.h
NS_EVENT_CLASS(Widget, KeyboardEvent)
NS_EVENT_CLASS(Widget, CompositionEvent)
NS_EVENT_CLASS(Widget, QueryContentEvent)
NS_EVENT_CLASS(Widget, SelectionEvent)
NS_EVENT_CLASS(Internal, EditorInputEvent)
NS_EVENT_CLASS(Internal, BeforeAfterKeyboardEvent)
// MouseEvents.h
NS_EVENT_CLASS(Widget, MouseEventBase)
NS_EVENT_CLASS(Widget, MouseEvent)
NS_EVENT_CLASS(Widget, DragEvent)
NS_EVENT_CLASS(Widget, MouseScrollEvent)
NS_EVENT_CLASS(Widget, WheelEvent)
NS_EVENT_CLASS(Widget, PointerEvent)
// TouchEvents.h
NS_EVENT_CLASS(Widget, GestureNotifyEvent)
NS_EVENT_CLASS(Widget, SimpleGestureEvent)
NS_EVENT_CLASS(Widget, TouchEvent)
// ContentEvents.h
NS_EVENT_CLASS(Internal, ScrollPortEvent)
NS_EVENT_CLASS(Internal, ScrollAreaEvent)
NS_EVENT_CLASS(Internal, FormEvent)
NS_EVENT_CLASS(Internal, ClipboardEvent)
NS_EVENT_CLASS(Internal, FocusEvent)
NS_EVENT_CLASS(Internal, TransitionEvent)
NS_EVENT_CLASS(Internal, AnimationEvent)
NS_EVENT_CLASS(Internal, SVGZoomEvent)
NS_EVENT_CLASS(Internal, SMILTimeEvent)
// MiscEvents.h
NS_EVENT_CLASS(Widget, CommandEvent)
NS_EVENT_CLASS(Widget, ContentCommandEvent)
NS_EVENT_CLASS(Widget, PluginEvent)
// InternalMutationEvent.h (dom/events)
NS_EVENT_CLASS(Internal, MutationEvent)

173
widget/EventForwards.h Normal file
View file

@ -0,0 +1,173 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_EventForwards_h__
#define mozilla_EventForwards_h__
#include <stdint.h>
#include "nsTArray.h"
class nsCString;
/**
* XXX Following enums should be in BasicEvents.h. However, currently, it's
* impossible to use foward delearation for enum.
*/
/**
* Return status for event processors.
*/
enum nsEventStatus
{
// The event is ignored, do default processing
nsEventStatus_eIgnore,
// The event is consumed, don't do default processing
nsEventStatus_eConsumeNoDefault,
// The event is consumed, but do default processing
nsEventStatus_eConsumeDoDefault,
// Value is not for use, only for serialization
nsEventStatus_eSentinel
};
namespace mozilla {
/**
* Event messages
*/
typedef uint16_t EventMessageType;
enum EventMessage : EventMessageType
{
#define NS_EVENT_MESSAGE(aMessage) aMessage,
#define NS_EVENT_MESSAGE_FIRST_LAST(aMessage, aFirst, aLast) \
aMessage##First = aFirst, aMessage##Last = aLast,
#include "mozilla/EventMessageList.h"
#undef NS_EVENT_MESSAGE
#undef NS_EVENT_MESSAGE_FIRST_LAST
// For preventing bustage due to "," after the last item.
eEventMessage_MaxValue
};
const char* ToChar(EventMessage aEventMessage);
/**
* Event class IDs
*/
typedef uint8_t EventClassIDType;
enum EventClassID : EventClassIDType
{
// The event class name will be:
// eBasicEventClass for WidgetEvent
// eFooEventClass for WidgetFooEvent or InternalFooEvent
#define NS_ROOT_EVENT_CLASS(aPrefix, aName) eBasic##aName##Class
#define NS_EVENT_CLASS(aPrefix, aName) , e##aName##Class
#include "mozilla/EventClassList.h"
#undef NS_EVENT_CLASS
#undef NS_ROOT_EVENT_CLASS
};
const char* ToChar(EventClassID aEventClassID);
typedef uint16_t Modifiers;
#define NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName) \
KEY_NAME_INDEX_##aCPPName,
typedef uint16_t KeyNameIndexType;
enum KeyNameIndex : KeyNameIndexType
{
#include "mozilla/KeyNameList.h"
// If a DOM keyboard event is synthesized by script, this is used. Then,
// specified key name should be stored and use it as .key value.
KEY_NAME_INDEX_USE_STRING
};
#undef NS_DEFINE_KEYNAME
const nsCString ToString(KeyNameIndex aKeyNameIndex);
#define NS_DEFINE_PHYSICAL_KEY_CODE_NAME(aCPPName, aDOMCodeName) \
CODE_NAME_INDEX_##aCPPName,
typedef uint8_t CodeNameIndexType;
enum CodeNameIndex : CodeNameIndexType
{
#include "mozilla/PhysicalKeyCodeNameList.h"
// If a DOM keyboard event is synthesized by script, this is used. Then,
// specified code name should be stored and use it as .code value.
CODE_NAME_INDEX_USE_STRING
};
#undef NS_DEFINE_PHYSICAL_KEY_CODE_NAME
const nsCString ToString(CodeNameIndex aCodeNameIndex);
#define NS_DEFINE_COMMAND(aName, aCommandStr) , Command##aName
typedef int8_t CommandInt;
enum Command : CommandInt
{
CommandDoNothing
#include "mozilla/CommandList.h"
};
#undef NS_DEFINE_COMMAND
} // namespace mozilla
/**
* All header files should include this header instead of *Events.h.
*/
namespace mozilla {
#define NS_EVENT_CLASS(aPrefix, aName) class aPrefix##aName;
#define NS_ROOT_EVENT_CLASS(aPrefix, aName) NS_EVENT_CLASS(aPrefix, aName)
#include "mozilla/EventClassList.h"
#undef NS_EVENT_CLASS
#undef NS_ROOT_EVENT_CLASS
// BasicEvents.h
struct BaseEventFlags;
struct EventFlags;
class WidgetEventTime;
class NativeEventData;
// TextEvents.h
struct AlternativeCharCode;
struct ShortcutKeyCandidate;
typedef nsTArray<ShortcutKeyCandidate> ShortcutKeyCandidateArray;
typedef AutoTArray<ShortcutKeyCandidate, 10> AutoShortcutKeyCandidateArray;
// TextRange.h
typedef uint8_t RawTextRangeType;
enum class TextRangeType : RawTextRangeType;
struct TextRangeStyle;
struct TextRange;
class TextRangeArray;
// FontRange.h
struct FontRange;
} // namespace mozilla
#endif // mozilla_EventForwards_h__

457
widget/EventMessageList.h Normal file
View file

@ -0,0 +1,457 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
* This header file lists up all event messages.
* Before including this header file, you should define:
* NS_EVENT_MESSAGE(aMessage)
*
* Additionally, you can specify following macro for e*First and e*Last.
* NS_EVENT_MESSAGE_FIRST_LAST(aMessage, aFirst, aLast)
* This is optional, if you need only actual event messages, you don't need
* to define this macro.
*
* Naming rules of the event messages:
* 0. Starting with "e" prefix and use camelcase.
* 1. Basically, use same name as the DOM name which is fired at dispatching
* the event.
* 2. If the event message name becomes too generic, e.g., "eInvalid", that may
* conflict with another enum's item name, append something after the "e"
* prefix, e.g., "eFormInvalid".
*/
#ifndef NS_EVENT_MESSAGE_FIRST_LAST
#define UNDEF_NS_EVENT_MESSAGE_FIRST_LAST 1
#define NS_EVENT_MESSAGE_FIRST_LAST(aMessage, aFirst, aLast)
#endif
NS_EVENT_MESSAGE(eVoidEvent)
// This is a dummy event message for all event listener implementation in
// EventListenerManager.
NS_EVENT_MESSAGE(eAllEvents)
// Widget may be destroyed
NS_EVENT_MESSAGE(eWindowClose)
NS_EVENT_MESSAGE(eKeyPress)
NS_EVENT_MESSAGE(eKeyUp)
NS_EVENT_MESSAGE(eKeyDown)
// These messages are dispatched when PluginInstaceChild receives native
// keyboard events directly and it posts the information to the widget.
// These messages shouldn't be handled by content and non-reserved chrome
// event handlers.
NS_EVENT_MESSAGE(eKeyDownOnPlugin)
NS_EVENT_MESSAGE(eKeyUpOnPlugin)
NS_EVENT_MESSAGE(eBeforeKeyDown)
NS_EVENT_MESSAGE(eAfterKeyDown)
NS_EVENT_MESSAGE(eBeforeKeyUp)
NS_EVENT_MESSAGE(eAfterKeyUp)
// This message is sent after a content process handles a key event or accesskey
// to indicate that an potential accesskey was not found. The parent process may
// then respond by, for example, opening menus and processing other shortcuts.
// It inherits its properties from a keypress event.
NS_EVENT_MESSAGE(eAccessKeyNotFound)
NS_EVENT_MESSAGE(eResize)
NS_EVENT_MESSAGE(eScroll)
// Application installation
NS_EVENT_MESSAGE(eInstall)
NS_EVENT_MESSAGE(eAppInstalled)
// A plugin was clicked or otherwise focused. ePluginActivate should be
// used when the window is not active. ePluginFocus should be used when
// the window is active. In the latter case, the dispatcher of the event
// is expected to ensure that the plugin's widget is focused beforehand.
NS_EVENT_MESSAGE(ePluginActivate)
NS_EVENT_MESSAGE(ePluginFocus)
NS_EVENT_MESSAGE(eOffline)
NS_EVENT_MESSAGE(eOnline)
NS_EVENT_MESSAGE(eLanguageChange)
NS_EVENT_MESSAGE(eMouseMove)
NS_EVENT_MESSAGE(eMouseUp)
NS_EVENT_MESSAGE(eMouseDown)
NS_EVENT_MESSAGE(eMouseEnterIntoWidget)
NS_EVENT_MESSAGE(eMouseExitFromWidget)
NS_EVENT_MESSAGE(eMouseDoubleClick)
NS_EVENT_MESSAGE(eMouseClick)
// eMouseActivate is fired when the widget is activated by a click.
NS_EVENT_MESSAGE(eMouseActivate)
NS_EVENT_MESSAGE(eMouseOver)
NS_EVENT_MESSAGE(eMouseOut)
NS_EVENT_MESSAGE(eMouseHitTest)
NS_EVENT_MESSAGE(eMouseEnter)
NS_EVENT_MESSAGE(eMouseLeave)
NS_EVENT_MESSAGE(eMouseTouchDrag)
NS_EVENT_MESSAGE(eMouseLongTap)
NS_EVENT_MESSAGE_FIRST_LAST(eMouseEvent, eMouseMove, eMouseLongTap)
// Pointer spec events
NS_EVENT_MESSAGE(ePointerMove)
NS_EVENT_MESSAGE(ePointerUp)
NS_EVENT_MESSAGE(ePointerDown)
NS_EVENT_MESSAGE(ePointerOver)
NS_EVENT_MESSAGE(ePointerOut)
NS_EVENT_MESSAGE(ePointerEnter)
NS_EVENT_MESSAGE(ePointerLeave)
NS_EVENT_MESSAGE(ePointerCancel)
NS_EVENT_MESSAGE(ePointerGotCapture)
NS_EVENT_MESSAGE(ePointerLostCapture)
NS_EVENT_MESSAGE_FIRST_LAST(ePointerEvent, ePointerMove, ePointerLostCapture)
NS_EVENT_MESSAGE(eContextMenu)
NS_EVENT_MESSAGE(eLoad)
NS_EVENT_MESSAGE(eUnload)
NS_EVENT_MESSAGE(eHashChange)
NS_EVENT_MESSAGE(eImageAbort)
NS_EVENT_MESSAGE(eLoadError)
NS_EVENT_MESSAGE(eLoadEnd)
NS_EVENT_MESSAGE(ePopState)
NS_EVENT_MESSAGE(eStorage)
NS_EVENT_MESSAGE(eBeforeUnload)
NS_EVENT_MESSAGE(eReadyStateChange)
NS_EVENT_MESSAGE(eFormSubmit)
NS_EVENT_MESSAGE(eFormReset)
NS_EVENT_MESSAGE(eFormChange)
NS_EVENT_MESSAGE(eFormSelect)
NS_EVENT_MESSAGE(eFormInvalid)
//Need separate focus/blur notifications for non-native widgets
NS_EVENT_MESSAGE(eFocus)
NS_EVENT_MESSAGE(eBlur)
NS_EVENT_MESSAGE(eFocusIn)
NS_EVENT_MESSAGE(eFocusOut)
NS_EVENT_MESSAGE(eDragEnter)
NS_EVENT_MESSAGE(eDragOver)
NS_EVENT_MESSAGE(eDragExit)
NS_EVENT_MESSAGE(eDrag)
NS_EVENT_MESSAGE(eDragEnd)
NS_EVENT_MESSAGE(eDragStart)
NS_EVENT_MESSAGE(eDrop)
NS_EVENT_MESSAGE(eDragLeave)
NS_EVENT_MESSAGE_FIRST_LAST(eDragDropEvent, eDragEnter, eDragLeave)
// XUL specific events
NS_EVENT_MESSAGE(eXULPopupShowing)
NS_EVENT_MESSAGE(eXULPopupShown)
NS_EVENT_MESSAGE(eXULPopupPositioned)
NS_EVENT_MESSAGE(eXULPopupHiding)
NS_EVENT_MESSAGE(eXULPopupHidden)
NS_EVENT_MESSAGE(eXULBroadcast)
NS_EVENT_MESSAGE(eXULCommandUpdate)
// Legacy mouse scroll (wheel) events
NS_EVENT_MESSAGE(eLegacyMouseLineOrPageScroll)
NS_EVENT_MESSAGE(eLegacyMousePixelScroll)
NS_EVENT_MESSAGE(eScrollPortUnderflow)
NS_EVENT_MESSAGE(eScrollPortOverflow)
NS_EVENT_MESSAGE(eLegacySubtreeModified)
NS_EVENT_MESSAGE(eLegacyNodeInserted)
NS_EVENT_MESSAGE(eLegacyNodeRemoved)
NS_EVENT_MESSAGE(eLegacyNodeRemovedFromDocument)
NS_EVENT_MESSAGE(eLegacyNodeInsertedIntoDocument)
NS_EVENT_MESSAGE(eLegacyAttrModified)
NS_EVENT_MESSAGE(eLegacyCharacterDataModified)
NS_EVENT_MESSAGE_FIRST_LAST(eLegacyMutationEvent,
eLegacySubtreeModified, eLegacyCharacterDataModified)
NS_EVENT_MESSAGE(eUnidentifiedEvent)
// composition events
NS_EVENT_MESSAGE(eCompositionStart)
// eCompositionEnd is the message for DOM compositionend event.
// This event should NOT be dispatched from widget if eCompositionCommit
// is available.
NS_EVENT_MESSAGE(eCompositionEnd)
// eCompositionUpdate is the message for DOM compositionupdate event.
// This event should NOT be dispatched from widget since it will be dispatched
// by mozilla::TextComposition automatically if eCompositionChange event
// will change composition string.
NS_EVENT_MESSAGE(eCompositionUpdate)
// eCompositionChange is the message for representing a change of
// composition string. This should be dispatched from widget even if
// composition string isn't changed but the ranges are changed. This causes
// a DOM "text" event which is a non-standard DOM event.
NS_EVENT_MESSAGE(eCompositionChange)
// eCompositionCommitAsIs is the message for representing a commit of
// composition string. TextComposition will commit composition with the
// last data. TextComposition will dispatch this event to the DOM tree as
// eCompositionChange without clause information. After that,
// eCompositionEnd will be dispatched automatically.
// Its mData and mRanges should be empty and nullptr.
NS_EVENT_MESSAGE(eCompositionCommitAsIs)
// eCompositionCommit is the message for representing a commit of
// composition string with its mData value. TextComposition will dispatch this
// event to the DOM tree as eCompositionChange without clause information.
// After that, eCompositionEnd will be dispatched automatically.
// Its mRanges should be nullptr.
NS_EVENT_MESSAGE(eCompositionCommit)
// Following events are defined for deprecated DOM events which are using
// InternalUIEvent class.
// DOMActivate (mapped with the DOM event and used internally)
NS_EVENT_MESSAGE(eLegacyDOMActivate)
// DOMFocusIn (only mapped with the DOM event)
NS_EVENT_MESSAGE(eLegacyDOMFocusIn)
// DOMFocusOut (only mapped with the DOM event)
NS_EVENT_MESSAGE(eLegacyDOMFocusOut)
// pagetransition events
NS_EVENT_MESSAGE(ePageShow)
NS_EVENT_MESSAGE(ePageHide)
// SVG events
NS_EVENT_MESSAGE(eSVGLoad)
NS_EVENT_MESSAGE(eSVGUnload)
NS_EVENT_MESSAGE(eSVGResize)
NS_EVENT_MESSAGE(eSVGScroll)
// SVG Zoom events
NS_EVENT_MESSAGE(eSVGZoom)
// XUL command events
NS_EVENT_MESSAGE(eXULCommand)
// Cut, copy, paste events
NS_EVENT_MESSAGE(eCopy)
NS_EVENT_MESSAGE(eCut)
NS_EVENT_MESSAGE(ePaste)
// Query for the selected text information, it return the selection offset,
// selection length and selected text.
NS_EVENT_MESSAGE(eQuerySelectedText)
// Query for the text content of specified range, it returns actual lengh (if
// the specified range is too long) and the text of the specified range.
// Returns the entire text if requested length > actual length.
NS_EVENT_MESSAGE(eQueryTextContent)
// Query for the caret rect of nth insertion point. The offset of the result is
// relative position from the top level widget.
NS_EVENT_MESSAGE(eQueryCaretRect)
// Query for the bounding rect of a range of characters. This works on any
// valid character range given offset and length. Result is relative to top
// level widget coordinates
NS_EVENT_MESSAGE(eQueryTextRect)
// Query for the bounding rect array of a range of characters.
// Thiis similar event of eQueryTextRect.
NS_EVENT_MESSAGE(eQueryTextRectArray)
// Query for the bounding rect of the current focused frame. Result is relative
// to top level widget coordinates
NS_EVENT_MESSAGE(eQueryEditorRect)
// Query for the current state of the content. The particular members of
// mReply that are set for each query content event will be valid on success.
NS_EVENT_MESSAGE(eQueryContentState)
// Query for the selection in the form of a nsITransferable.
NS_EVENT_MESSAGE(eQuerySelectionAsTransferable)
// Query for character at a point. This returns the character offset, its
// rect and also tentative caret point if the point is clicked. The point is
// specified by Event::mRefPoint.
NS_EVENT_MESSAGE(eQueryCharacterAtPoint)
// Query if the DOM element under Event::mRefPoint belongs to our widget
// or not.
NS_EVENT_MESSAGE(eQueryDOMWidgetHittest)
// Video events
NS_EVENT_MESSAGE(eLoadStart)
NS_EVENT_MESSAGE(eProgress)
NS_EVENT_MESSAGE(eSuspend)
NS_EVENT_MESSAGE(eEmptied)
NS_EVENT_MESSAGE(eStalled)
NS_EVENT_MESSAGE(ePlay)
NS_EVENT_MESSAGE(ePause)
NS_EVENT_MESSAGE(eLoadedMetaData)
NS_EVENT_MESSAGE(eLoadedData)
NS_EVENT_MESSAGE(eWaiting)
NS_EVENT_MESSAGE(ePlaying)
NS_EVENT_MESSAGE(eCanPlay)
NS_EVENT_MESSAGE(eCanPlayThrough)
NS_EVENT_MESSAGE(eSeeking)
NS_EVENT_MESSAGE(eSeeked)
NS_EVENT_MESSAGE(eTimeUpdate)
NS_EVENT_MESSAGE(eEnded)
NS_EVENT_MESSAGE(eRateChange)
NS_EVENT_MESSAGE(eDurationChange)
NS_EVENT_MESSAGE(eVolumeChange)
// paint notification events
NS_EVENT_MESSAGE(eAfterPaint)
// Simple gesture events
NS_EVENT_MESSAGE(eSwipeGestureMayStart)
NS_EVENT_MESSAGE(eSwipeGestureStart)
NS_EVENT_MESSAGE(eSwipeGestureUpdate)
NS_EVENT_MESSAGE(eSwipeGestureEnd)
NS_EVENT_MESSAGE(eSwipeGesture)
NS_EVENT_MESSAGE(eMagnifyGestureStart)
NS_EVENT_MESSAGE(eMagnifyGestureUpdate)
NS_EVENT_MESSAGE(eMagnifyGesture)
NS_EVENT_MESSAGE(eRotateGestureStart)
NS_EVENT_MESSAGE(eRotateGestureUpdate)
NS_EVENT_MESSAGE(eRotateGesture)
NS_EVENT_MESSAGE(eTapGesture)
NS_EVENT_MESSAGE(ePressTapGesture)
NS_EVENT_MESSAGE(eEdgeUIStarted)
NS_EVENT_MESSAGE(eEdgeUICanceled)
NS_EVENT_MESSAGE(eEdgeUICompleted)
// These are used to send native events to plugins.
NS_EVENT_MESSAGE(ePluginInputEvent)
// Events to manipulate selection (WidgetSelectionEvent)
// Clear any previous selection and set the given range as the selection
NS_EVENT_MESSAGE(eSetSelection)
// Events of commands for the contents
NS_EVENT_MESSAGE(eContentCommandCut)
NS_EVENT_MESSAGE(eContentCommandCopy)
NS_EVENT_MESSAGE(eContentCommandPaste)
NS_EVENT_MESSAGE(eContentCommandDelete)
NS_EVENT_MESSAGE(eContentCommandUndo)
NS_EVENT_MESSAGE(eContentCommandRedo)
NS_EVENT_MESSAGE(eContentCommandPasteTransferable)
NS_EVENT_MESSAGE(eContentCommandLookUpDictionary)
// eContentCommandScroll scrolls the nearest scrollable element to the
// currently focused content or latest DOM selection. This would normally be
// the same element scrolled by keyboard scroll commands, except that this event
// will scroll an element scrollable in either direction. I.e., if the nearest
// scrollable ancestor element can only be scrolled vertically, and horizontal
// scrolling is requested using this event, no scrolling will occur.
NS_EVENT_MESSAGE(eContentCommandScroll)
// Event to gesture notification
NS_EVENT_MESSAGE(eGestureNotify)
NS_EVENT_MESSAGE(eScrolledAreaChanged)
// CSS Transition & Animation events:
NS_EVENT_MESSAGE(eTransitionStart)
NS_EVENT_MESSAGE(eTransitionRun)
NS_EVENT_MESSAGE(eTransitionEnd)
NS_EVENT_MESSAGE(eAnimationStart)
NS_EVENT_MESSAGE(eAnimationEnd)
NS_EVENT_MESSAGE(eAnimationIteration)
// Webkit-prefixed versions of Transition & Animation events, for web compat:
NS_EVENT_MESSAGE(eWebkitTransitionEnd)
NS_EVENT_MESSAGE(eWebkitAnimationStart)
NS_EVENT_MESSAGE(eWebkitAnimationEnd)
NS_EVENT_MESSAGE(eWebkitAnimationIteration)
NS_EVENT_MESSAGE(eSMILBeginEvent)
NS_EVENT_MESSAGE(eSMILEndEvent)
NS_EVENT_MESSAGE(eSMILRepeatEvent)
NS_EVENT_MESSAGE(eAudioProcess)
NS_EVENT_MESSAGE(eAudioComplete)
// script notification events
NS_EVENT_MESSAGE(eBeforeScriptExecute)
NS_EVENT_MESSAGE(eAfterScriptExecute)
NS_EVENT_MESSAGE(eBeforePrint)
NS_EVENT_MESSAGE(eAfterPrint)
NS_EVENT_MESSAGE(eMessage)
// Menu open event
NS_EVENT_MESSAGE(eOpen)
// Device motion and orientation
NS_EVENT_MESSAGE(eDeviceOrientation)
NS_EVENT_MESSAGE(eAbsoluteDeviceOrientation)
NS_EVENT_MESSAGE(eDeviceMotion)
NS_EVENT_MESSAGE(eDeviceProximity)
NS_EVENT_MESSAGE(eUserProximity)
NS_EVENT_MESSAGE(eDeviceLight)
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
NS_EVENT_MESSAGE(eOrientationChange)
#endif
// WebVR events
NS_EVENT_MESSAGE(eVRDisplayConnect)
NS_EVENT_MESSAGE(eVRDisplayDisconnect)
NS_EVENT_MESSAGE(eVRDisplayPresentChange)
NS_EVENT_MESSAGE(eShow)
// Fullscreen DOM API
NS_EVENT_MESSAGE(eFullscreenChange)
NS_EVENT_MESSAGE(eFullscreenError)
NS_EVENT_MESSAGE(eMozFullscreenChange)
NS_EVENT_MESSAGE(eMozFullscreenError)
NS_EVENT_MESSAGE(eTouchStart)
NS_EVENT_MESSAGE(eTouchMove)
NS_EVENT_MESSAGE(eTouchEnd)
NS_EVENT_MESSAGE(eTouchCancel)
// Pointerlock DOM API
NS_EVENT_MESSAGE(ePointerLockChange)
NS_EVENT_MESSAGE(ePointerLockError)
NS_EVENT_MESSAGE(eMozPointerLockChange)
NS_EVENT_MESSAGE(eMozPointerLockError)
// eWheel is the event message of DOM wheel event.
NS_EVENT_MESSAGE(eWheel)
// eWheelOperationStart may be dispatched when user starts to operate mouse
// wheel. This won't be fired on some platforms which don't have corresponding
// native event.
NS_EVENT_MESSAGE(eWheelOperationStart)
// eWheelOperationEnd may be dispatched when user ends or cancels operating
// mouse wheel. This won't be fired on some platforms which don't have
// corresponding native event.
NS_EVENT_MESSAGE(eWheelOperationEnd)
//System time is changed
NS_EVENT_MESSAGE(eTimeChange)
// Network packet events.
NS_EVENT_MESSAGE(eNetworkUpload)
NS_EVENT_MESSAGE(eNetworkDownload)
// MediaRecorder events.
NS_EVENT_MESSAGE(eMediaRecorderDataAvailable)
NS_EVENT_MESSAGE(eMediaRecorderWarning)
NS_EVENT_MESSAGE(eMediaRecorderStop)
// SpeakerManager events
NS_EVENT_MESSAGE(eSpeakerForcedChange)
#ifdef MOZ_GAMEPAD
// Gamepad input events
NS_EVENT_MESSAGE(eGamepadButtonDown)
NS_EVENT_MESSAGE(eGamepadButtonUp)
NS_EVENT_MESSAGE(eGamepadAxisMove)
NS_EVENT_MESSAGE(eGamepadConnected)
NS_EVENT_MESSAGE(eGamepadDisconnected)
NS_EVENT_MESSAGE_FIRST_LAST(eGamepadEvent,
eGamepadButtonDown, eGamepadDisconnected)
#endif
// input and beforeinput events.
NS_EVENT_MESSAGE(eEditorInput)
// selection events
NS_EVENT_MESSAGE(eSelectStart)
NS_EVENT_MESSAGE(eSelectionChange)
// Details element events.
NS_EVENT_MESSAGE(eToggle)
#ifdef UNDEF_NS_EVENT_MESSAGE_FIRST_LAST
#undef UNDEF_NS_EVENT_MESSAGE_FIRST_LAST
#undef NS_EVENT_MESSAGE_FIRST_LAST
#endif

27
widget/FontRange.h Normal file
View file

@ -0,0 +1,27 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_FontRange_h_
#define mozilla_FontRange_h_
namespace mozilla {
struct FontRange
{
FontRange()
: mStartOffset(0)
, mFontSize(0)
{
}
int32_t mStartOffset;
nsString mFontName;
gfxFloat mFontSize; // in device pixels
};
} // namespace mozilla
#endif // mozilla_FontRange_h_

314
widget/GfxDriverInfo.cpp Normal file
View file

@ -0,0 +1,314 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "GfxDriverInfo.h"
#include "nsIGfxInfo.h"
#include "nsTArray.h"
using namespace mozilla::widget;
int32_t GfxDriverInfo::allFeatures = 0;
uint64_t GfxDriverInfo::allDriverVersions = ~(uint64_t(0));
GfxDeviceFamily* const GfxDriverInfo::allDevices = nullptr;
GfxDeviceFamily* GfxDriverInfo::mDeviceFamilies[DeviceFamilyMax];
nsAString* GfxDriverInfo::mDeviceVendors[DeviceVendorMax];
GfxDriverInfo::GfxDriverInfo()
: mOperatingSystem(OperatingSystem::Unknown),
mOperatingSystemVersion(0),
mAdapterVendor(GfxDriverInfo::GetDeviceVendor(VendorAll)),
mDevices(allDevices),
mDeleteDevices(false),
mFeature(allFeatures),
mFeatureStatus(nsIGfxInfo::FEATURE_STATUS_OK),
mComparisonOp(DRIVER_COMPARISON_IGNORED),
mDriverVersion(0),
mDriverVersionMax(0),
mSuggestedVersion(nullptr),
mRuleId(nullptr),
mGpu2(false)
{}
GfxDriverInfo::GfxDriverInfo(OperatingSystem os, nsAString& vendor,
GfxDeviceFamily* devices,
int32_t feature, int32_t featureStatus,
VersionComparisonOp op,
uint64_t driverVersion,
const char *ruleId,
const char *suggestedVersion /* = nullptr */,
bool ownDevices /* = false */,
bool gpu2 /* = false */)
: mOperatingSystem(os),
mOperatingSystemVersion(0),
mAdapterVendor(vendor),
mDevices(devices),
mDeleteDevices(ownDevices),
mFeature(feature),
mFeatureStatus(featureStatus),
mComparisonOp(op),
mDriverVersion(driverVersion),
mDriverVersionMax(0),
mSuggestedVersion(suggestedVersion),
mRuleId(ruleId),
mGpu2(gpu2)
{}
GfxDriverInfo::GfxDriverInfo(const GfxDriverInfo& aOrig)
: mOperatingSystem(aOrig.mOperatingSystem),
mOperatingSystemVersion(aOrig.mOperatingSystemVersion),
mAdapterVendor(aOrig.mAdapterVendor),
mFeature(aOrig.mFeature),
mFeatureStatus(aOrig.mFeatureStatus),
mComparisonOp(aOrig.mComparisonOp),
mDriverVersion(aOrig.mDriverVersion),
mDriverVersionMax(aOrig.mDriverVersionMax),
mSuggestedVersion(aOrig.mSuggestedVersion),
mRuleId(aOrig.mRuleId),
mGpu2(aOrig.mGpu2)
{
// If we're managing the lifetime of the device family, we have to make a
// copy of the original's device family.
if (aOrig.mDeleteDevices && aOrig.mDevices) {
mDevices = new GfxDeviceFamily;
*mDevices = *aOrig.mDevices;
} else {
mDevices = aOrig.mDevices;
}
mDeleteDevices = aOrig.mDeleteDevices;
}
GfxDriverInfo::~GfxDriverInfo()
{
if (mDeleteDevices)
delete mDevices;
}
// Macros for appending a device to the DeviceFamily.
#define APPEND_DEVICE(device) APPEND_DEVICE2(#device)
#define APPEND_DEVICE2(device) deviceFamily->AppendElement(NS_LITERAL_STRING(device))
const GfxDeviceFamily* GfxDriverInfo::GetDeviceFamily(DeviceFamily id)
{
// The code here is too sensitive to fall through to the default case if the
// code is invalid.
NS_ASSERTION(id >= 0 && id < DeviceFamilyMax, "DeviceFamily id is out of range");
// If it already exists, we must have processed it once, so return it now.
if (mDeviceFamilies[id])
return mDeviceFamilies[id];
mDeviceFamilies[id] = new GfxDeviceFamily;
GfxDeviceFamily* deviceFamily = mDeviceFamilies[id];
switch (id) {
case IntelGMA500:
APPEND_DEVICE(0x8108); /* IntelGMA500_1 */
APPEND_DEVICE(0x8109); /* IntelGMA500_2 */
break;
case IntelGMA900:
APPEND_DEVICE(0x2582); /* IntelGMA900_1 */
APPEND_DEVICE(0x2782); /* IntelGMA900_2 */
APPEND_DEVICE(0x2592); /* IntelGMA900_3 */
APPEND_DEVICE(0x2792); /* IntelGMA900_4 */
break;
case IntelGMA950:
APPEND_DEVICE(0x2772); /* Intel945G_1 */
APPEND_DEVICE(0x2776); /* Intel945G_2 */
APPEND_DEVICE(0x27a2); /* Intel945_1 */
APPEND_DEVICE(0x27a6); /* Intel945_2 */
APPEND_DEVICE(0x27ae); /* Intel945_3 */
break;
case IntelGMA3150:
APPEND_DEVICE(0xa001); /* IntelGMA3150_Nettop_1 */
APPEND_DEVICE(0xa002); /* IntelGMA3150_Nettop_2 */
APPEND_DEVICE(0xa011); /* IntelGMA3150_Netbook_1 */
APPEND_DEVICE(0xa012); /* IntelGMA3150_Netbook_2 */
break;
case IntelGMAX3000:
APPEND_DEVICE(0x2972); /* Intel946GZ_1 */
APPEND_DEVICE(0x2973); /* Intel946GZ_2 */
APPEND_DEVICE(0x2982); /* IntelG35_1 */
APPEND_DEVICE(0x2983); /* IntelG35_2 */
APPEND_DEVICE(0x2992); /* IntelQ965_1 */
APPEND_DEVICE(0x2993); /* IntelQ965_2 */
APPEND_DEVICE(0x29a2); /* IntelG965_1 */
APPEND_DEVICE(0x29a3); /* IntelG965_2 */
APPEND_DEVICE(0x29b2); /* IntelQ35_1 */
APPEND_DEVICE(0x29b3); /* IntelQ35_2 */
APPEND_DEVICE(0x29c2); /* IntelG33_1 */
APPEND_DEVICE(0x29c3); /* IntelG33_2 */
APPEND_DEVICE(0x29d2); /* IntelQ33_1 */
APPEND_DEVICE(0x29d3); /* IntelQ33_2 */
APPEND_DEVICE(0x2a02); /* IntelGL960_1 */
APPEND_DEVICE(0x2a03); /* IntelGL960_2 */
APPEND_DEVICE(0x2a12); /* IntelGM965_1 */
APPEND_DEVICE(0x2a13); /* IntelGM965_2 */
break;
case IntelGMAX4500HD:
APPEND_DEVICE(0x2a42); /* IntelGMA4500MHD_1 */
APPEND_DEVICE(0x2a43); /* IntelGMA4500MHD_2 */
APPEND_DEVICE(0x2e42); /* IntelB43_1 */
APPEND_DEVICE(0x2e43); /* IntelB43_2 */
APPEND_DEVICE(0x2e92); /* IntelB43_3 */
APPEND_DEVICE(0x2e93); /* IntelB43_4 */
APPEND_DEVICE(0x2e32); /* IntelG41_1 */
APPEND_DEVICE(0x2e33); /* IntelG41_2 */
APPEND_DEVICE(0x2e22); /* IntelG45_1 */
APPEND_DEVICE(0x2e23); /* IntelG45_2 */
APPEND_DEVICE(0x2e12); /* IntelQ45_1 */
APPEND_DEVICE(0x2e13); /* IntelQ45_2 */
break;
case IntelHDGraphicsToSandyBridge:
APPEND_DEVICE(0x0042); /* IntelHDGraphics */
APPEND_DEVICE(0x0046); /* IntelMobileHDGraphics */
APPEND_DEVICE(0x0102); /* IntelSandyBridge_1 */
APPEND_DEVICE(0x0106); /* IntelSandyBridge_2 */
APPEND_DEVICE(0x0112); /* IntelSandyBridge_3 */
APPEND_DEVICE(0x0116); /* IntelSandyBridge_4 */
APPEND_DEVICE(0x0122); /* IntelSandyBridge_5 */
APPEND_DEVICE(0x0126); /* IntelSandyBridge_6 */
APPEND_DEVICE(0x010a); /* IntelSandyBridge_7 */
break;
case IntelHD3000:
APPEND_DEVICE(0x0126);
break;
case IntelMobileHDGraphics:
APPEND_DEVICE(0x0046); /* IntelMobileHDGraphics */
break;
case NvidiaBlockD3D9Layers:
// Glitches whilst scrolling (see bugs 612007, 644787, 645872)
APPEND_DEVICE(0x00f3); /* NV43 [GeForce 6200 (TM)] */
APPEND_DEVICE(0x0146); /* NV43 [Geforce Go 6600TE/6200TE (TM)] */
APPEND_DEVICE(0x014f); /* NV43 [GeForce 6200 (TM)] */
APPEND_DEVICE(0x0161); /* NV44 [GeForce 6200 TurboCache (TM)] */
APPEND_DEVICE(0x0162); /* NV44 [GeForce 6200SE TurboCache (TM)] */
APPEND_DEVICE(0x0163); /* NV44 [GeForce 6200 LE (TM)] */
APPEND_DEVICE(0x0164); /* NV44 [GeForce Go 6200 (TM)] */
APPEND_DEVICE(0x0167); /* NV43 [GeForce Go 6200/6400 (TM)] */
APPEND_DEVICE(0x0168); /* NV43 [GeForce Go 6200/6400 (TM)] */
APPEND_DEVICE(0x0169); /* NV44 [GeForce 6250 (TM)] */
APPEND_DEVICE(0x0222); /* NV44 [GeForce 6200 A-LE (TM)] */
APPEND_DEVICE(0x0240); /* C51PV [GeForce 6150 (TM)] */
APPEND_DEVICE(0x0241); /* C51 [GeForce 6150 LE (TM)] */
APPEND_DEVICE(0x0244); /* C51 [Geforce Go 6150 (TM)] */
APPEND_DEVICE(0x0245); /* C51 [Quadro NVS 210S/GeForce 6150LE (TM)] */
APPEND_DEVICE(0x0247); /* C51 [GeForce Go 6100 (TM)] */
APPEND_DEVICE(0x03d0); /* C61 [GeForce 6150SE nForce 430 (TM)] */
APPEND_DEVICE(0x03d1); /* C61 [GeForce 6100 nForce 405 (TM)] */
APPEND_DEVICE(0x03d2); /* C61 [GeForce 6100 nForce 400 (TM)] */
APPEND_DEVICE(0x03d5); /* C61 [GeForce 6100 nForce 420 (TM)] */
break;
case RadeonX1000:
// This list is from the ATIRadeonX1000.kext Info.plist
APPEND_DEVICE(0x7187);
APPEND_DEVICE(0x7210);
APPEND_DEVICE(0x71de);
APPEND_DEVICE(0x7146);
APPEND_DEVICE(0x7142);
APPEND_DEVICE(0x7109);
APPEND_DEVICE(0x71c5);
APPEND_DEVICE(0x71c0);
APPEND_DEVICE(0x7240);
APPEND_DEVICE(0x7249);
APPEND_DEVICE(0x7291);
break;
case Geforce7300GT:
APPEND_DEVICE(0x0393);
break;
case Nvidia310M:
APPEND_DEVICE(0x0A70);
break;
case Nvidia8800GTS:
APPEND_DEVICE(0x0193);
break;
case Bug1137716:
APPEND_DEVICE(0x0a29);
APPEND_DEVICE(0x0a2b);
APPEND_DEVICE(0x0a2d);
APPEND_DEVICE(0x0a35);
APPEND_DEVICE(0x0a6c);
APPEND_DEVICE(0x0a70);
APPEND_DEVICE(0x0a72);
APPEND_DEVICE(0x0a7a);
APPEND_DEVICE(0x0caf);
APPEND_DEVICE(0x0dd2);
APPEND_DEVICE(0x0dd3);
// GF180M ids
APPEND_DEVICE(0x0de3);
APPEND_DEVICE(0x0de8);
APPEND_DEVICE(0x0de9);
APPEND_DEVICE(0x0dea);
APPEND_DEVICE(0x0deb);
APPEND_DEVICE(0x0dec);
APPEND_DEVICE(0x0ded);
APPEND_DEVICE(0x0dee);
APPEND_DEVICE(0x0def);
APPEND_DEVICE(0x0df0);
APPEND_DEVICE(0x0df1);
APPEND_DEVICE(0x0df2);
APPEND_DEVICE(0x0df3);
APPEND_DEVICE(0x0df4);
APPEND_DEVICE(0x0df5);
APPEND_DEVICE(0x0df6);
APPEND_DEVICE(0x0df7);
APPEND_DEVICE(0x1050);
APPEND_DEVICE(0x1051);
APPEND_DEVICE(0x1052);
APPEND_DEVICE(0x1054);
APPEND_DEVICE(0x1055);
break;
case Bug1116812:
APPEND_DEVICE(0x2e32);
APPEND_DEVICE(0x2a02);
break;
case Bug1155608:
APPEND_DEVICE(0x2e22); /* IntelG45_1 */
break;
case Bug1207665:
APPEND_DEVICE(0xa001); /* Intel Media Accelerator 3150 */
APPEND_DEVICE(0xa002);
APPEND_DEVICE(0xa011);
APPEND_DEVICE(0xa012);
break;
// This should never happen, but we get a warning if we don't handle this.
case DeviceFamilyMax:
NS_WARNING("Invalid DeviceFamily id");
break;
}
return deviceFamily;
}
// Macro for assigning a device vendor id to a string.
#define DECLARE_VENDOR_ID(name, deviceId) \
case name: \
mDeviceVendors[id]->AssignLiteral(deviceId); \
break;
const nsAString& GfxDriverInfo::GetDeviceVendor(DeviceVendor id)
{
NS_ASSERTION(id >= 0 && id < DeviceVendorMax, "DeviceVendor id is out of range");
if (mDeviceVendors[id])
return *mDeviceVendors[id];
mDeviceVendors[id] = new nsString();
switch (id) {
DECLARE_VENDOR_ID(VendorAll, "");
DECLARE_VENDOR_ID(VendorIntel, "0x8086");
DECLARE_VENDOR_ID(VendorNVIDIA, "0x10de");
DECLARE_VENDOR_ID(VendorAMD, "0x1022");
DECLARE_VENDOR_ID(VendorATI, "0x1002");
DECLARE_VENDOR_ID(VendorMicrosoft, "0x1414");
// Suppress a warning.
DECLARE_VENDOR_ID(DeviceVendorMax, "");
}
return *mDeviceVendors[id];
}

300
widget/GfxDriverInfo.h Normal file
View file

@ -0,0 +1,300 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef __mozilla_widget_GfxDriverInfo_h__
#define __mozilla_widget_GfxDriverInfo_h__
#include "nsString.h"
// Macros for adding a blocklist item to the static list.
#define APPEND_TO_DRIVER_BLOCKLIST(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, ruleId, suggestedVersion) \
mDriverInfo->AppendElement(GfxDriverInfo(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, ruleId, suggestedVersion))
#define APPEND_TO_DRIVER_BLOCKLIST2(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, ruleId) \
mDriverInfo->AppendElement(GfxDriverInfo(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, ruleId))
#define APPEND_TO_DRIVER_BLOCKLIST_RANGE(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, driverVersionMax, ruleId, suggestedVersion) \
do { \
MOZ_ASSERT(driverComparator == DRIVER_BETWEEN_EXCLUSIVE || \
driverComparator == DRIVER_BETWEEN_INCLUSIVE || \
driverComparator == DRIVER_BETWEEN_INCLUSIVE_START); \
GfxDriverInfo info(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, ruleId, suggestedVersion); \
info.mDriverVersionMax = driverVersionMax; \
mDriverInfo->AppendElement(info); \
} while (false)
#define APPEND_TO_DRIVER_BLOCKLIST_RANGE_GPU2(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, driverVersionMax, ruleId, suggestedVersion) \
do { \
MOZ_ASSERT(driverComparator == DRIVER_BETWEEN_EXCLUSIVE || \
driverComparator == DRIVER_BETWEEN_INCLUSIVE || \
driverComparator == DRIVER_BETWEEN_INCLUSIVE_START); \
GfxDriverInfo info(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, ruleId, suggestedVersion, false, true); \
info.mDriverVersionMax = driverVersionMax; \
mDriverInfo->AppendElement(info); \
} while (false)
namespace mozilla {
namespace widget {
enum class OperatingSystem {
Unknown,
Windows,
WindowsXP,
WindowsServer2003,
WindowsVista,
Windows7,
Windows8,
Windows8_1,
Windows10,
Linux,
OSX,
OSX10_5,
OSX10_6,
OSX10_7,
OSX10_8,
OSX10_9,
OSX10_10,
OSX10_11,
OSX10_12,
Android,
Ios
};
enum VersionComparisonOp {
DRIVER_LESS_THAN, // driver < version
DRIVER_BUILD_ID_LESS_THAN, // driver build id < version
DRIVER_LESS_THAN_OR_EQUAL, // driver <= version
DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL, // driver build id <= version
DRIVER_GREATER_THAN, // driver > version
DRIVER_GREATER_THAN_OR_EQUAL, // driver >= version
DRIVER_EQUAL, // driver == version
DRIVER_NOT_EQUAL, // driver != version
DRIVER_BETWEEN_EXCLUSIVE, // driver > version && driver < versionMax
DRIVER_BETWEEN_INCLUSIVE, // driver >= version && driver <= versionMax
DRIVER_BETWEEN_INCLUSIVE_START, // driver >= version && driver < versionMax
DRIVER_COMPARISON_IGNORED
};
enum DeviceFamily {
IntelGMA500,
IntelGMA900,
IntelGMA950,
IntelGMA3150,
IntelGMAX3000,
IntelGMAX4500HD,
IntelHDGraphicsToSandyBridge,
IntelHD3000,
IntelMobileHDGraphics,
NvidiaBlockD3D9Layers,
RadeonX1000,
Geforce7300GT,
Nvidia310M,
Nvidia8800GTS,
Bug1137716,
Bug1116812,
Bug1155608,
Bug1207665,
DeviceFamilyMax
};
enum DeviceVendor {
VendorAll,
VendorIntel,
VendorNVIDIA,
VendorAMD,
VendorATI,
VendorMicrosoft,
DeviceVendorMax
};
/* Array of devices to match, or an empty array for all devices */
typedef nsTArray<nsString> GfxDeviceFamily;
struct GfxDriverInfo
{
// If |ownDevices| is true, you are transferring ownership of the devices
// array, and it will be deleted when this GfxDriverInfo is destroyed.
GfxDriverInfo(OperatingSystem os, nsAString& vendor, GfxDeviceFamily* devices,
int32_t feature, int32_t featureStatus, VersionComparisonOp op,
uint64_t driverVersion, const char *ruleId,
const char *suggestedVersion = nullptr,
bool ownDevices = false, bool gpu2 = false);
GfxDriverInfo();
GfxDriverInfo(const GfxDriverInfo&);
~GfxDriverInfo();
OperatingSystem mOperatingSystem;
uint32_t mOperatingSystemVersion;
nsString mAdapterVendor;
static GfxDeviceFamily* const allDevices;
GfxDeviceFamily* mDevices;
// Whether the mDevices array should be deleted when this structure is
// deallocated. False by default.
bool mDeleteDevices;
/* A feature from nsIGfxInfo, or all features */
int32_t mFeature;
static int32_t allFeatures;
/* A feature status from nsIGfxInfo */
int32_t mFeatureStatus;
VersionComparisonOp mComparisonOp;
/* versions are assumed to be A.B.C.D packed as 0xAAAABBBBCCCCDDDD */
uint64_t mDriverVersion;
uint64_t mDriverVersionMax;
static uint64_t allDriverVersions;
const char *mSuggestedVersion;
nsCString mRuleId;
static const GfxDeviceFamily* GetDeviceFamily(DeviceFamily id);
static GfxDeviceFamily* mDeviceFamilies[DeviceFamilyMax];
static const nsAString& GetDeviceVendor(DeviceVendor id);
static nsAString* mDeviceVendors[DeviceVendorMax];
nsString mModel, mHardware, mProduct, mManufacturer;
bool mGpu2;
};
#define GFX_DRIVER_VERSION(a,b,c,d) \
((uint64_t(a)<<48) | (uint64_t(b)<<32) | (uint64_t(c)<<16) | uint64_t(d))
inline uint64_t
V(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
{
// We make sure every driver number is padded by 0s, this will allow us the
// easiest 'compare as if decimals' approach. See ParseDriverVersion for a
// more extensive explanation of this approach.
while (b > 0 && b < 1000) {
b *= 10;
}
while (c > 0 && c < 1000) {
c *= 10;
}
while (d > 0 && d < 1000) {
d *= 10;
}
return GFX_DRIVER_VERSION(a, b, c, d);
}
// All destination string storage needs to have at least 5 bytes available.
inline bool SplitDriverVersion(const char *aSource, char *aAStr, char *aBStr, char *aCStr, char *aDStr)
{
// sscanf doesn't do what we want here to we parse this manually.
int len = strlen(aSource);
// This "4" is hardcoded in a few places, including once as a 3.
char *dest[4] = { aAStr, aBStr, aCStr, aDStr };
unsigned destIdx = 0;
unsigned destPos = 0;
for (int i = 0; i < len; i++) {
if (destIdx >= 4) {
// Invalid format found. Ensure we don't access dest beyond bounds.
return false;
}
if (aSource[i] == '.') {
MOZ_ASSERT (destIdx < 4 && destPos <= 4);
dest[destIdx++][destPos] = 0;
destPos = 0;
continue;
}
if (destPos > 3) {
// Ignore more than 4 chars. Ensure we never access dest[destIdx]
// beyond its bounds.
continue;
}
MOZ_ASSERT (destIdx < 4 && destPos < 4);
dest[destIdx][destPos++] = aSource[i];
}
// Take care of the trailing period
if (destIdx >= 4) {
return false;
}
// Add last terminator.
MOZ_ASSERT (destIdx < 4 && destPos <= 4);
dest[destIdx][destPos] = 0;
if (destIdx != 3) {
return false;
}
return true;
}
// This allows us to pad driver version 'substrings' with 0s, this
// effectively allows us to treat the version numbers as 'decimals'. This is
// a little strange but this method seems to do the right thing for all
// different vendor's driver strings. i.e. .98 will become 9800, which is
// larger than .978 which would become 9780.
inline void PadDriverDecimal(char *aString)
{
for (int i = 0; i < 4; i++) {
if (!aString[i]) {
for (int c = i; c < 4; c++) {
aString[c] = '0';
}
break;
}
}
aString[4] = 0;
}
inline bool
ParseDriverVersion(const nsAString& aVersion, uint64_t *aNumericVersion)
{
*aNumericVersion = 0;
#if defined(XP_WIN)
int a, b, c, d;
char aStr[8], bStr[8], cStr[8], dStr[8];
/* honestly, why do I even bother */
if (!SplitDriverVersion(NS_LossyConvertUTF16toASCII(aVersion).get(), aStr, bStr, cStr, dStr))
return false;
PadDriverDecimal(bStr);
PadDriverDecimal(cStr);
PadDriverDecimal(dStr);
a = atoi(aStr);
b = atoi(bStr);
c = atoi(cStr);
d = atoi(dStr);
if (a < 0 || a > 0xffff) return false;
if (b < 0 || b > 0xffff) return false;
if (c < 0 || c > 0xffff) return false;
if (d < 0 || d > 0xffff) return false;
*aNumericVersion = GFX_DRIVER_VERSION(a, b, c, d);
MOZ_ASSERT(*aNumericVersion != GfxDriverInfo::allDriverVersions);
return true;
#elif defined(ANDROID)
// Can't use aVersion.ToInteger() because that's not compiled into our code
// unless we have XPCOM_GLUE_AVOID_NSPR disabled.
*aNumericVersion = atoi(NS_LossyConvertUTF16toASCII(aVersion).get());
MOZ_ASSERT(*aNumericVersion != GfxDriverInfo::allDriverVersions);
return true;
#else
return false;
#endif
}
} // namespace widget
} // namespace mozilla
#endif /*__mozilla_widget_GfxDriverInfo_h__ */

1438
widget/GfxInfoBase.cpp Normal file

File diff suppressed because it is too large Load diff

136
widget/GfxInfoBase.h Normal file
View file

@ -0,0 +1,136 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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/. */
#ifndef __mozilla_widget_GfxInfoBase_h__
#define __mozilla_widget_GfxInfoBase_h__
#include "GfxDriverInfo.h"
#include "GfxInfoCollector.h"
#include "gfxFeature.h"
#include "gfxTelemetry.h"
#include "js/Value.h"
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "mozilla/Mutex.h"
#include "nsCOMPtr.h"
#include "nsIGfxInfo.h"
#include "nsIGfxInfoDebug.h"
#include "nsIObserver.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsWeakReference.h"
namespace mozilla {
namespace widget {
class GfxInfoBase : public nsIGfxInfo,
public nsIObserver,
public nsSupportsWeakReference
#ifdef DEBUG
, public nsIGfxInfoDebug
#endif
{
public:
GfxInfoBase();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER
// We only declare a subset of the nsIGfxInfo interface. It's up to derived
// classes to implement the rest of the interface.
// Derived classes need to use
// using GfxInfoBase::GetFeatureStatus;
// using GfxInfoBase::GetFeatureSuggestedDriverVersion;
// using GfxInfoBase::GetWebGLParameter;
// to import the relevant methods into their namespace.
NS_IMETHOD GetFeatureStatus(int32_t aFeature, nsACString& aFailureId, int32_t *_retval) override;
NS_IMETHOD GetFeatureSuggestedDriverVersion(int32_t aFeature, nsAString & _retval) override;
NS_IMETHOD GetWebGLParameter(const nsAString & aParam, nsAString & _retval) override;
NS_IMETHOD GetMonitors(JSContext* cx, JS::MutableHandleValue _retval) override;
NS_IMETHOD GetFailures(uint32_t *failureCount, int32_t** indices, char ***failures) override;
NS_IMETHOD_(void) LogFailure(const nsACString &failure) override;
NS_IMETHOD GetInfo(JSContext*, JS::MutableHandle<JS::Value>) override;
NS_IMETHOD GetFeatures(JSContext*, JS::MutableHandle<JS::Value>) override;
NS_IMETHOD GetFeatureLog(JSContext*, JS::MutableHandle<JS::Value>) override;
NS_IMETHOD GetActiveCrashGuards(JSContext*, JS::MutableHandle<JS::Value>) override;
NS_IMETHOD GetContentBackend(nsAString & aContentBackend) override;
// Initialization function. If you override this, you must call this class's
// version of Init first.
// We need Init to be called separately from the constructor so we can
// register as an observer after all derived classes have been constructed
// and we know we have a non-zero refcount.
// Ideally, Init() would be void-return, but the rules of
// NS_GENERIC_FACTORY_CONSTRUCTOR_INIT require it be nsresult return.
virtual nsresult Init();
// only useful on X11
NS_IMETHOD_(void) GetData() override { }
static void AddCollector(GfxInfoCollectorBase* collector);
static void RemoveCollector(GfxInfoCollectorBase* collector);
static nsTArray<GfxDriverInfo>* mDriverInfo;
static bool mDriverInfoObserverInitialized;
virtual nsString Model() { return EmptyString(); }
virtual nsString Hardware() { return EmptyString(); }
virtual nsString Product() { return EmptyString(); }
virtual nsString Manufacturer() { return EmptyString(); }
virtual uint32_t OperatingSystemVersion() { return 0; }
// Convenience to get the application version
static const nsCString& GetApplicationVersion();
virtual nsresult FindMonitors(JSContext* cx, JS::HandleObject array) {
return NS_ERROR_NOT_IMPLEMENTED;
}
protected:
virtual ~GfxInfoBase();
virtual nsresult GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
nsAString& aSuggestedDriverVersion,
const nsTArray<GfxDriverInfo>& aDriverInfo,
nsACString& aFailureId,
OperatingSystem* aOS = nullptr);
// Gets the driver info table. Used by GfxInfoBase to check for general cases
// (while subclasses check for more specific ones).
virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo() = 0;
virtual void DescribeFeatures(JSContext* aCx, JS::Handle<JSObject*> obj);
bool InitFeatureObject(
JSContext* aCx,
JS::Handle<JSObject*> aContainer,
const char* aName,
int32_t aFeature,
Maybe<mozilla::gfx::FeatureStatus> aKnownStatus,
JS::MutableHandle<JSObject*> aOutObj);
private:
virtual int32_t FindBlocklistedDeviceInList(const nsTArray<GfxDriverInfo>& aDriverInfo,
nsAString& aSuggestedVersion,
int32_t aFeature,
nsACString &aFailureId,
OperatingSystem os);
void EvaluateDownloadedBlacklist(nsTArray<GfxDriverInfo>& aDriverInfo);
bool BuildFeatureStateLog(JSContext* aCx, const gfx::FeatureState& aFeature,
JS::MutableHandle<JS::Value> aOut);
Mutex mMutex;
};
} // namespace widget
} // namespace mozilla
#endif /* __mozilla_widget_GfxInfoBase_h__ */

View file

@ -0,0 +1,54 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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 "GfxInfoCollector.h"
#include "jsapi.h"
#include "nsString.h"
using namespace mozilla;
using namespace widget;
void
InfoObject::DefineProperty(const char *name, int value)
{
if (!mOk)
return;
mOk = JS_DefineProperty(mCx, mObj, name, value, JSPROP_ENUMERATE);
}
void
InfoObject::DefineProperty(const char *name, nsAString &value)
{
if (!mOk)
return;
const nsString &flat = PromiseFlatString(value);
JS::Rooted<JSString*> string(mCx, JS_NewUCStringCopyN(mCx, static_cast<const char16_t*>(flat.get()),
flat.Length()));
if (!string)
mOk = false;
if (!mOk)
return;
mOk = JS_DefineProperty(mCx, mObj, name, string, JSPROP_ENUMERATE);
}
void
InfoObject::DefineProperty(const char *name, const char *value)
{
nsAutoString string = NS_ConvertASCIItoUTF16(value);
DefineProperty(name, string);
}
InfoObject::InfoObject(JSContext *aCx) : mCx(aCx), mObj(aCx), mOk(true)
{
mObj = JS_NewPlainObject(aCx);
if (!mObj)
mOk = false;
}

94
widget/GfxInfoCollector.h Normal file
View file

@ -0,0 +1,94 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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/. */
#ifndef __mozilla_widget_GfxInfoCollector_h__
#define __mozilla_widget_GfxInfoCollector_h__
#include "mozilla/Attributes.h"
#include "nsStringFwd.h"
#include "js/RootingAPI.h"
namespace mozilla {
namespace widget {
/* this is handy wrapper around JSAPI to make it more pleasant to use.
* We collect the JSAPI errors and so that callers don't need to */
class MOZ_STACK_CLASS InfoObject
{
friend class GfxInfoBase;
public:
void DefineProperty(const char *name, int value);
void DefineProperty(const char *name, nsAString &value);
void DefineProperty(const char *name, const char *value);
private:
// We need to ensure that this object lives on the stack so that GC sees it properly
explicit InfoObject(JSContext *aCx);
InfoObject(InfoObject&);
JSContext *mCx;
JS::Rooted<JSObject*> mObj;
bool mOk;
};
/*
Here's an example usage:
class Foo {
Foo::Foo() : mInfoCollector(this, &Foo::GetAweseomeness) {}
void GetAwesomeness(InfoObject &obj) {
obj.DefineProperty("awesome", mAwesome);
}
int mAwesome;
GfxInfoCollector<Foo> mInfoCollector;
}
This will define a property on the object
returned from calling getInfo() on a
GfxInfo object. e.g.
gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
info = gfxInfo.getInfo();
if (info.awesome)
alert(info.awesome);
*/
class GfxInfoCollectorBase
{
public:
GfxInfoCollectorBase();
virtual void GetInfo(InfoObject &obj) = 0;
virtual ~GfxInfoCollectorBase();
};
template<class T>
class GfxInfoCollector : public GfxInfoCollectorBase
{
public:
GfxInfoCollector(T* aPointer, void (T::*aFunc)(InfoObject &obj)) : mPointer(aPointer), mFunc(aFunc) {
}
virtual void GetInfo(InfoObject &obj) override {
(mPointer->*mFunc)(obj);
}
protected:
T* mPointer;
void (T::*mFunc)(InfoObject &obj);
};
} // namespace widget
} // namespace mozilla
#endif

69
widget/GfxInfoWebGL.cpp Normal file
View file

@ -0,0 +1,69 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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 "GfxInfoWebGL.h"
#include "nsServiceManagerUtils.h"
#include "GLDefs.h"
#include "nsIDOMWebGLRenderingContext.h"
#include "nsICanvasRenderingContextInternal.h"
using namespace mozilla::widget;
nsresult
GfxInfoWebGL::GetWebGLParameter(const nsAString& aParam, nsAString& aResult)
{
GLenum param;
if (aParam.EqualsLiteral("vendor")) param = LOCAL_GL_VENDOR;
else if (aParam.EqualsLiteral("renderer")) param = LOCAL_GL_RENDERER;
else if (aParam.EqualsLiteral("version")) param = LOCAL_GL_VERSION;
else if (aParam.EqualsLiteral("shading_language_version")) param = LOCAL_GL_SHADING_LANGUAGE_VERSION;
else if (aParam.EqualsLiteral("extensions")) param = LOCAL_GL_EXTENSIONS;
else if (aParam.EqualsLiteral("full-renderer")) param = 0;
else return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIDOMWebGLRenderingContext> webgl =
do_CreateInstance("@mozilla.org/content/canvas-rendering-context;1?id=webgl");
if (!webgl)
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<nsICanvasRenderingContextInternal> webglInternal =
do_QueryInterface(webgl);
if (!webglInternal)
return NS_ERROR_NOT_AVAILABLE;
nsresult rv = webglInternal->SetDimensions(16, 16);
NS_ENSURE_SUCCESS(rv, rv);
if (param)
return webgl->MozGetUnderlyingParamString(param, aResult);
// this is the "full renderer" string, which is vendor + renderer + version
nsAutoString str;
rv = webgl->MozGetUnderlyingParamString(LOCAL_GL_VENDOR, str);
NS_ENSURE_SUCCESS(rv, rv);
aResult.Append(str);
aResult.AppendLiteral(" -- ");
rv = webgl->MozGetUnderlyingParamString(LOCAL_GL_RENDERER, str);
NS_ENSURE_SUCCESS(rv, rv);
aResult.Append(str);
aResult.AppendLiteral(" -- ");
rv = webgl->MozGetUnderlyingParamString(LOCAL_GL_VERSION, str);
NS_ENSURE_SUCCESS(rv, rv);
aResult.Append(str);
return NS_OK;
}

27
widget/GfxInfoWebGL.h Normal file
View file

@ -0,0 +1,27 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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/. */
#ifndef __mozilla_widget_GfxInfoWebGL_h__
#define __mozilla_widget_GfxInfoWebGL_h__
#include "nsString.h"
namespace mozilla {
namespace widget {
class GfxInfoWebGL {
public:
static nsresult GetWebGLParameter(const nsAString& aParam, nsAString& aResult);
protected:
GfxInfoWebGL() { }
};
} // namespace widget
} // namespace mozilla
#endif

564
widget/GfxInfoX11.cpp Normal file
View file

@ -0,0 +1,564 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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 <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/utsname.h>
#include "nsCRTGlue.h"
#include "prenv.h"
#include "GfxInfoX11.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#include "nsICrashReporter.h"
#endif
namespace mozilla {
namespace widget {
#ifdef DEBUG
NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
#endif
// these global variables will be set when firing the glxtest process
int glxtest_pipe = 0;
pid_t glxtest_pid = 0;
nsresult
GfxInfo::Init()
{
mGLMajorVersion = 0;
mMajorVersion = 0;
mMinorVersion = 0;
mRevisionVersion = 0;
mIsMesa = false;
mIsNVIDIA = false;
mIsFGLRX = false;
mIsNouveau = false;
mIsIntel = false;
mIsOldSwrast = false;
mIsLlvmpipe = false;
mHasTextureFromPixmap = false;
return GfxInfoBase::Init();
}
void
GfxInfo::GetData()
{
// to understand this function, see bug 639842. We retrieve the OpenGL driver information in a
// separate process to protect against bad drivers.
// if glxtest_pipe == 0, that means that we already read the information
if (!glxtest_pipe)
return;
enum { buf_size = 1024 };
char buf[buf_size];
ssize_t bytesread = read(glxtest_pipe,
&buf,
buf_size-1); // -1 because we'll append a zero
close(glxtest_pipe);
glxtest_pipe = 0;
// bytesread < 0 would mean that the above read() call failed.
// This should never happen. If it did, the outcome would be to blacklist anyway.
if (bytesread < 0)
bytesread = 0;
// let buf be a zero-terminated string
buf[bytesread] = 0;
// Wait for the glxtest process to finish. This serves 2 purposes:
// * avoid having a zombie glxtest process laying around
// * get the glxtest process status info.
int glxtest_status = 0;
bool wait_for_glxtest_process = true;
bool waiting_for_glxtest_process_failed = false;
int waitpid_errno = 0;
while(wait_for_glxtest_process) {
wait_for_glxtest_process = false;
if (waitpid(glxtest_pid, &glxtest_status, 0) == -1) {
waitpid_errno = errno;
if (waitpid_errno == EINTR) {
wait_for_glxtest_process = true;
} else {
// Bug 718629
// ECHILD happens when the glxtest process got reaped got reaped after a PR_CreateProcess
// as per bug 227246. This shouldn't matter, as we still seem to get the data
// from the pipe, and if we didn't, the outcome would be to blacklist anyway.
waiting_for_glxtest_process_failed = (waitpid_errno != ECHILD);
}
}
}
bool exited_with_error_code = !waiting_for_glxtest_process_failed &&
WIFEXITED(glxtest_status) &&
WEXITSTATUS(glxtest_status) != EXIT_SUCCESS;
bool received_signal = !waiting_for_glxtest_process_failed &&
WIFSIGNALED(glxtest_status);
bool error = waiting_for_glxtest_process_failed || exited_with_error_code || received_signal;
nsCString textureFromPixmap;
nsCString *stringToFill = nullptr;
char *bufptr = buf;
if (!error) {
while(true) {
char *line = NS_strtok("\n", &bufptr);
if (!line)
break;
if (stringToFill) {
stringToFill->Assign(line);
stringToFill = nullptr;
}
else if(!strcmp(line, "VENDOR"))
stringToFill = &mVendor;
else if(!strcmp(line, "RENDERER"))
stringToFill = &mRenderer;
else if(!strcmp(line, "VERSION"))
stringToFill = &mVersion;
else if(!strcmp(line, "TFP"))
stringToFill = &textureFromPixmap;
}
}
if (!strcmp(textureFromPixmap.get(), "TRUE"))
mHasTextureFromPixmap = true;
// only useful for Linux kernel version check for FGLRX driver.
// assumes X client == X server, which is sad.
struct utsname unameobj;
if (uname(&unameobj) >= 0)
{
mOS.Assign(unameobj.sysname);
mOSRelease.Assign(unameobj.release);
}
const char *spoofedVendor = PR_GetEnv("MOZ_GFX_SPOOF_GL_VENDOR");
if (spoofedVendor)
mVendor.Assign(spoofedVendor);
const char *spoofedRenderer = PR_GetEnv("MOZ_GFX_SPOOF_GL_RENDERER");
if (spoofedRenderer)
mRenderer.Assign(spoofedRenderer);
const char *spoofedVersion = PR_GetEnv("MOZ_GFX_SPOOF_GL_VERSION");
if (spoofedVersion)
mVersion.Assign(spoofedVersion);
const char *spoofedOS = PR_GetEnv("MOZ_GFX_SPOOF_OS");
if (spoofedOS)
mOS.Assign(spoofedOS);
const char *spoofedOSRelease = PR_GetEnv("MOZ_GFX_SPOOF_OS_RELEASE");
if (spoofedOSRelease)
mOSRelease.Assign(spoofedOSRelease);
if (error ||
mVendor.IsEmpty() ||
mRenderer.IsEmpty() ||
mVersion.IsEmpty() ||
mOS.IsEmpty() ||
mOSRelease.IsEmpty())
{
mAdapterDescription.AppendLiteral("GLXtest process failed");
if (waiting_for_glxtest_process_failed)
mAdapterDescription.AppendPrintf(" (waitpid failed with errno=%d for pid %d)", waitpid_errno, glxtest_pid);
if (exited_with_error_code)
mAdapterDescription.AppendPrintf(" (exited with status %d)", WEXITSTATUS(glxtest_status));
if (received_signal)
mAdapterDescription.AppendPrintf(" (received signal %d)", WTERMSIG(glxtest_status));
if (bytesread) {
mAdapterDescription.AppendLiteral(": ");
mAdapterDescription.Append(nsDependentCString(buf));
mAdapterDescription.Append('\n');
}
#ifdef MOZ_CRASHREPORTER
CrashReporter::AppendAppNotesToCrashReport(mAdapterDescription);
#endif
return;
}
mAdapterDescription.Append(mVendor);
mAdapterDescription.AppendLiteral(" -- ");
mAdapterDescription.Append(mRenderer);
nsAutoCString note;
note.AppendLiteral("OpenGL: ");
note.Append(mAdapterDescription);
note.AppendLiteral(" -- ");
note.Append(mVersion);
if (mHasTextureFromPixmap)
note.AppendLiteral(" -- texture_from_pixmap");
note.Append('\n');
#ifdef MOZ_CRASHREPORTER
CrashReporter::AppendAppNotesToCrashReport(note);
#endif
// determine the major OpenGL version. That's the first integer in the version string.
mGLMajorVersion = strtol(mVersion.get(), 0, 10);
// determine driver type (vendor) and where in the version string
// the actual driver version numbers should be expected to be found (whereToReadVersionNumbers)
const char *whereToReadVersionNumbers = nullptr;
const char *Mesa_in_version_string = strstr(mVersion.get(), "Mesa");
if (Mesa_in_version_string) {
mIsMesa = true;
// with Mesa, the version string contains "Mesa major.minor" and that's all the version information we get:
// there is no actual driver version info.
whereToReadVersionNumbers = Mesa_in_version_string + strlen("Mesa");
if (strcasestr(mVendor.get(), "nouveau"))
mIsNouveau = true;
if (strcasestr(mRenderer.get(), "intel")) // yes, intel is in the renderer string
mIsIntel = true;
if (strcasestr(mRenderer.get(), "llvmpipe"))
mIsLlvmpipe = true;
if (strcasestr(mRenderer.get(), "software rasterizer"))
mIsOldSwrast = true;
} else if (strstr(mVendor.get(), "NVIDIA Corporation")) {
mIsNVIDIA = true;
// with the NVIDIA driver, the version string contains "NVIDIA major.minor"
// note that here the vendor and version strings behave differently, that's why we don't put this above
// alongside Mesa_in_version_string.
const char *NVIDIA_in_version_string = strstr(mVersion.get(), "NVIDIA");
if (NVIDIA_in_version_string)
whereToReadVersionNumbers = NVIDIA_in_version_string + strlen("NVIDIA");
} else if (strstr(mVendor.get(), "ATI Technologies Inc")) {
mIsFGLRX = true;
// with the FGLRX driver, the version string only gives a OpenGL version :/ so let's return that.
// that can at least give a rough idea of how old the driver is.
whereToReadVersionNumbers = mVersion.get();
}
// read major.minor version numbers of the driver (not to be confused with the OpenGL version)
if (whereToReadVersionNumbers) {
// copy into writable buffer, for tokenization
strncpy(buf, whereToReadVersionNumbers, buf_size);
bufptr = buf;
// now try to read major.minor version numbers. In case of failure, gracefully exit: these numbers have
// been initialized as 0 anyways
char *token = NS_strtok(".", &bufptr);
if (token) {
mMajorVersion = strtol(token, 0, 10);
token = NS_strtok(".", &bufptr);
if (token) {
mMinorVersion = strtol(token, 0, 10);
token = NS_strtok(".", &bufptr);
if (token)
mRevisionVersion = strtol(token, 0, 10);
}
}
}
}
static inline uint64_t version(uint32_t major, uint32_t minor, uint32_t revision = 0)
{
return (uint64_t(major) << 32) + (uint64_t(minor) << 16) + uint64_t(revision);
}
const nsTArray<GfxDriverInfo>&
GfxInfo::GetGfxDriverInfo()
{
// Nothing here yet.
//if (!mDriverInfo->Length()) {
//
//}
return *mDriverInfo;
}
nsresult
GfxInfo::GetFeatureStatusImpl(int32_t aFeature,
int32_t *aStatus,
nsAString & aSuggestedDriverVersion,
const nsTArray<GfxDriverInfo>& aDriverInfo,
nsACString& aFailureId,
OperatingSystem* aOS /* = nullptr */)
{
GetData();
NS_ENSURE_ARG_POINTER(aStatus);
*aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
aSuggestedDriverVersion.SetIsVoid(true);
OperatingSystem os = OperatingSystem::Linux;
if (aOS)
*aOS = os;
if (mGLMajorVersion == 1) {
// We're on OpenGL 1. In most cases that indicates really old hardware.
// We better block them, rather than rely on them to fail gracefully, because they don't!
// see bug 696636
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
aFailureId = "FEATURE_FAILURE_OPENGL_1";
return NS_OK;
}
// Don't evaluate any special cases if we're checking the downloaded blocklist.
if (!aDriverInfo.Length()) {
// Blacklist software GL implementations from using layers acceleration.
// On the test infrastructure, we'll force-enable layers acceleration.
if (aFeature == nsIGfxInfo::FEATURE_OPENGL_LAYERS &&
(mIsLlvmpipe || mIsOldSwrast) &&
!PR_GetEnv("MOZ_LAYERS_ALLOW_SOFTWARE_GL"))
{
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
aFailureId = "FEATURE_FAILURE_SOFTWARE_GL";
return NS_OK;
}
// Only check features relevant to Linux.
if (aFeature == nsIGfxInfo::FEATURE_OPENGL_LAYERS ||
aFeature == nsIGfxInfo::FEATURE_WEBGL_OPENGL ||
aFeature == nsIGfxInfo::FEATURE_WEBGL_MSAA) {
// whitelist the linux test slaves' current configuration.
// this is necessary as they're still using the slightly outdated 190.42 driver.
// this isn't a huge risk, as at least this is the exact setting in which we do continuous testing,
// and this only affects GeForce 9400 cards on linux on this precise driver version, which is very few users.
// We do the same thing on Windows XP, see in widget/windows/GfxInfo.cpp
if (mIsNVIDIA &&
!strcmp(mRenderer.get(), "GeForce 9400/PCI/SSE2") &&
!strcmp(mVersion.get(), "3.2.0 NVIDIA 190.42"))
{
*aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
return NS_OK;
}
if (mIsMesa) {
if (mIsNouveau && version(mMajorVersion, mMinorVersion) < version(8,0)) {
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
aFailureId = "FEATURE_FAILURE_MESA_1";
aSuggestedDriverVersion.AssignLiteral("Mesa 8.0");
}
else if (version(mMajorVersion, mMinorVersion, mRevisionVersion) < version(7,10,3)) {
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
aFailureId = "FEATURE_FAILURE_MESA_2";
aSuggestedDriverVersion.AssignLiteral("Mesa 7.10.3");
}
else if (mIsOldSwrast) {
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
aFailureId = "FEATURE_FAILURE_SW_RAST";
}
else if (mIsLlvmpipe && version(mMajorVersion, mMinorVersion) < version(9, 1)) {
// bug 791905, Mesa bug 57733, fixed in Mesa 9.1 according to
// https://bugs.freedesktop.org/show_bug.cgi?id=57733#c3
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
aFailureId = "FEATURE_FAILURE_MESA_3";
}
else if (aFeature == nsIGfxInfo::FEATURE_WEBGL_MSAA)
{
if (mIsIntel && version(mMajorVersion, mMinorVersion) < version(8,1)) {
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
aFailureId = "FEATURE_FAILURE_MESA_4";
aSuggestedDriverVersion.AssignLiteral("Mesa 8.1");
}
}
} else if (mIsNVIDIA) {
if (version(mMajorVersion, mMinorVersion, mRevisionVersion) < version(257,21)) {
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
aFailureId = "FEATURE_FAILURE_OLD_NV";
aSuggestedDriverVersion.AssignLiteral("NVIDIA 257.21");
}
} else if (mIsFGLRX) {
// FGLRX does not report a driver version number, so we have the OpenGL version instead.
// by requiring OpenGL 3, we effectively require recent drivers.
if (version(mMajorVersion, mMinorVersion, mRevisionVersion) < version(3, 0)) {
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
aFailureId = "FEATURE_FAILURE_OLD_FGLRX";
aSuggestedDriverVersion.AssignLiteral("<Something recent>");
}
// Bug 724640: FGLRX + Linux 2.6.32 is a crashy combo
bool unknownOS = mOS.IsEmpty() || mOSRelease.IsEmpty();
bool badOS = mOS.Find("Linux", true) != -1 &&
mOSRelease.Find("2.6.32") != -1;
if (unknownOS || badOS) {
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
aFailureId = "FEATURE_FAILURE_OLD_OS";
}
} else {
// like on windows, let's block unknown vendors. Think of virtual machines.
// Also, this case is hit whenever the GLXtest probe failed to get driver info or crashed.
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
}
}
}
return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
}
NS_IMETHODIMP
GfxInfo::GetD2DEnabled(bool *aEnabled)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetDWriteEnabled(bool *aEnabled)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetDWriteVersion(nsAString & aDwriteVersion)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetCleartypeParameters(nsAString & aCleartypeParams)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription)
{
GetData();
AppendASCIItoUTF16(mAdapterDescription, aAdapterDescription);
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM)
{
aAdapterRAM.Truncate();
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver)
{
aAdapterDriver.Truncate();
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion)
{
GetData();
CopyASCIItoUTF16(mVersion, aAdapterDriverVersion);
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate)
{
aAdapterDriverDate.Truncate();
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterVendorID(nsAString & aAdapterVendorID)
{
GetData();
CopyUTF8toUTF16(mVendor, aAdapterVendorID);
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterVendorID2(nsAString & aAdapterVendorID)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDeviceID(nsAString & aAdapterDeviceID)
{
GetData();
CopyUTF8toUTF16(mRenderer, aAdapterDeviceID);
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDeviceID2(nsAString & aAdapterDeviceID)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterSubsysID(nsAString & aAdapterSubsysID)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterSubsysID2(nsAString & aAdapterSubsysID)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active)
{
return NS_ERROR_FAILURE;
}
#ifdef DEBUG
// Implement nsIGfxInfoDebug
// We don't support spoofing anything on Linux
NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString & aVendorID)
{
CopyUTF16toUTF8(aVendorID, mVendor);
return NS_OK;
}
NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString & aDeviceID)
{
CopyUTF16toUTF8(aDeviceID, mRenderer);
return NS_OK;
}
NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString & aDriverVersion)
{
CopyUTF16toUTF8(aDriverVersion, mVersion);
return NS_OK;
}
NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion)
{
// We don't support OS versioning on Linux. There's just "Linux".
return NS_OK;
}
#endif
} // end namespace widget
} // end namespace mozilla

84
widget/GfxInfoX11.h Normal file
View file

@ -0,0 +1,84 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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/. */
#ifndef __GfxInfoX11_h__
#define __GfxInfoX11_h__
#include "GfxInfoBase.h"
namespace mozilla {
namespace widget {
class GfxInfo final : public GfxInfoBase
{
public:
// We only declare the subset of nsIGfxInfo that we actually implement. The
// rest is brought forward from GfxInfoBase.
NS_IMETHOD GetD2DEnabled(bool *aD2DEnabled) override;
NS_IMETHOD GetDWriteEnabled(bool *aDWriteEnabled) override;
NS_IMETHOD GetDWriteVersion(nsAString & aDwriteVersion) override;
NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams) override;
NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription) override;
NS_IMETHOD GetAdapterDriver(nsAString & aAdapterDriver) override;
NS_IMETHOD GetAdapterVendorID(nsAString & aAdapterVendorID) override;
NS_IMETHOD GetAdapterDeviceID(nsAString & aAdapterDeviceID) override;
NS_IMETHOD GetAdapterSubsysID(nsAString & aAdapterSubsysID) override;
NS_IMETHOD GetAdapterRAM(nsAString & aAdapterRAM) override;
NS_IMETHOD GetAdapterDriverVersion(nsAString & aAdapterDriverVersion) override;
NS_IMETHOD GetAdapterDriverDate(nsAString & aAdapterDriverDate) override;
NS_IMETHOD GetAdapterDescription2(nsAString & aAdapterDescription) override;
NS_IMETHOD GetAdapterDriver2(nsAString & aAdapterDriver) override;
NS_IMETHOD GetAdapterVendorID2(nsAString & aAdapterVendorID) override;
NS_IMETHOD GetAdapterDeviceID2(nsAString & aAdapterDeviceID) override;
NS_IMETHOD GetAdapterSubsysID2(nsAString & aAdapterSubsysID) override;
NS_IMETHOD GetAdapterRAM2(nsAString & aAdapterRAM) override;
NS_IMETHOD GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion) override;
NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate) override;
NS_IMETHOD GetIsGPU2Active(bool *aIsGPU2Active) override;
using GfxInfoBase::GetFeatureStatus;
using GfxInfoBase::GetFeatureSuggestedDriverVersion;
using GfxInfoBase::GetWebGLParameter;
virtual nsresult Init() override;
NS_IMETHOD_(void) GetData() override;
#ifdef DEBUG
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIGFXINFODEBUG
#endif
protected:
~GfxInfo() {}
virtual nsresult GetFeatureStatusImpl(int32_t aFeature,
int32_t *aStatus,
nsAString & aSuggestedDriverVersion,
const nsTArray<GfxDriverInfo>& aDriverInfo,
nsACString& aFailureId,
OperatingSystem* aOS = nullptr) override;
virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo() override;
private:
nsCString mVendor;
nsCString mRenderer;
nsCString mVersion;
nsCString mAdapterDescription;
nsCString mOS;
nsCString mOSRelease;
bool mIsMesa, mIsNVIDIA, mIsFGLRX, mIsNouveau, mIsIntel, mIsOldSwrast, mIsLlvmpipe;
bool mHasTextureFromPixmap;
int mGLMajorVersion, mMajorVersion, mMinorVersion, mRevisionVersion;
void AddCrashReportAnnotations();
};
} // namespace widget
} // namespace mozilla
#endif /* __GfxInfoX11_h__ */

882
widget/IMEData.h Normal file
View file

@ -0,0 +1,882 @@
/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef mozilla_widget_IMEData_h_
#define mozilla_widget_IMEData_h_
#include "nsPoint.h"
#include "nsRect.h"
#include "nsStringGlue.h"
class nsIWidget;
namespace mozilla {
class WritingMode;
} // namespace mozilla
/**
* Preference for receiving IME updates
*
* If mWantUpdates is not NOTIFY_NOTHING, nsTextStateManager will observe text
* change and/or selection change and call nsIWidget::NotifyIME() with
* NOTIFY_IME_OF_SELECTION_CHANGE and/or NOTIFY_IME_OF_TEXT_CHANGE.
* Please note that the text change observing cost is very expensive especially
* on an HTML editor has focus.
* If the IME implementation on a particular platform doesn't care about
* NOTIFY_IME_OF_SELECTION_CHANGE and/or NOTIFY_IME_OF_TEXT_CHANGE,
* they should set mWantUpdates to NOTIFY_NOTHING to avoid the cost.
* If the IME implementation needs notifications even while our process is
* deactive, it should also set NOTIFY_DURING_DEACTIVE.
*/
struct nsIMEUpdatePreference final
{
typedef uint8_t Notifications;
enum : Notifications
{
NOTIFY_NOTHING = 0,
NOTIFY_TEXT_CHANGE = 1 << 1,
NOTIFY_POSITION_CHANGE = 1 << 2,
// NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR is used when mouse button is pressed
// or released on a character in the focused editor. The notification is
// notified to IME as a mouse event. If it's consumed by IME, NotifyIME()
// returns NS_SUCCESS_EVENT_CONSUMED. Otherwise, it returns NS_OK if it's
// handled without any error.
NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR = 1 << 3,
// NOTE: NOTIFY_DURING_DEACTIVE isn't supported in environments where two
// or more compositions are possible. E.g., Mac and Linux (GTK).
NOTIFY_DURING_DEACTIVE = 1 << 7
};
nsIMEUpdatePreference()
: mWantUpdates(NOTIFY_NOTHING)
{
}
explicit nsIMEUpdatePreference(Notifications aWantUpdates)
: mWantUpdates(aWantUpdates)
{
}
nsIMEUpdatePreference operator|(const nsIMEUpdatePreference& aOther) const
{
return nsIMEUpdatePreference(aOther.mWantUpdates | mWantUpdates);
}
bool WantTextChange() const
{
return !!(mWantUpdates & NOTIFY_TEXT_CHANGE);
}
bool WantPositionChanged() const
{
return !!(mWantUpdates & NOTIFY_POSITION_CHANGE);
}
bool WantChanges() const
{
return WantTextChange();
}
bool WantMouseButtonEventOnChar() const
{
return !!(mWantUpdates & NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR);
}
bool WantDuringDeactive() const
{
return !!(mWantUpdates & NOTIFY_DURING_DEACTIVE);
}
Notifications mWantUpdates;
};
/**
* Contains IMEStatus plus information about the current
* input context that the IME can use as hints if desired.
*/
namespace mozilla {
namespace widget {
struct IMEState final
{
/**
* IME enabled states, the mEnabled value of
* SetInputContext()/GetInputContext() should be one value of following
* values.
*
* WARNING: If you change these values, you also need to edit:
* nsIDOMWindowUtils.idl
* nsContentUtils::GetWidgetStatusFromIMEStatus
*/
enum Enabled
{
/**
* 'Disabled' means the user cannot use IME. So, the IME open state should
* be 'closed' during 'disabled'.
*/
DISABLED,
/**
* 'Enabled' means the user can use IME.
*/
ENABLED,
/**
* 'Password' state is a special case for the password editors.
* E.g., on mac, the password editors should disable the non-Roman
* keyboard layouts at getting focus. Thus, the password editor may have
* special rules on some platforms.
*/
PASSWORD,
/**
* This state is used when a plugin is focused.
* When a plug-in is focused content, we should send native events
* directly. Because we don't process some native events, but they may
* be needed by the plug-in.
*/
PLUGIN,
/**
* 'Unknown' is useful when you cache this enum. So, this shouldn't be
* used with nsIWidget::SetInputContext().
*/
UNKNOWN
};
Enabled mEnabled;
/**
* IME open states the mOpen value of SetInputContext() should be one value of
* OPEN, CLOSE or DONT_CHANGE_OPEN_STATE. GetInputContext() should return
* OPEN, CLOSE or OPEN_STATE_NOT_SUPPORTED.
*/
enum Open
{
/**
* 'Unsupported' means the platform cannot return actual IME open state.
* This value is used only by GetInputContext().
*/
OPEN_STATE_NOT_SUPPORTED,
/**
* 'Don't change' means the widget shouldn't change IME open state when
* SetInputContext() is called.
*/
DONT_CHANGE_OPEN_STATE = OPEN_STATE_NOT_SUPPORTED,
/**
* 'Open' means that IME should compose in its primary language (or latest
* input mode except direct ASCII character input mode). Even if IME is
* opened by this value, users should be able to close IME by theirselves.
* Web contents can specify this value by |ime-mode: active;|.
*/
OPEN,
/**
* 'Closed' means that IME shouldn't handle key events (or should handle
* as ASCII character inputs on mobile device). Even if IME is closed by
* this value, users should be able to open IME by theirselves.
* Web contents can specify this value by |ime-mode: inactive;|.
*/
CLOSED
};
Open mOpen;
IMEState()
: mEnabled(ENABLED)
, mOpen(DONT_CHANGE_OPEN_STATE)
{
}
explicit IMEState(Enabled aEnabled, Open aOpen = DONT_CHANGE_OPEN_STATE)
: mEnabled(aEnabled)
, mOpen(aOpen)
{
}
// Returns true if the user can input characters.
// This means that a plain text editor, an HTML editor, a password editor or
// a plain text editor whose ime-mode is "disabled".
bool IsEditable() const
{
return mEnabled == ENABLED || mEnabled == PASSWORD;
}
// Returns true if the user might be able to input characters.
// This means that a plain text editor, an HTML editor, a password editor,
// a plain text editor whose ime-mode is "disabled" or a windowless plugin
// has focus.
bool MaybeEditable() const
{
return IsEditable() || mEnabled == PLUGIN;
}
};
// NS_ONLY_ONE_NATIVE_IME_CONTEXT is a special value of native IME context.
// If there can be only one IME composition in a process, this can be used.
#define NS_ONLY_ONE_NATIVE_IME_CONTEXT \
(reinterpret_cast<void*>(static_cast<intptr_t>(-1)))
struct NativeIMEContext final
{
// Pointer to native IME context. Typically this is the result of
// nsIWidget::GetNativeData(NS_RAW_NATIVE_IME_CONTEXT) in the parent process.
// See also NS_ONLY_ONE_NATIVE_IME_CONTEXT.
uintptr_t mRawNativeIMEContext;
// Process ID of the origin of mNativeIMEContext.
uint64_t mOriginProcessID;
NativeIMEContext()
{
Init(nullptr);
}
explicit NativeIMEContext(nsIWidget* aWidget)
{
Init(aWidget);
}
bool IsValid() const
{
return mRawNativeIMEContext &&
mOriginProcessID != static_cast<uintptr_t>(-1);
}
void Init(nsIWidget* aWidget);
void InitWithRawNativeIMEContext(const void* aRawNativeIMEContext)
{
InitWithRawNativeIMEContext(const_cast<void*>(aRawNativeIMEContext));
}
void InitWithRawNativeIMEContext(void* aRawNativeIMEContext);
bool operator==(const NativeIMEContext& aOther) const
{
return mRawNativeIMEContext == aOther.mRawNativeIMEContext &&
mOriginProcessID == aOther.mOriginProcessID;
}
bool operator!=(const NativeIMEContext& aOther) const
{
return !(*this == aOther);
}
};
struct InputContext final
{
InputContext()
: mOrigin(XRE_IsParentProcess() ? ORIGIN_MAIN : ORIGIN_CONTENT)
, mMayBeIMEUnaware(false)
{
}
bool IsPasswordEditor() const
{
return mHTMLInputType.LowerCaseEqualsLiteral("password");
}
IMEState mIMEState;
/* The type of the input if the input is a html input field */
nsString mHTMLInputType;
/* The type of the inputmode */
nsString mHTMLInputInputmode;
/* A hint for the action that is performed when the input is submitted */
nsString mActionHint;
/**
* mOrigin indicates whether this focus event refers to main or remote
* content.
*/
enum Origin
{
// Adjusting focus of content on the main process
ORIGIN_MAIN,
// Adjusting focus of content in a remote process
ORIGIN_CONTENT
};
Origin mOrigin;
/* True if the webapp may be unaware of IME events such as input event or
* composiion events. This enables a key-events-only mode on Android for
* compatibility with webapps relying on key listeners. */
bool mMayBeIMEUnaware;
bool IsOriginMainProcess() const
{
return mOrigin == ORIGIN_MAIN;
}
bool IsOriginContentProcess() const
{
return mOrigin == ORIGIN_CONTENT;
}
bool IsOriginCurrentProcess() const
{
if (XRE_IsParentProcess()) {
return IsOriginMainProcess();
}
return IsOriginContentProcess();
}
};
struct InputContextAction final
{
/**
* mCause indicates what action causes calling nsIWidget::SetInputContext().
* It must be one of following values.
*/
enum Cause
{
// The cause is unknown but originated from content. Focus might have been
// changed by content script.
CAUSE_UNKNOWN,
// The cause is unknown but originated from chrome. Focus might have been
// changed by chrome script.
CAUSE_UNKNOWN_CHROME,
// The cause is user's keyboard operation.
CAUSE_KEY,
// The cause is user's mouse operation.
CAUSE_MOUSE,
// The cause is user's touch operation (implies mouse)
CAUSE_TOUCH
};
Cause mCause;
/**
* mFocusChange indicates what happened for focus.
*/
enum FocusChange
{
FOCUS_NOT_CHANGED,
// A content got focus.
GOT_FOCUS,
// Focused content lost focus.
LOST_FOCUS,
// Menu got pseudo focus that means focused content isn't changed but
// keyboard events will be handled by menu.
MENU_GOT_PSEUDO_FOCUS,
// Menu lost pseudo focus that means focused content will handle keyboard
// events.
MENU_LOST_PSEUDO_FOCUS
};
FocusChange mFocusChange;
bool ContentGotFocusByTrustedCause() const
{
return (mFocusChange == GOT_FOCUS &&
mCause != CAUSE_UNKNOWN);
}
bool UserMightRequestOpenVKB() const
{
return (mFocusChange == FOCUS_NOT_CHANGED &&
(mCause == CAUSE_MOUSE || mCause == CAUSE_TOUCH));
}
static bool IsUserAction(Cause aCause)
{
switch (aCause) {
case CAUSE_KEY:
case CAUSE_MOUSE:
case CAUSE_TOUCH:
return true;
default:
return false;
}
}
InputContextAction()
: mCause(CAUSE_UNKNOWN)
, mFocusChange(FOCUS_NOT_CHANGED)
{
}
explicit InputContextAction(Cause aCause,
FocusChange aFocusChange = FOCUS_NOT_CHANGED)
: mCause(aCause)
, mFocusChange(aFocusChange)
{
}
};
// IMEMessage is shared by IMEStateManager and TextComposition.
// Update values in GeckoEditable.java if you make changes here.
// XXX Negative values are used in Android...
typedef int8_t IMEMessageType;
enum IMEMessage : IMEMessageType
{
// This is used by IMENotification internally. This means that the instance
// hasn't been initialized yet.
NOTIFY_IME_OF_NOTHING,
// An editable content is getting focus
NOTIFY_IME_OF_FOCUS,
// An editable content is losing focus
NOTIFY_IME_OF_BLUR,
// Selection in the focused editable content is changed
NOTIFY_IME_OF_SELECTION_CHANGE,
// Text in the focused editable content is changed
NOTIFY_IME_OF_TEXT_CHANGE,
// Notified when a dispatched composition event is handled by the
// contents. This must be notified after the other notifications.
// Note that if a remote process has focus, this is notified only once when
// all dispatched events are handled completely. So, the receiver shouldn't
// count number of received this notification for comparing with the number
// of dispatched events.
// NOTE: If a composition event causes moving focus from the focused editor,
// this notification may not be notified as usual. Even in such case,
// NOTIFY_IME_OF_BLUR is always sent. So, notification listeners
// should tread the blur notification as including this if there is
// pending composition events.
NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED,
// Position or size of focused element may be changed.
NOTIFY_IME_OF_POSITION_CHANGE,
// Mouse button event is fired on a character in focused editor
NOTIFY_IME_OF_MOUSE_BUTTON_EVENT,
// Request to commit current composition to IME
// (some platforms may not support)
REQUEST_TO_COMMIT_COMPOSITION,
// Request to cancel current composition to IME
// (some platforms may not support)
REQUEST_TO_CANCEL_COMPOSITION
};
// FYI: Implemented in nsBaseWidget.cpp
const char* ToChar(IMEMessage aIMEMessage);
struct IMENotification final
{
IMENotification()
: mMessage(NOTIFY_IME_OF_NOTHING)
{
}
IMENotification(const IMENotification& aOther)
: mMessage(NOTIFY_IME_OF_NOTHING)
{
Assign(aOther);
}
~IMENotification()
{
Clear();
}
MOZ_IMPLICIT IMENotification(IMEMessage aMessage)
: mMessage(aMessage)
{
switch (aMessage) {
case NOTIFY_IME_OF_SELECTION_CHANGE:
mSelectionChangeData.mString = new nsString();
mSelectionChangeData.Clear();
break;
case NOTIFY_IME_OF_TEXT_CHANGE:
mTextChangeData.Clear();
break;
case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
mMouseButtonEventData.mEventMessage = eVoidEvent;
mMouseButtonEventData.mOffset = UINT32_MAX;
mMouseButtonEventData.mCursorPos.Set(nsIntPoint(0, 0));
mMouseButtonEventData.mCharRect.Set(nsIntRect(0, 0, 0, 0));
mMouseButtonEventData.mButton = -1;
mMouseButtonEventData.mButtons = 0;
mMouseButtonEventData.mModifiers = 0;
break;
default:
break;
}
}
void Assign(const IMENotification& aOther)
{
bool changingMessage = mMessage != aOther.mMessage;
if (changingMessage) {
Clear();
mMessage = aOther.mMessage;
}
switch (mMessage) {
case NOTIFY_IME_OF_SELECTION_CHANGE:
if (changingMessage) {
mSelectionChangeData.mString = new nsString();
}
mSelectionChangeData.Assign(aOther.mSelectionChangeData);
break;
case NOTIFY_IME_OF_TEXT_CHANGE:
mTextChangeData = aOther.mTextChangeData;
break;
case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
mMouseButtonEventData = aOther.mMouseButtonEventData;
break;
default:
break;
}
}
IMENotification& operator=(const IMENotification& aOther)
{
Assign(aOther);
return *this;
}
void Clear()
{
if (mMessage == NOTIFY_IME_OF_SELECTION_CHANGE) {
MOZ_ASSERT(mSelectionChangeData.mString);
delete mSelectionChangeData.mString;
mSelectionChangeData.mString = nullptr;
}
mMessage = NOTIFY_IME_OF_NOTHING;
}
bool HasNotification() const
{
return mMessage != NOTIFY_IME_OF_NOTHING;
}
void MergeWith(const IMENotification& aNotification)
{
switch (mMessage) {
case NOTIFY_IME_OF_NOTHING:
MOZ_ASSERT(aNotification.mMessage != NOTIFY_IME_OF_NOTHING);
Assign(aNotification);
break;
case NOTIFY_IME_OF_SELECTION_CHANGE:
MOZ_ASSERT(aNotification.mMessage == NOTIFY_IME_OF_SELECTION_CHANGE);
mSelectionChangeData.Assign(aNotification.mSelectionChangeData);
break;
case NOTIFY_IME_OF_TEXT_CHANGE:
MOZ_ASSERT(aNotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE);
mTextChangeData += aNotification.mTextChangeData;
break;
case NOTIFY_IME_OF_POSITION_CHANGE:
case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED:
MOZ_ASSERT(aNotification.mMessage == mMessage);
break;
default:
MOZ_CRASH("Merging notification isn't supported");
break;
}
}
IMEMessage mMessage;
struct Point
{
int32_t mX;
int32_t mY;
void Set(const nsIntPoint& aPoint)
{
mX = aPoint.x;
mY = aPoint.y;
}
nsIntPoint AsIntPoint() const
{
return nsIntPoint(mX, mY);
}
};
struct Rect
{
int32_t mX;
int32_t mY;
int32_t mWidth;
int32_t mHeight;
void Set(const nsIntRect& aRect)
{
mX = aRect.x;
mY = aRect.y;
mWidth = aRect.width;
mHeight = aRect.height;
}
nsIntRect AsIntRect() const
{
return nsIntRect(mX, mY, mWidth, mHeight);
}
};
// NOTIFY_IME_OF_SELECTION_CHANGE specific data
struct SelectionChangeDataBase
{
// Selection range.
uint32_t mOffset;
// Selected string
nsString* mString;
// Writing mode at the selection.
uint8_t mWritingMode;
bool mReversed;
bool mCausedByComposition;
bool mCausedBySelectionEvent;
bool mOccurredDuringComposition;
void SetWritingMode(const WritingMode& aWritingMode);
WritingMode GetWritingMode() const;
uint32_t StartOffset() const
{
return mOffset + (mReversed ? Length() : 0);
}
uint32_t EndOffset() const
{
return mOffset + (mReversed ? 0 : Length());
}
const nsString& String() const
{
return *mString;
}
uint32_t Length() const
{
return mString->Length();
}
bool IsInInt32Range() const
{
return mOffset + Length() <= INT32_MAX;
}
bool IsCollapsed() const
{
return mString->IsEmpty();
}
void ClearSelectionData()
{
mOffset = UINT32_MAX;
mString->Truncate();
mWritingMode = 0;
mReversed = false;
}
void Clear()
{
ClearSelectionData();
mCausedByComposition = false;
mCausedBySelectionEvent = false;
mOccurredDuringComposition = false;
}
bool IsValid() const
{
return mOffset != UINT32_MAX;
}
void Assign(const SelectionChangeDataBase& aOther)
{
mOffset = aOther.mOffset;
*mString = aOther.String();
mWritingMode = aOther.mWritingMode;
mReversed = aOther.mReversed;
AssignReason(aOther.mCausedByComposition,
aOther.mCausedBySelectionEvent,
aOther.mOccurredDuringComposition);
}
void AssignReason(bool aCausedByComposition,
bool aCausedBySelectionEvent,
bool aOccurredDuringComposition)
{
mCausedByComposition = aCausedByComposition;
mCausedBySelectionEvent = aCausedBySelectionEvent;
mOccurredDuringComposition = aOccurredDuringComposition;
}
};
// SelectionChangeDataBase cannot have constructors because it's used in
// the union. Therefore, SelectionChangeData should only implement
// constructors. In other words, add other members to
// SelectionChangeDataBase.
struct SelectionChangeData final : public SelectionChangeDataBase
{
SelectionChangeData()
{
mString = &mStringInstance;
Clear();
}
explicit SelectionChangeData(const SelectionChangeDataBase& aOther)
{
mString = &mStringInstance;
Assign(aOther);
}
SelectionChangeData(const SelectionChangeData& aOther)
{
mString = &mStringInstance;
Assign(aOther);
}
SelectionChangeData& operator=(const SelectionChangeDataBase& aOther)
{
mString = &mStringInstance;
Assign(aOther);
return *this;
}
SelectionChangeData& operator=(const SelectionChangeData& aOther)
{
mString = &mStringInstance;
Assign(aOther);
return *this;
}
private:
// When SelectionChangeData is used outside of union, it shouldn't create
// nsString instance in the heap as far as possible.
nsString mStringInstance;
};
struct TextChangeDataBase
{
// mStartOffset is the start offset of modified or removed text in
// original content and inserted text in new content.
uint32_t mStartOffset;
// mRemovalEndOffset is the end offset of modified or removed text in
// original content. If the value is same as mStartOffset, no text hasn't
// been removed yet.
uint32_t mRemovedEndOffset;
// mAddedEndOffset is the end offset of inserted text or same as
// mStartOffset if just removed. The vlaue is offset in the new content.
uint32_t mAddedEndOffset;
// Note that TextChangeDataBase may be the result of merging two or more
// changes especially in e10s mode.
// mCausedOnlyByComposition is true only when *all* merged changes are
// caused by composition.
bool mCausedOnlyByComposition;
// mIncludingChangesDuringComposition is true if at least one change which
// is not caused by composition occurred during the last composition.
// Note that if after the last composition is finished and there are some
// changes not caused by composition, this is set to false.
bool mIncludingChangesDuringComposition;
// mIncludingChangesWithoutComposition is true if there is at least one
// change which did occur when there wasn't a composition ongoing.
bool mIncludingChangesWithoutComposition;
uint32_t OldLength() const
{
MOZ_ASSERT(IsValid());
return mRemovedEndOffset - mStartOffset;
}
uint32_t NewLength() const
{
MOZ_ASSERT(IsValid());
return mAddedEndOffset - mStartOffset;
}
// Positive if text is added. Negative if text is removed.
int64_t Difference() const
{
return mAddedEndOffset - mRemovedEndOffset;
}
bool IsInInt32Range() const
{
MOZ_ASSERT(IsValid());
return mStartOffset <= INT32_MAX &&
mRemovedEndOffset <= INT32_MAX &&
mAddedEndOffset <= INT32_MAX;
}
bool IsValid() const
{
return !(mStartOffset == UINT32_MAX &&
!mRemovedEndOffset && !mAddedEndOffset);
}
void Clear()
{
mStartOffset = UINT32_MAX;
mRemovedEndOffset = mAddedEndOffset = 0;
}
void MergeWith(const TextChangeDataBase& aOther);
TextChangeDataBase& operator+=(const TextChangeDataBase& aOther)
{
MergeWith(aOther);
return *this;
}
#ifdef DEBUG
void Test();
#endif // #ifdef DEBUG
};
// TextChangeDataBase cannot have constructors because they are used in union.
// Therefore, TextChangeData should only implement constructor. In other
// words, add other members to TextChangeDataBase.
struct TextChangeData : public TextChangeDataBase
{
TextChangeData() { Clear(); }
TextChangeData(uint32_t aStartOffset,
uint32_t aRemovedEndOffset,
uint32_t aAddedEndOffset,
bool aCausedByComposition,
bool aOccurredDuringComposition)
{
MOZ_ASSERT(aRemovedEndOffset >= aStartOffset,
"removed end offset must not be smaller than start offset");
MOZ_ASSERT(aAddedEndOffset >= aStartOffset,
"added end offset must not be smaller than start offset");
mStartOffset = aStartOffset;
mRemovedEndOffset = aRemovedEndOffset;
mAddedEndOffset = aAddedEndOffset;
mCausedOnlyByComposition = aCausedByComposition;
mIncludingChangesDuringComposition =
!aCausedByComposition && aOccurredDuringComposition;
mIncludingChangesWithoutComposition =
!aCausedByComposition && !aOccurredDuringComposition;
}
};
struct MouseButtonEventData
{
// The value of WidgetEvent::mMessage
EventMessage mEventMessage;
// Character offset from the start of the focused editor under the cursor
uint32_t mOffset;
// Cursor position in pixels relative to the widget
Point mCursorPos;
// Character rect in pixels under the cursor relative to the widget
Rect mCharRect;
// The value of WidgetMouseEventBase::button and buttons
int16_t mButton;
int16_t mButtons;
// The value of WidgetInputEvent::modifiers
Modifiers mModifiers;
};
union
{
// NOTIFY_IME_OF_SELECTION_CHANGE specific data
SelectionChangeDataBase mSelectionChangeData;
// NOTIFY_IME_OF_TEXT_CHANGE specific data
TextChangeDataBase mTextChangeData;
// NOTIFY_IME_OF_MOUSE_BUTTON_EVENT specific data
MouseButtonEventData mMouseButtonEventData;
};
void SetData(const SelectionChangeDataBase& aSelectionChangeData)
{
MOZ_RELEASE_ASSERT(mMessage == NOTIFY_IME_OF_SELECTION_CHANGE);
mSelectionChangeData.Assign(aSelectionChangeData);
}
void SetData(const TextChangeDataBase& aTextChangeData)
{
MOZ_RELEASE_ASSERT(mMessage == NOTIFY_IME_OF_TEXT_CHANGE);
mTextChangeData = aTextChangeData;
}
};
struct CandidateWindowPosition
{
// Upper left corner of the candidate window if mExcludeRect is false.
// Otherwise, the position currently interested. E.g., caret position.
LayoutDeviceIntPoint mPoint;
// Rect which shouldn't be overlapped with the candidate window.
// This is valid only when mExcludeRect is true.
LayoutDeviceIntRect mRect;
// See explanation of mPoint and mRect.
bool mExcludeRect;
};
} // namespace widget
} // namespace mozilla
#endif // #ifndef mozilla_widget_IMEData_h_

View file

@ -0,0 +1,145 @@
/* 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 "InProcessCompositorWidget.h"
#include "nsBaseWidget.h"
#if defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING)
#include "mozilla/widget/AndroidCompositorWidget.h"
#endif
namespace mozilla {
namespace widget {
// Platforms with no OOP compositor process support use
// InProcessCompositorWidget by default.
#if !defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING)
/* static */ RefPtr<CompositorWidget>
CompositorWidget::CreateLocal(const CompositorWidgetInitData& aInitData, nsIWidget* aWidget)
{
MOZ_ASSERT(aWidget);
#ifdef MOZ_WIDGET_ANDROID
return new AndroidCompositorWidget(static_cast<nsBaseWidget*>(aWidget));
#else
return new InProcessCompositorWidget(static_cast<nsBaseWidget*>(aWidget));
#endif
}
#endif
InProcessCompositorWidget::InProcessCompositorWidget(nsBaseWidget* aWidget)
: mWidget(aWidget)
{
}
bool
InProcessCompositorWidget::PreRender(WidgetRenderingContext* aContext)
{
return mWidget->PreRender(aContext);
}
void
InProcessCompositorWidget::PostRender(WidgetRenderingContext* aContext)
{
mWidget->PostRender(aContext);
}
void
InProcessCompositorWidget::DrawWindowUnderlay(WidgetRenderingContext* aContext,
LayoutDeviceIntRect aRect)
{
mWidget->DrawWindowUnderlay(aContext, aRect);
}
void
InProcessCompositorWidget::DrawWindowOverlay(WidgetRenderingContext* aContext,
LayoutDeviceIntRect aRect)
{
mWidget->DrawWindowOverlay(aContext, aRect);
}
already_AddRefed<gfx::DrawTarget>
InProcessCompositorWidget::StartRemoteDrawing()
{
return mWidget->StartRemoteDrawing();
}
already_AddRefed<gfx::DrawTarget>
InProcessCompositorWidget::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion,
layers::BufferMode* aBufferMode)
{
return mWidget->StartRemoteDrawingInRegion(aInvalidRegion, aBufferMode);
}
void
InProcessCompositorWidget::EndRemoteDrawing()
{
mWidget->EndRemoteDrawing();
}
void
InProcessCompositorWidget::EndRemoteDrawingInRegion(gfx::DrawTarget* aDrawTarget,
LayoutDeviceIntRegion& aInvalidRegion)
{
mWidget->EndRemoteDrawingInRegion(aDrawTarget, aInvalidRegion);
}
void
InProcessCompositorWidget::CleanupRemoteDrawing()
{
mWidget->CleanupRemoteDrawing();
}
void
InProcessCompositorWidget::CleanupWindowEffects()
{
mWidget->CleanupWindowEffects();
}
bool
InProcessCompositorWidget::InitCompositor(layers::Compositor* aCompositor)
{
return mWidget->InitCompositor(aCompositor);
}
LayoutDeviceIntSize
InProcessCompositorWidget::GetClientSize()
{
return mWidget->GetClientSize();
}
uint32_t
InProcessCompositorWidget::GetGLFrameBufferFormat()
{
return mWidget->GetGLFrameBufferFormat();
}
layers::Composer2D*
InProcessCompositorWidget::GetComposer2D()
{
return mWidget->GetComposer2D();
}
uintptr_t
InProcessCompositorWidget::GetWidgetKey()
{
return reinterpret_cast<uintptr_t>(mWidget);
}
nsIWidget*
InProcessCompositorWidget::RealWidget()
{
return mWidget;
}
void
InProcessCompositorWidget::ObserveVsync(VsyncObserver* aObserver)
{
if (RefPtr<CompositorVsyncDispatcher> cvd = mWidget->GetCompositorVsyncDispatcher()) {
cvd->SetCompositorVsyncObserver(aObserver);
}
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,52 @@
/* 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/. */
#ifndef mozilla_widget_InProcessCompositorWidget_h__
#define mozilla_widget_InProcessCompositorWidget_h__
#include "CompositorWidget.h"
namespace mozilla {
namespace widget {
// This version of CompositorWidget implements a wrapper around
// nsBaseWidget.
class InProcessCompositorWidget : public CompositorWidget
{
public:
explicit InProcessCompositorWidget(nsBaseWidget* aWidget);
virtual bool PreRender(WidgetRenderingContext* aManager) override;
virtual void PostRender(WidgetRenderingContext* aManager) override;
virtual void DrawWindowUnderlay(WidgetRenderingContext* aContext,
LayoutDeviceIntRect aRect) override;
virtual void DrawWindowOverlay(WidgetRenderingContext* aContext,
LayoutDeviceIntRect aRect) override;
virtual already_AddRefed<gfx::DrawTarget> StartRemoteDrawing() override;
virtual already_AddRefed<gfx::DrawTarget>
StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion,
layers::BufferMode* aBufferMode) override;
virtual void EndRemoteDrawing() override;
virtual void EndRemoteDrawingInRegion(gfx::DrawTarget* aDrawTarget,
LayoutDeviceIntRegion& aInvalidRegion) override;
virtual void CleanupRemoteDrawing() override;
virtual void CleanupWindowEffects() override;
virtual bool InitCompositor(layers::Compositor* aCompositor) override;
virtual LayoutDeviceIntSize GetClientSize() override;
virtual uint32_t GetGLFrameBufferFormat() override;
virtual layers::Composer2D* GetComposer2D() override;
virtual void ObserveVsync(VsyncObserver* aObserver) override;
virtual uintptr_t GetWidgetKey() override;
// If you can override this method, inherit from CompositorWidget instead.
nsIWidget* RealWidget() override;
private:
nsBaseWidget* mWidget;
};
} // namespace widget
} // namespace mozilla
#endif

777
widget/InputData.cpp Normal file
View file

@ -0,0 +1,777 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "InputData.h"
#include "mozilla/dom/Touch.h"
#include "nsDebug.h"
#include "nsThreadUtils.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/TouchEvents.h"
#include "UnitTransforms.h"
namespace mozilla {
using namespace dom;
InputData::~InputData()
{
}
InputData::InputData(InputType aInputType)
: mInputType(aInputType)
, mTime(0)
, modifiers(0)
{
}
InputData::InputData(InputType aInputType, uint32_t aTime, TimeStamp aTimeStamp,
Modifiers aModifiers)
: mInputType(aInputType)
, mTime(aTime)
, mTimeStamp(aTimeStamp)
, modifiers(aModifiers)
{
}
SingleTouchData::SingleTouchData(int32_t aIdentifier, ScreenIntPoint aScreenPoint,
ScreenSize aRadius, float aRotationAngle,
float aForce)
: mIdentifier(aIdentifier)
, mScreenPoint(aScreenPoint)
, mRadius(aRadius)
, mRotationAngle(aRotationAngle)
, mForce(aForce)
{
}
SingleTouchData::SingleTouchData(int32_t aIdentifier,
ParentLayerPoint aLocalScreenPoint,
ScreenSize aRadius, float aRotationAngle,
float aForce)
: mIdentifier(aIdentifier)
, mLocalScreenPoint(aLocalScreenPoint)
, mRadius(aRadius)
, mRotationAngle(aRotationAngle)
, mForce(aForce)
{
}
SingleTouchData::SingleTouchData()
{
}
already_AddRefed<Touch> SingleTouchData::ToNewDOMTouch() const
{
MOZ_ASSERT(NS_IsMainThread(),
"Can only create dom::Touch instances on main thread");
RefPtr<Touch> touch = new Touch(mIdentifier,
LayoutDeviceIntPoint::Truncate(mScreenPoint.x, mScreenPoint.y),
LayoutDeviceIntPoint::Truncate(mRadius.width, mRadius.height),
mRotationAngle,
mForce);
return touch.forget();
}
MultiTouchInput::MultiTouchInput(MultiTouchType aType, uint32_t aTime,
TimeStamp aTimeStamp, Modifiers aModifiers)
: InputData(MULTITOUCH_INPUT, aTime, aTimeStamp, aModifiers)
, mType(aType)
, mHandledByAPZ(false)
{
}
MultiTouchInput::MultiTouchInput()
: InputData(MULTITOUCH_INPUT)
, mHandledByAPZ(false)
{
}
MultiTouchInput::MultiTouchInput(const MultiTouchInput& aOther)
: InputData(MULTITOUCH_INPUT, aOther.mTime, aOther.mTimeStamp, aOther.modifiers)
, mType(aOther.mType)
, mHandledByAPZ(aOther.mHandledByAPZ)
{
mTouches.AppendElements(aOther.mTouches);
}
MultiTouchInput::MultiTouchInput(const WidgetTouchEvent& aTouchEvent)
: InputData(MULTITOUCH_INPUT, aTouchEvent.mTime, aTouchEvent.mTimeStamp,
aTouchEvent.mModifiers)
, mHandledByAPZ(aTouchEvent.mFlags.mHandledByAPZ)
{
MOZ_ASSERT(NS_IsMainThread(),
"Can only copy from WidgetTouchEvent on main thread");
switch (aTouchEvent.mMessage) {
case eTouchStart:
mType = MULTITOUCH_START;
break;
case eTouchMove:
mType = MULTITOUCH_MOVE;
break;
case eTouchEnd:
mType = MULTITOUCH_END;
break;
case eTouchCancel:
mType = MULTITOUCH_CANCEL;
break;
default:
MOZ_ASSERT_UNREACHABLE("Did not assign a type to a MultiTouchInput");
break;
}
for (size_t i = 0; i < aTouchEvent.mTouches.Length(); i++) {
const Touch* domTouch = aTouchEvent.mTouches[i];
// Extract data from weird interfaces.
int32_t identifier = domTouch->Identifier();
int32_t radiusX = domTouch->RadiusX();
int32_t radiusY = domTouch->RadiusY();
float rotationAngle = domTouch->RotationAngle();
float force = domTouch->Force();
SingleTouchData data(identifier,
ViewAs<ScreenPixel>(domTouch->mRefPoint,
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent),
ScreenSize(radiusX, radiusY),
rotationAngle,
force);
mTouches.AppendElement(data);
}
}
MultiTouchInput::MultiTouchInput(const WidgetMouseEvent& aMouseEvent)
: InputData(MULTITOUCH_INPUT, aMouseEvent.mTime, aMouseEvent.mTimeStamp,
aMouseEvent.mModifiers)
, mHandledByAPZ(aMouseEvent.mFlags.mHandledByAPZ)
{
MOZ_ASSERT(NS_IsMainThread(),
"Can only copy from WidgetMouseEvent on main thread");
switch (aMouseEvent.mMessage) {
case eMouseDown:
mType = MULTITOUCH_START;
break;
case eMouseMove:
mType = MULTITOUCH_MOVE;
break;
case eMouseUp:
mType = MULTITOUCH_END;
break;
// The mouse pointer has been interrupted in an implementation-specific
// manner, such as a synchronous event or action cancelling the touch, or a
// touch point leaving the document window and going into a non-document
// area capable of handling user interactions.
case eMouseExitFromWidget:
mType = MULTITOUCH_CANCEL;
break;
default:
NS_WARNING("Did not assign a type to a MultiTouchInput");
break;
}
mTouches.AppendElement(SingleTouchData(0,
ViewAs<ScreenPixel>(aMouseEvent.mRefPoint,
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent),
ScreenSize(1, 1),
180.0f,
1.0f));
}
WidgetTouchEvent
MultiTouchInput::ToWidgetTouchEvent(nsIWidget* aWidget) const
{
MOZ_ASSERT(NS_IsMainThread(),
"Can only convert To WidgetTouchEvent on main thread");
EventMessage touchEventMessage = eVoidEvent;
switch (mType) {
case MULTITOUCH_START:
touchEventMessage = eTouchStart;
break;
case MULTITOUCH_MOVE:
touchEventMessage = eTouchMove;
break;
case MULTITOUCH_END:
touchEventMessage = eTouchEnd;
break;
case MULTITOUCH_CANCEL:
touchEventMessage = eTouchCancel;
break;
default:
MOZ_ASSERT_UNREACHABLE("Did not assign a type to WidgetTouchEvent in MultiTouchInput");
break;
}
WidgetTouchEvent event(true, touchEventMessage, aWidget);
if (touchEventMessage == eVoidEvent) {
return event;
}
event.mModifiers = this->modifiers;
event.mTime = this->mTime;
event.mTimeStamp = this->mTimeStamp;
event.mFlags.mHandledByAPZ = mHandledByAPZ;
for (size_t i = 0; i < mTouches.Length(); i++) {
*event.mTouches.AppendElement() = mTouches[i].ToNewDOMTouch();
}
return event;
}
WidgetMouseEvent
MultiTouchInput::ToWidgetMouseEvent(nsIWidget* aWidget) const
{
MOZ_ASSERT(NS_IsMainThread(),
"Can only convert To WidgetMouseEvent on main thread");
EventMessage mouseEventMessage = eVoidEvent;
switch (mType) {
case MultiTouchInput::MULTITOUCH_START:
mouseEventMessage = eMouseDown;
break;
case MultiTouchInput::MULTITOUCH_MOVE:
mouseEventMessage = eMouseMove;
break;
case MultiTouchInput::MULTITOUCH_CANCEL:
case MultiTouchInput::MULTITOUCH_END:
mouseEventMessage = eMouseUp;
break;
default:
MOZ_ASSERT_UNREACHABLE("Did not assign a type to WidgetMouseEvent");
break;
}
WidgetMouseEvent event(true, mouseEventMessage, aWidget,
WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
const SingleTouchData& firstTouch = mTouches[0];
event.mRefPoint.x = firstTouch.mScreenPoint.x;
event.mRefPoint.y = firstTouch.mScreenPoint.y;
event.mTime = mTime;
event.button = WidgetMouseEvent::eLeftButton;
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
event.mModifiers = modifiers;
event.mFlags.mHandledByAPZ = mHandledByAPZ;
if (mouseEventMessage != eMouseMove) {
event.mClickCount = 1;
}
return event;
}
int32_t
MultiTouchInput::IndexOfTouch(int32_t aTouchIdentifier)
{
for (size_t i = 0; i < mTouches.Length(); i++) {
if (mTouches[i].mIdentifier == aTouchIdentifier) {
return (int32_t)i;
}
}
return -1;
}
bool
MultiTouchInput::TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform)
{
for (size_t i = 0; i < mTouches.Length(); i++) {
Maybe<ParentLayerIntPoint> point = UntransformBy(aTransform, mTouches[i].mScreenPoint);
if (!point) {
return false;
}
mTouches[i].mLocalScreenPoint = *point;
}
return true;
}
MouseInput::MouseInput()
: InputData(MOUSE_INPUT)
, mType(MOUSE_NONE)
, mButtonType(NONE)
, mInputSource(0)
, mButtons(0)
, mHandledByAPZ(false)
{
}
MouseInput::MouseInput(MouseType aType, ButtonType aButtonType,
uint16_t aInputSource, int16_t aButtons,
const ScreenPoint& aPoint, uint32_t aTime,
TimeStamp aTimeStamp, Modifiers aModifiers)
: InputData(MOUSE_INPUT, aTime, aTimeStamp, aModifiers)
, mType(aType)
, mButtonType(aButtonType)
, mInputSource(aInputSource)
, mButtons(aButtons)
, mOrigin(aPoint)
, mHandledByAPZ(false)
{
}
MouseInput::MouseInput(const WidgetMouseEventBase& aMouseEvent)
: InputData(MOUSE_INPUT, aMouseEvent.mTime, aMouseEvent.mTimeStamp,
aMouseEvent.mModifiers)
, mType(MOUSE_NONE)
, mButtonType(NONE)
, mInputSource(aMouseEvent.inputSource)
, mButtons(aMouseEvent.buttons)
, mHandledByAPZ(aMouseEvent.mFlags.mHandledByAPZ)
{
MOZ_ASSERT(NS_IsMainThread(),
"Can only copy from WidgetTouchEvent on main thread");
mButtonType = NONE;
switch (aMouseEvent.button) {
case WidgetMouseEventBase::eLeftButton:
mButtonType = MouseInput::LEFT_BUTTON;
break;
case WidgetMouseEventBase::eMiddleButton:
mButtonType = MouseInput::MIDDLE_BUTTON;
break;
case WidgetMouseEventBase::eRightButton:
mButtonType = MouseInput::RIGHT_BUTTON;
break;
}
switch (aMouseEvent.mMessage) {
case eMouseMove:
mType = MOUSE_MOVE;
break;
case eMouseUp:
mType = MOUSE_UP;
break;
case eMouseDown:
mType = MOUSE_DOWN;
break;
case eDragStart:
mType = MOUSE_DRAG_START;
break;
case eDragEnd:
mType = MOUSE_DRAG_END;
break;
case eMouseEnterIntoWidget:
mType = MOUSE_WIDGET_ENTER;
break;
case eMouseExitFromWidget:
mType = MOUSE_WIDGET_EXIT;
break;
default:
MOZ_ASSERT_UNREACHABLE("Mouse event type not supported");
break;
}
mOrigin =
ScreenPoint(ViewAs<ScreenPixel>(aMouseEvent.mRefPoint,
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
}
bool
MouseInput::IsLeftButton() const
{
return mButtonType == LEFT_BUTTON;
}
bool
MouseInput::TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform)
{
Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
if (!point) {
return false;
}
mLocalOrigin = *point;
return true;
}
WidgetMouseEvent
MouseInput::ToWidgetMouseEvent(nsIWidget* aWidget) const
{
MOZ_ASSERT(NS_IsMainThread(),
"Can only convert To WidgetTouchEvent on main thread");
EventMessage msg = eVoidEvent;
uint32_t clickCount = 0;
switch (mType) {
case MOUSE_MOVE:
msg = eMouseMove;
break;
case MOUSE_UP:
msg = eMouseUp;
clickCount = 1;
break;
case MOUSE_DOWN:
msg = eMouseDown;
clickCount = 1;
break;
case MOUSE_DRAG_START:
msg = eDragStart;
break;
case MOUSE_DRAG_END:
msg = eDragEnd;
break;
case MOUSE_WIDGET_ENTER:
msg = eMouseEnterIntoWidget;
break;
case MOUSE_WIDGET_EXIT:
msg = eMouseExitFromWidget;
break;
default:
MOZ_ASSERT_UNREACHABLE("Did not assign a type to WidgetMouseEvent in MouseInput");
break;
}
WidgetMouseEvent event(true, msg, aWidget, WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
if (msg == eVoidEvent) {
return event;
}
switch (mButtonType) {
case MouseInput::LEFT_BUTTON:
event.button = WidgetMouseEventBase::eLeftButton;
break;
case MouseInput::MIDDLE_BUTTON:
event.button = WidgetMouseEventBase::eMiddleButton;
break;
case MouseInput::RIGHT_BUTTON:
event.button = WidgetMouseEventBase::eRightButton;
break;
case MouseInput::NONE:
default:
break;
}
event.buttons = mButtons;
event.mModifiers = modifiers;
event.mTime = mTime;
event.mTimeStamp = mTimeStamp;
event.mFlags.mHandledByAPZ = mHandledByAPZ;
event.mRefPoint =
RoundedToInt(ViewAs<LayoutDevicePixel>(mOrigin,
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
event.mClickCount = clickCount;
event.inputSource = mInputSource;
event.mIgnoreRootScrollFrame = true;
return event;
}
PanGestureInput::PanGestureInput()
: InputData(PANGESTURE_INPUT)
, mLineOrPageDeltaX(0)
, mLineOrPageDeltaY(0)
, mUserDeltaMultiplierX(1.0)
, mUserDeltaMultiplierY(1.0)
, mHandledByAPZ(false)
, mFollowedByMomentum(false)
, mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection(false)
{
}
PanGestureInput::PanGestureInput(PanGestureType aType, uint32_t aTime,
TimeStamp aTimeStamp,
const ScreenPoint& aPanStartPoint,
const ScreenPoint& aPanDisplacement,
Modifiers aModifiers)
: InputData(PANGESTURE_INPUT, aTime, aTimeStamp, aModifiers)
, mType(aType)
, mPanStartPoint(aPanStartPoint)
, mPanDisplacement(aPanDisplacement)
, mLineOrPageDeltaX(0)
, mLineOrPageDeltaY(0)
, mUserDeltaMultiplierX(1.0)
, mUserDeltaMultiplierY(1.0)
, mHandledByAPZ(false)
, mFollowedByMomentum(false)
, mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection(false)
{
}
bool
PanGestureInput::IsMomentum() const
{
switch (mType) {
case PanGestureInput::PANGESTURE_MOMENTUMSTART:
case PanGestureInput::PANGESTURE_MOMENTUMPAN:
case PanGestureInput::PANGESTURE_MOMENTUMEND:
return true;
default:
return false;
}
}
WidgetWheelEvent
PanGestureInput::ToWidgetWheelEvent(nsIWidget* aWidget) const
{
WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
wheelEvent.mModifiers = this->modifiers;
wheelEvent.mTime = mTime;
wheelEvent.mTimeStamp = mTimeStamp;
wheelEvent.mRefPoint =
RoundedToInt(ViewAs<LayoutDevicePixel>(mPanStartPoint,
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
wheelEvent.buttons = 0;
wheelEvent.mDeltaMode = nsIDOMWheelEvent::DOM_DELTA_PIXEL;
wheelEvent.mMayHaveMomentum = true; // pan inputs may have momentum
wheelEvent.mIsMomentum = IsMomentum();
wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
wheelEvent.mDeltaX = mPanDisplacement.x;
wheelEvent.mDeltaY = mPanDisplacement.y;
wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
return wheelEvent;
}
bool
PanGestureInput::TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform)
{
Maybe<ParentLayerPoint> panStartPoint = UntransformBy(aTransform, mPanStartPoint);
if (!panStartPoint) {
return false;
}
mLocalPanStartPoint = *panStartPoint;
Maybe<ParentLayerPoint> panDisplacement = UntransformVector(aTransform, mPanDisplacement, mPanStartPoint);
if (!panDisplacement) {
return false;
}
mLocalPanDisplacement = *panDisplacement;
return true;
}
ScreenPoint
PanGestureInput::UserMultipliedPanDisplacement() const
{
return ScreenPoint(mPanDisplacement.x * mUserDeltaMultiplierX,
mPanDisplacement.y * mUserDeltaMultiplierY);
}
ParentLayerPoint
PanGestureInput::UserMultipliedLocalPanDisplacement() const
{
return ParentLayerPoint(mLocalPanDisplacement.x * mUserDeltaMultiplierX,
mLocalPanDisplacement.y * mUserDeltaMultiplierY);
}
PinchGestureInput::PinchGestureInput()
: InputData(PINCHGESTURE_INPUT)
{
}
PinchGestureInput::PinchGestureInput(PinchGestureType aType, uint32_t aTime,
TimeStamp aTimeStamp,
const ParentLayerPoint& aLocalFocusPoint,
ParentLayerCoord aCurrentSpan,
ParentLayerCoord aPreviousSpan,
Modifiers aModifiers)
: InputData(PINCHGESTURE_INPUT, aTime, aTimeStamp, aModifiers)
, mType(aType)
, mLocalFocusPoint(aLocalFocusPoint)
, mCurrentSpan(aCurrentSpan)
, mPreviousSpan(aPreviousSpan)
{
}
bool
PinchGestureInput::TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform)
{
Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mFocusPoint);
if (!point) {
return false;
}
mLocalFocusPoint = *point;
return true;
}
TapGestureInput::TapGestureInput()
: InputData(TAPGESTURE_INPUT)
{
}
TapGestureInput::TapGestureInput(TapGestureType aType, uint32_t aTime,
TimeStamp aTimeStamp,
const ScreenIntPoint& aPoint,
Modifiers aModifiers)
: InputData(TAPGESTURE_INPUT, aTime, aTimeStamp, aModifiers)
, mType(aType)
, mPoint(aPoint)
{
}
TapGestureInput::TapGestureInput(TapGestureType aType, uint32_t aTime,
TimeStamp aTimeStamp,
const ParentLayerPoint& aLocalPoint,
Modifiers aModifiers)
: InputData(TAPGESTURE_INPUT, aTime, aTimeStamp, aModifiers)
, mType(aType)
, mLocalPoint(aLocalPoint)
{
}
bool
TapGestureInput::TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform)
{
Maybe<ParentLayerIntPoint> point = UntransformBy(aTransform, mPoint);
if (!point) {
return false;
}
mLocalPoint = *point;
return true;
}
ScrollWheelInput::ScrollWheelInput()
: InputData(SCROLLWHEEL_INPUT)
, mHandledByAPZ(false)
, mLineOrPageDeltaX(0)
, mLineOrPageDeltaY(0)
, mScrollSeriesNumber(0)
, mUserDeltaMultiplierX(1.0)
, mUserDeltaMultiplierY(1.0)
, mMayHaveMomentum(false)
, mIsMomentum(false)
{
}
ScrollWheelInput::ScrollWheelInput(uint32_t aTime, TimeStamp aTimeStamp,
Modifiers aModifiers, ScrollMode aScrollMode,
ScrollDeltaType aDeltaType,
const ScreenPoint& aOrigin, double aDeltaX,
double aDeltaY,
bool aAllowToOverrideSystemScrollSpeed)
: InputData(SCROLLWHEEL_INPUT, aTime, aTimeStamp, aModifiers)
, mDeltaType(aDeltaType)
, mScrollMode(aScrollMode)
, mOrigin(aOrigin)
, mHandledByAPZ(false)
, mDeltaX(aDeltaX)
, mDeltaY(aDeltaY)
, mLineOrPageDeltaX(0)
, mLineOrPageDeltaY(0)
, mScrollSeriesNumber(0)
, mUserDeltaMultiplierX(1.0)
, mUserDeltaMultiplierY(1.0)
, mMayHaveMomentum(false)
, mIsMomentum(false)
, mAllowToOverrideSystemScrollSpeed(aAllowToOverrideSystemScrollSpeed)
{
}
ScrollWheelInput::ScrollWheelInput(const WidgetWheelEvent& aWheelEvent)
: InputData(SCROLLWHEEL_INPUT, aWheelEvent.mTime, aWheelEvent.mTimeStamp,
aWheelEvent.mModifiers)
, mDeltaType(DeltaTypeForDeltaMode(aWheelEvent.mDeltaMode))
, mScrollMode(SCROLLMODE_INSTANT)
, mHandledByAPZ(aWheelEvent.mFlags.mHandledByAPZ)
, mDeltaX(aWheelEvent.mDeltaX)
, mDeltaY(aWheelEvent.mDeltaY)
, mLineOrPageDeltaX(aWheelEvent.mLineOrPageDeltaX)
, mLineOrPageDeltaY(aWheelEvent.mLineOrPageDeltaY)
, mScrollSeriesNumber(0)
, mUserDeltaMultiplierX(1.0)
, mUserDeltaMultiplierY(1.0)
, mMayHaveMomentum(aWheelEvent.mMayHaveMomentum)
, mIsMomentum(aWheelEvent.mIsMomentum)
, mAllowToOverrideSystemScrollSpeed(
aWheelEvent.mAllowToOverrideSystemScrollSpeed)
{
mOrigin =
ScreenPoint(ViewAs<ScreenPixel>(aWheelEvent.mRefPoint,
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
}
ScrollWheelInput::ScrollDeltaType
ScrollWheelInput::DeltaTypeForDeltaMode(uint32_t aDeltaMode)
{
switch (aDeltaMode) {
case nsIDOMWheelEvent::DOM_DELTA_LINE:
return SCROLLDELTA_LINE;
case nsIDOMWheelEvent::DOM_DELTA_PAGE:
return SCROLLDELTA_PAGE;
case nsIDOMWheelEvent::DOM_DELTA_PIXEL:
return SCROLLDELTA_PIXEL;
default:
MOZ_CRASH();
}
return SCROLLDELTA_LINE;
}
uint32_t
ScrollWheelInput::DeltaModeForDeltaType(ScrollDeltaType aDeltaType)
{
switch (aDeltaType) {
case ScrollWheelInput::SCROLLDELTA_LINE:
return nsIDOMWheelEvent::DOM_DELTA_LINE;
case ScrollWheelInput::SCROLLDELTA_PAGE:
return nsIDOMWheelEvent::DOM_DELTA_PAGE;
case ScrollWheelInput::SCROLLDELTA_PIXEL:
default:
return nsIDOMWheelEvent::DOM_DELTA_PIXEL;
}
}
nsIScrollableFrame::ScrollUnit
ScrollWheelInput::ScrollUnitForDeltaType(ScrollDeltaType aDeltaType)
{
switch (aDeltaType) {
case SCROLLDELTA_LINE:
return nsIScrollableFrame::LINES;
case SCROLLDELTA_PAGE:
return nsIScrollableFrame::PAGES;
case SCROLLDELTA_PIXEL:
return nsIScrollableFrame::DEVICE_PIXELS;
default:
MOZ_CRASH();
}
return nsIScrollableFrame::LINES;
}
WidgetWheelEvent
ScrollWheelInput::ToWidgetWheelEvent(nsIWidget* aWidget) const
{
WidgetWheelEvent wheelEvent(true, eWheel, aWidget);
wheelEvent.mModifiers = this->modifiers;
wheelEvent.mTime = mTime;
wheelEvent.mTimeStamp = mTimeStamp;
wheelEvent.mRefPoint =
RoundedToInt(ViewAs<LayoutDevicePixel>(mOrigin,
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent));
wheelEvent.buttons = 0;
wheelEvent.mDeltaMode = DeltaModeForDeltaType(mDeltaType);
wheelEvent.mMayHaveMomentum = mMayHaveMomentum;
wheelEvent.mIsMomentum = mIsMomentum;
wheelEvent.mDeltaX = mDeltaX;
wheelEvent.mDeltaY = mDeltaY;
wheelEvent.mLineOrPageDeltaX = mLineOrPageDeltaX;
wheelEvent.mLineOrPageDeltaY = mLineOrPageDeltaY;
wheelEvent.mAllowToOverrideSystemScrollSpeed =
mAllowToOverrideSystemScrollSpeed;
wheelEvent.mFlags.mHandledByAPZ = mHandledByAPZ;
return wheelEvent;
}
bool
ScrollWheelInput::TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform)
{
Maybe<ParentLayerPoint> point = UntransformBy(aTransform, mOrigin);
if (!point) {
return false;
}
mLocalOrigin = *point;
return true;
}
bool
ScrollWheelInput::IsCustomizedByUserPrefs() const
{
return mUserDeltaMultiplierX != 1.0 ||
mUserDeltaMultiplierY != 1.0;
}
} // namespace mozilla

617
widget/InputData.h Normal file
View file

@ -0,0 +1,617 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef InputData_h__
#define InputData_h__
#include "nsDebug.h"
#include "nsIDOMWheelEvent.h"
#include "nsIScrollableFrame.h"
#include "nsPoint.h"
#include "nsTArray.h"
#include "Units.h"
#include "mozilla/EventForwards.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/gfx/MatrixFwd.h"
template<class E> struct already_AddRefed;
class nsIWidget;
namespace mozilla {
namespace layers {
class PAPZCTreeManagerParent;
class APZCTreeManagerChild;
}
namespace dom {
class Touch;
} // namespace dom
enum InputType
{
// Warning, this enum is serialized and sent over IPC. If you reorder, add,
// or remove a value, you need to update its ParamTraits<> in nsGUIEventIPC.h
MULTITOUCH_INPUT,
MOUSE_INPUT,
PANGESTURE_INPUT,
PINCHGESTURE_INPUT,
TAPGESTURE_INPUT,
SCROLLWHEEL_INPUT,
// Used as an upper bound for ContiguousEnumSerializer
SENTINEL_INPUT,
};
class MultiTouchInput;
class MouseInput;
class PanGestureInput;
class PinchGestureInput;
class TapGestureInput;
class ScrollWheelInput;
// This looks unnecessary now, but as we add more and more classes that derive
// from InputType (eventually probably almost as many as *Events.h has), it
// will be more and more clear what's going on with a macro that shortens the
// definition of the RTTI functions.
#define INPUTDATA_AS_CHILD_TYPE(type, enumID) \
const type& As##type() const \
{ \
MOZ_ASSERT(mInputType == enumID, "Invalid cast of InputData."); \
return (const type&) *this; \
} \
type& As##type() \
{ \
MOZ_ASSERT(mInputType == enumID, "Invalid cast of InputData."); \
return (type&) *this; \
}
/** Base input data class. Should never be instantiated. */
class InputData
{
public:
// Warning, this class is serialized and sent over IPC. Any change to its
// fields must be reflected in its ParamTraits<>, in nsGUIEventIPC.h
InputType mInputType;
// Time in milliseconds that this data is relevant to. This only really
// matters when this data is used as an event. We use uint32_t instead of
// TimeStamp because it is easier to convert from WidgetInputEvent. The time
// is platform-specific but it in the case of B2G and Fennec it is since
// startup.
uint32_t mTime;
// Set in parallel to mTime until we determine it is safe to drop
// platform-specific event times (see bug 77992).
TimeStamp mTimeStamp;
Modifiers modifiers;
INPUTDATA_AS_CHILD_TYPE(MultiTouchInput, MULTITOUCH_INPUT)
INPUTDATA_AS_CHILD_TYPE(MouseInput, MOUSE_INPUT)
INPUTDATA_AS_CHILD_TYPE(PanGestureInput, PANGESTURE_INPUT)
INPUTDATA_AS_CHILD_TYPE(PinchGestureInput, PINCHGESTURE_INPUT)
INPUTDATA_AS_CHILD_TYPE(TapGestureInput, TAPGESTURE_INPUT)
INPUTDATA_AS_CHILD_TYPE(ScrollWheelInput, SCROLLWHEEL_INPUT)
virtual ~InputData();
explicit InputData(InputType aInputType);
protected:
InputData(InputType aInputType, uint32_t aTime, TimeStamp aTimeStamp,
Modifiers aModifiers);
};
/**
* Data container for a single touch input. Similar to dom::Touch, but used in
* off-main-thread situations. This is more for just storing touch data, whereas
* dom::Touch is more useful for dispatching through the DOM (which can only
* happen on the main thread). dom::Touch also bears the problem of storing
* pointers to nsIWidget instances which can only be used on the main thread,
* so if instead we used dom::Touch and ever set these pointers
* off-main-thread, Bad Things Can Happen(tm).
*
* Note that this doesn't inherit from InputData because this itself is not an
* event. It is only a container/struct that should have any number of instances
* within a MultiTouchInput.
*
* fixme/bug 775746: Make dom::Touch inherit from this class.
*/
class SingleTouchData
{
public:
// Construct a SingleTouchData from a Screen point.
// mLocalScreenPoint remains (0,0) unless it's set later.
SingleTouchData(int32_t aIdentifier,
ScreenIntPoint aScreenPoint,
ScreenSize aRadius,
float aRotationAngle,
float aForce);
// Construct a SingleTouchData from a ParentLayer point.
// mScreenPoint remains (0,0) unless it's set later.
// Note: if APZ starts using the radius for anything, we should add a local
// version of that too, and have this constructor take it as a ParentLayerSize.
SingleTouchData(int32_t aIdentifier,
ParentLayerPoint aLocalScreenPoint,
ScreenSize aRadius,
float aRotationAngle,
float aForce);
SingleTouchData();
already_AddRefed<dom::Touch> ToNewDOMTouch() const;
// Warning, this class is serialized and sent over IPC. Any change to its
// fields must be reflected in its ParamTraits<>, in nsGUIEventIPC.h
// A unique number assigned to each SingleTouchData within a MultiTouchInput so
// that they can be easily distinguished when handling a touch start/move/end.
int32_t mIdentifier;
// Point on the screen that the touch hit, in device pixels. They are
// coordinates on the screen.
ScreenIntPoint mScreenPoint;
// |mScreenPoint| transformed to the local coordinates of the APZC targeted
// by the hit. This is set and used by APZ.
ParentLayerPoint mLocalScreenPoint;
// Radius that the touch covers, i.e. if you're using your thumb it will
// probably be larger than using your pinky, even with the same force.
// Radius can be different along x and y. For example, if you press down with
// your entire finger vertically, the y radius will be much larger than the x
// radius.
ScreenSize mRadius;
float mRotationAngle;
// How hard the screen is being pressed.
float mForce;
};
/**
* Similar to WidgetTouchEvent, but for use off-main-thread. Also only stores a
* screen touch point instead of the many different coordinate spaces
* WidgetTouchEvent stores its touch point in. This includes a way to initialize
* itself from a WidgetTouchEvent by copying all relevant data over. Note that
* this copying from WidgetTouchEvent functionality can only be used on the main
* thread.
*
* Stores an array of SingleTouchData.
*/
class MultiTouchInput : public InputData
{
public:
enum MultiTouchType
{
// Warning, this enum is serialized and sent over IPC. If you reorder, add,
// or remove a value, you need to update its ParamTraits<> in nsGUIEventIPC.h
MULTITOUCH_START,
MULTITOUCH_MOVE,
MULTITOUCH_END,
MULTITOUCH_CANCEL,
// Used as an upper bound for ContiguousEnumSerializer
MULTITOUCH_SENTINEL,
};
MultiTouchInput(MultiTouchType aType, uint32_t aTime, TimeStamp aTimeStamp,
Modifiers aModifiers);
MultiTouchInput();
MultiTouchInput(const MultiTouchInput& aOther);
explicit MultiTouchInput(const WidgetTouchEvent& aTouchEvent);
// This conversion from WidgetMouseEvent to MultiTouchInput is needed because
// on the B2G emulator we can only receive mouse events, but we need to be
// able to pan correctly. To do this, we convert the events into a format that
// the panning code can handle. This code is very limited and only supports
// SingleTouchData. It also sends garbage for the identifier, radius, force
// and rotation angle.
explicit MultiTouchInput(const WidgetMouseEvent& aMouseEvent);
WidgetTouchEvent ToWidgetTouchEvent(nsIWidget* aWidget) const;
WidgetMouseEvent ToWidgetMouseEvent(nsIWidget* aWidget) const;
// Return the index into mTouches of the SingleTouchData with the given
// identifier, or -1 if there is no such SingleTouchData.
int32_t IndexOfTouch(int32_t aTouchIdentifier);
bool TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform);
// Warning, this class is serialized and sent over IPC. Any change to its
// fields must be reflected in its ParamTraits<>, in nsGUIEventIPC.h
MultiTouchType mType;
nsTArray<SingleTouchData> mTouches;
bool mHandledByAPZ;
};
class MouseInput : public InputData
{
protected:
friend mozilla::layers::PAPZCTreeManagerParent;
friend mozilla::layers::APZCTreeManagerChild;
MouseInput();
public:
enum MouseType
{
// Warning, this enum is serialized and sent over IPC. If you reorder, add,
// or remove a value, you need to update its ParamTraits<> in nsGUIEventIPC.h
MOUSE_NONE,
MOUSE_MOVE,
MOUSE_DOWN,
MOUSE_UP,
MOUSE_DRAG_START,
MOUSE_DRAG_END,
MOUSE_WIDGET_ENTER,
MOUSE_WIDGET_EXIT,
// Used as an upper bound for ContiguousEnumSerializer
MOUSE_SENTINEL,
};
enum ButtonType
{
// Warning, this enum is serialized and sent over IPC. If you reorder, add,
// or remove a value, you need to update its ParamTraits<> in nsGUIEventIPC.h
LEFT_BUTTON,
MIDDLE_BUTTON,
RIGHT_BUTTON,
NONE,
// Used as an upper bound for ContiguousEnumSerializer
BUTTON_SENTINEL,
};
MouseInput(MouseType aType, ButtonType aButtonType, uint16_t aInputSource,
int16_t aButtons, const ScreenPoint& aPoint, uint32_t aTime,
TimeStamp aTimeStamp, Modifiers aModifiers);
explicit MouseInput(const WidgetMouseEventBase& aMouseEvent);
bool IsLeftButton() const;
bool TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform);
WidgetMouseEvent ToWidgetMouseEvent(nsIWidget* aWidget) const;
// Warning, this class is serialized and sent over IPC. Any change to its
// fields must be reflected in its ParamTraits<>, in nsGUIEventIPC.h
MouseType mType;
ButtonType mButtonType;
uint16_t mInputSource;
int16_t mButtons;
ScreenPoint mOrigin;
ParentLayerPoint mLocalOrigin;
bool mHandledByAPZ;
};
/**
* Encapsulation class for pan events, can be used off-main-thread.
* These events are currently only used for scrolling on desktop.
*/
class PanGestureInput : public InputData
{
protected:
friend mozilla::layers::PAPZCTreeManagerParent;
friend mozilla::layers::APZCTreeManagerChild;
PanGestureInput();
public:
enum PanGestureType
{
// Warning, this enum is serialized and sent over IPC. If you reorder, add,
// or remove a value, you need to update its ParamTraits<> in nsGUIEventIPC.h
// MayStart: Dispatched before any actual panning has occurred but when a
// pan gesture is probably about to start, for example when the user
// starts touching the touchpad. Should interrupt any ongoing APZ
// animation and can be used to trigger scrollability indicators (e.g.
// flashing overlay scrollbars).
PANGESTURE_MAYSTART,
// Cancelled: Dispatched after MayStart when no pan gesture is going to
// happen after all, for example when the user lifts their fingers from a
// touchpad without having done any scrolling.
PANGESTURE_CANCELLED,
// Start: A pan gesture is starting.
// For devices that do not support the MayStart event type, this event can
// be used to interrupt ongoing APZ animations.
PANGESTURE_START,
// Pan: The actual pan motion by mPanDisplacement.
PANGESTURE_PAN,
// End: The pan gesture has ended, for example because the user has lifted
// their fingers from a touchpad after scrolling.
// Any potential momentum events fire after this event.
PANGESTURE_END,
// The following momentum event types are used in order to control the pan
// momentum animation. Using these instead of our own animation ensures
// that the animation curve is OS native and that the animation stops
// reliably if it is cancelled by the user.
// MomentumStart: Dispatched between the End event of the actual
// user-controlled pan, and the first MomentumPan event of the momentum
// animation.
PANGESTURE_MOMENTUMSTART,
// MomentumPan: The actual momentum motion by mPanDisplacement.
PANGESTURE_MOMENTUMPAN,
// MomentumEnd: The momentum animation has ended, for example because the
// momentum velocity has gone below the stopping threshold, or because the
// user has stopped the animation by putting their fingers on a touchpad.
PANGESTURE_MOMENTUMEND,
// Used as an upper bound for ContiguousEnumSerializer
PANGESTURE_SENTINEL,
};
PanGestureInput(PanGestureType aType,
uint32_t aTime,
TimeStamp aTimeStamp,
const ScreenPoint& aPanStartPoint,
const ScreenPoint& aPanDisplacement,
Modifiers aModifiers);
bool IsMomentum() const;
WidgetWheelEvent ToWidgetWheelEvent(nsIWidget* aWidget) const;
bool TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform);
ScreenPoint UserMultipliedPanDisplacement() const;
ParentLayerPoint UserMultipliedLocalPanDisplacement() const;
// Warning, this class is serialized and sent over IPC. Any change to its
// fields must be reflected in its ParamTraits<>, in nsGUIEventIPC.h
PanGestureType mType;
ScreenPoint mPanStartPoint;
// The delta. This can be non-zero on any type of event.
ScreenPoint mPanDisplacement;
// Versions of |mPanStartPoint| and |mPanDisplacement| in the local
// coordinates of the APZC receiving the pan. These are set and used by APZ.
ParentLayerPoint mLocalPanStartPoint;
ParentLayerPoint mLocalPanDisplacement;
// See lineOrPageDeltaX/Y on WidgetWheelEvent.
int32_t mLineOrPageDeltaX;
int32_t mLineOrPageDeltaY;
// User-set delta multipliers.
double mUserDeltaMultiplierX;
double mUserDeltaMultiplierY;
bool mHandledByAPZ;
// true if this is a PANGESTURE_END event that will be followed by a
// PANGESTURE_MOMENTUMSTART event.
bool mFollowedByMomentum;
// If this is true, and this event started a new input block that couldn't
// find a scrollable target which is scrollable in the horizontal component
// of the scroll start direction, then this input block needs to be put on
// hold until a content response has arrived, even if the block has a
// confirmed target.
// This is used by events that can result in a swipe instead of a scroll.
bool mRequiresContentResponseIfCannotScrollHorizontallyInStartDirection;
};
/**
* Encapsulation class for pinch events. In general, these will be generated by
* a gesture listener by looking at SingleTouchData/MultiTouchInput instances and
* determining whether or not the user was trying to do a gesture.
*/
class PinchGestureInput : public InputData
{
protected:
friend mozilla::layers::PAPZCTreeManagerParent;
friend mozilla::layers::APZCTreeManagerChild;
PinchGestureInput();
public:
enum PinchGestureType
{
// Warning, this enum is serialized and sent over IPC. If you reorder, add,
// or remove a value, you need to update its ParamTraits<> in nsGUIEventIPC.h
PINCHGESTURE_START,
PINCHGESTURE_SCALE,
PINCHGESTURE_END,
// Used as an upper bound for ContiguousEnumSerializer
PINCHGESTURE_SENTINEL,
};
// Construct a pinch gesture from a ParentLayer point.
// mFocusPoint remains (0,0) unless it's set later.
PinchGestureInput(PinchGestureType aType, uint32_t aTime, TimeStamp aTimeStamp,
const ParentLayerPoint& aLocalFocusPoint,
ParentLayerCoord aCurrentSpan,
ParentLayerCoord aPreviousSpan, Modifiers aModifiers);
bool TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform);
// Warning, this class is serialized and sent over IPC. Any change to its
// fields must be reflected in its ParamTraits<>, in nsGUIEventIPC.h
PinchGestureType mType;
// Center point of the pinch gesture. That is, if there are two fingers on the
// screen, it is their midpoint. In the case of more than two fingers, the
// point is implementation-specific, but can for example be the midpoint
// between the very first and very last touch. This is in device pixels and
// are the coordinates on the screen of this midpoint.
// For PINCHGESTURE_END events, this instead will hold the coordinates of
// the remaining finger, if there is one. If there isn't one then it will
// store -1, -1.
ScreenPoint mFocusPoint;
// |mFocusPoint| transformed to the local coordinates of the APZC targeted
// by the hit. This is set and used by APZ.
ParentLayerPoint mLocalFocusPoint;
// The distance between the touches responsible for the pinch gesture.
ParentLayerCoord mCurrentSpan;
// The previous |mCurrentSpan| in the PinchGestureInput preceding this one.
// This is only really relevant during a PINCHGESTURE_SCALE because when it is
// of this type then there must have been a history of spans.
ParentLayerCoord mPreviousSpan;
};
/**
* Encapsulation class for tap events. In general, these will be generated by
* a gesture listener by looking at SingleTouchData/MultiTouchInput instances and
* determining whether or not the user was trying to do a gesture.
*/
class TapGestureInput : public InputData
{
protected:
friend mozilla::layers::PAPZCTreeManagerParent;
friend mozilla::layers::APZCTreeManagerChild;
TapGestureInput();
public:
enum TapGestureType
{
// Warning, this enum is serialized and sent over IPC. If you reorder, add,
// or remove a value, you need to update its ParamTraits<> in nsGUIEventIPC.h
TAPGESTURE_LONG,
TAPGESTURE_LONG_UP,
TAPGESTURE_UP,
TAPGESTURE_CONFIRMED,
TAPGESTURE_DOUBLE,
TAPGESTURE_SECOND, // See GeckoContentController::TapType::eSecondTap
TAPGESTURE_CANCEL,
// Used as an upper bound for ContiguousEnumSerializer
TAPGESTURE_SENTINEL,
};
// Construct a tap gesture from a Screen point.
// mLocalPoint remains (0,0) unless it's set later.
TapGestureInput(TapGestureType aType, uint32_t aTime, TimeStamp aTimeStamp,
const ScreenIntPoint& aPoint, Modifiers aModifiers);
// Construct a tap gesture from a ParentLayer point.
// mPoint remains (0,0) unless it's set later.
TapGestureInput(TapGestureType aType, uint32_t aTime, TimeStamp aTimeStamp,
const ParentLayerPoint& aLocalPoint, Modifiers aModifiers);
bool TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform);
// Warning, this class is serialized and sent over IPC. Any change to its
// fields must be reflected in its ParamTraits<>, in nsGUIEventIPC.h
TapGestureType mType;
// The location of the tap in screen pixels.
ScreenIntPoint mPoint;
// The location of the tap in the local coordinates of the APZC receiving it.
// This is set and used by APZ.
ParentLayerPoint mLocalPoint;
};
// Encapsulation class for scroll-wheel events. These are generated by mice
// with physical scroll wheels, and on Windows by most touchpads when using
// scroll gestures.
class ScrollWheelInput : public InputData
{
protected:
friend mozilla::layers::PAPZCTreeManagerParent;
friend mozilla::layers::APZCTreeManagerChild;
ScrollWheelInput();
public:
enum ScrollDeltaType
{
// Warning, this enum is serialized and sent over IPC. If you reorder, add,
// or remove a value, you need to update its ParamTraits<> in nsGUIEventIPC.h
// There are three kinds of scroll delta modes in Gecko: "page", "line" and
// "pixel".
SCROLLDELTA_LINE,
SCROLLDELTA_PAGE,
SCROLLDELTA_PIXEL,
// Used as an upper bound for ContiguousEnumSerializer
SCROLLDELTA_SENTINEL,
};
enum ScrollMode
{
// Warning, this enum is serialized and sent over IPC. If you reorder, add,
// or remove a value, you need to update its ParamTraits<> in nsGUIEventIPC.h
SCROLLMODE_INSTANT,
SCROLLMODE_SMOOTH,
// Used as an upper bound for ContiguousEnumSerializer
SCROLLMODE_SENTINEL,
};
ScrollWheelInput(uint32_t aTime, TimeStamp aTimeStamp, Modifiers aModifiers,
ScrollMode aScrollMode, ScrollDeltaType aDeltaType,
const ScreenPoint& aOrigin, double aDeltaX, double aDeltaY,
bool aAllowToOverrideSystemScrollSpeed);
explicit ScrollWheelInput(const WidgetWheelEvent& aEvent);
static ScrollDeltaType DeltaTypeForDeltaMode(uint32_t aDeltaMode);
static uint32_t DeltaModeForDeltaType(ScrollDeltaType aDeltaType);
static nsIScrollableFrame::ScrollUnit ScrollUnitForDeltaType(ScrollDeltaType aDeltaType);
WidgetWheelEvent ToWidgetWheelEvent(nsIWidget* aWidget) const;
bool TransformToLocal(const ScreenToParentLayerMatrix4x4& aTransform);
bool IsCustomizedByUserPrefs() const;
// Warning, this class is serialized and sent over IPC. Any change to its
// fields must be reflected in its ParamTraits<>, in nsGUIEventIPC.h
ScrollDeltaType mDeltaType;
ScrollMode mScrollMode;
ScreenPoint mOrigin;
bool mHandledByAPZ;
// Deltas are in units corresponding to the delta type. For line deltas, they
// are the number of line units to scroll. The number of device pixels for a
// horizontal and vertical line unit are in FrameMetrics::mLineScrollAmount.
// For pixel deltas, these values are in ScreenCoords.
//
// The horizontal (X) delta is > 0 for scrolling right and < 0 for scrolling
// left. The vertical (Y) delta is < 0 for scrolling up and > 0 for
// scrolling down.
double mDeltaX;
double mDeltaY;
// The location of the scroll in local coordinates. This is set and used by
// APZ.
ParentLayerPoint mLocalOrigin;
// See lineOrPageDeltaX/Y on WidgetWheelEvent.
int32_t mLineOrPageDeltaX;
int32_t mLineOrPageDeltaY;
// Indicates the order in which this event was added to a transaction. The
// first event is 1; if not a member of a transaction, this is 0.
uint32_t mScrollSeriesNumber;
// User-set delta multipliers.
double mUserDeltaMultiplierX;
double mUserDeltaMultiplierY;
bool mMayHaveMomentum;
bool mIsMomentum;
bool mAllowToOverrideSystemScrollSpeed;
};
} // namespace mozilla
#endif // InputData_h__

81
widget/LSBUtils.cpp Normal file
View file

@ -0,0 +1,81 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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 "LSBUtils.h"
#include <unistd.h>
#include "base/process_util.h"
namespace mozilla {
namespace widget {
namespace lsb {
static const char* gLsbReleasePath = "/usr/bin/lsb_release";
bool
GetLSBRelease(nsACString& aDistributor,
nsACString& aDescription,
nsACString& aRelease,
nsACString& aCodename)
{
if (access(gLsbReleasePath, R_OK) != 0)
return false;
int pipefd[2];
if (pipe(pipefd) == -1) {
NS_WARNING("pipe() failed!");
return false;
}
std::vector<std::string> argv = {
gLsbReleasePath, "-idrc"
};
std::vector<std::pair<int, int>> fdMap = {
{ pipefd[1], STDOUT_FILENO }
};
base::ProcessHandle process;
base::LaunchApp(argv, fdMap, true, &process);
close(pipefd[1]);
if (!process) {
NS_WARNING("Failed to spawn lsb_release!");
close(pipefd[0]);
return false;
}
FILE* stream = fdopen(pipefd[0], "r");
if (!stream) {
NS_WARNING("Could not wrap fd!");
close(pipefd[0]);
return false;
}
char dist[256], desc[256], release[256], codename[256];
if (fscanf(stream, "Distributor ID:\t%255[^\n]\n"
"Description:\t%255[^\n]\n"
"Release:\t%255[^\n]\n"
"Codename:\t%255[^\n]\n",
dist, desc, release, codename) != 4)
{
NS_WARNING("Failed to parse lsb_release!");
fclose(stream);
close(pipefd[0]);
return false;
}
fclose(stream);
close(pipefd[0]);
aDistributor.Assign(dist);
aDescription.Assign(desc);
aRelease.Assign(release);
aCodename.Assign(codename);
return true;
}
} // namespace lsb
} // namespace widget
} // namespace mozilla

28
widget/LSBUtils.h Normal file
View file

@ -0,0 +1,28 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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/. */
#ifndef _MOZILLA_WIDGET_LSB_UTILS_H
#define _MOZILLA_WIDGET_LSB_UTILS_H
#include "nsString.h"
namespace mozilla {
namespace widget {
namespace lsb {
// Fetches the LSB release data by parsing the lsb_release command.
// Returns false if the lsb_release command was not found, or parsing failed.
bool GetLSBRelease(nsACString& aDistributor,
nsACString& aDescription,
nsACString& aRelease,
nsACString& aCodename);
} // namespace lsb
} // namespace widget
} // namespace mozilla
#endif // _MOZILLA_WIDGET_LSB_UTILS_H

640
widget/LookAndFeel.h Normal file
View file

@ -0,0 +1,640 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef __LookAndFeel
#define __LookAndFeel
#ifndef MOZILLA_INTERNAL_API
#error "This header is only usable from within libxul (MOZILLA_INTERNAL_API)."
#endif
#include "nsDebug.h"
#include "nsColor.h"
#include "nsTArray.h"
struct gfxFontStyle;
struct LookAndFeelInt
{
int32_t id;
int32_t value;
};
namespace mozilla {
class LookAndFeel
{
public:
// When modifying this list, also modify nsXPLookAndFeel::sColorPrefs
// in widget/xpwidgts/nsXPLookAndFeel.cpp.
enum ColorID : uint8_t {
// WARNING : NO NEGATIVE VALUE IN THIS ENUMERATION
// see patch in bug 57757 for more information
eColorID_WindowBackground,
eColorID_WindowForeground,
eColorID_WidgetBackground,
eColorID_WidgetForeground,
eColorID_WidgetSelectBackground,
eColorID_WidgetSelectForeground,
eColorID_Widget3DHighlight,
eColorID_Widget3DShadow,
eColorID_TextBackground,
eColorID_TextForeground,
eColorID_TextSelectBackground,
eColorID_TextSelectForeground,
eColorID_TextSelectForegroundCustom,
eColorID_TextSelectBackgroundDisabled,
eColorID_TextSelectBackgroundAttention,
eColorID_TextHighlightBackground,
eColorID_TextHighlightForeground,
eColorID_IMERawInputBackground,
eColorID_IMERawInputForeground,
eColorID_IMERawInputUnderline,
eColorID_IMESelectedRawTextBackground,
eColorID_IMESelectedRawTextForeground,
eColorID_IMESelectedRawTextUnderline,
eColorID_IMEConvertedTextBackground,
eColorID_IMEConvertedTextForeground,
eColorID_IMEConvertedTextUnderline,
eColorID_IMESelectedConvertedTextBackground,
eColorID_IMESelectedConvertedTextForeground,
eColorID_IMESelectedConvertedTextUnderline,
eColorID_SpellCheckerUnderline,
// New CSS 2 color definitions
eColorID_activeborder,
eColorID_activecaption,
eColorID_appworkspace,
eColorID_background,
eColorID_buttonface,
eColorID_buttonhighlight,
eColorID_buttonshadow,
eColorID_buttontext,
eColorID_captiontext,
eColorID_graytext,
eColorID_highlight,
eColorID_highlighttext,
eColorID_inactiveborder,
eColorID_inactivecaption,
eColorID_inactivecaptiontext,
eColorID_infobackground,
eColorID_infotext,
eColorID_menu,
eColorID_menutext,
eColorID_scrollbar,
eColorID_threeddarkshadow,
eColorID_threedface,
eColorID_threedhighlight,
eColorID_threedlightshadow,
eColorID_threedshadow,
eColorID_window,
eColorID_windowframe,
eColorID_windowtext,
eColorID__moz_buttondefault,
// Colors which will hopefully become CSS3
eColorID__moz_field,
eColorID__moz_fieldtext,
eColorID__moz_dialog,
eColorID__moz_dialogtext,
// used to highlight valid regions to drop something onto
eColorID__moz_dragtargetzone,
// used to cell text background, selected but not focus
eColorID__moz_cellhighlight,
// used to cell text, selected but not focus
eColorID__moz_cellhighlighttext,
// used to html select cell text background, selected but not focus
eColorID__moz_html_cellhighlight,
// used to html select cell text, selected but not focus
eColorID__moz_html_cellhighlighttext,
// used to button text background, when mouse is over
eColorID__moz_buttonhoverface,
// used to button text, when mouse is over
eColorID__moz_buttonhovertext,
// used to menu item background, when mouse is over
eColorID__moz_menuhover,
// used to menu item text, when mouse is over
eColorID__moz_menuhovertext,
// used to menu bar item text
eColorID__moz_menubartext,
// used to menu bar item text, when mouse is over
eColorID__moz_menubarhovertext,
// On platforms where these colors are the same as
// -moz-field, use -moz-fieldtext as foreground color
eColorID__moz_eventreerow,
eColorID__moz_oddtreerow,
// colors needed by the Mac OS X theme
// foreground color of :hover:active buttons
eColorID__moz_mac_buttonactivetext,
// background color of chrome toolbars in active windows
eColorID__moz_mac_chrome_active,
// background color of chrome toolbars in inactive windows
eColorID__moz_mac_chrome_inactive,
// foreground color of default buttons
eColorID__moz_mac_defaultbuttontext,
//ring around text fields and lists
eColorID__moz_mac_focusring,
//colour used when mouse is over a menu item
eColorID__moz_mac_menuselect,
//colour used to do shadows on menu items
eColorID__moz_mac_menushadow,
// color used to display text for disabled menu items
eColorID__moz_mac_menutextdisable,
//colour used to display text while mouse is over a menu item
eColorID__moz_mac_menutextselect,
// text color of disabled text on toolbars
eColorID__moz_mac_disabledtoolbartext,
//inactive light hightlight
eColorID__moz_mac_secondaryhighlight,
// vista rebars
// media rebar text
eColorID__moz_win_mediatext,
// communications rebar text
eColorID__moz_win_communicationstext,
// Hyperlink color extracted from the system, not affected by the
// browser.anchor_color user pref.
// There is no OS-specified safe background color for this text,
// but it is used regularly within Windows and the Gnome DE on Dialog and
// Window colors.
eColorID__moz_nativehyperlinktext,
// Combo box widgets
eColorID__moz_comboboxtext,
eColorID__moz_combobox,
// GtkInfoBar
eColorID__moz_gtk_info_bar_text,
// keep this one last, please
eColorID_LAST_COLOR
};
// When modifying this list, also modify nsXPLookAndFeel::sIntPrefs
// in widget/xpwidgts/nsXPLookAndFeel.cpp.
enum IntID {
// default, may be overriden by OS
eIntID_CaretBlinkTime,
// pixel width of caret
eIntID_CaretWidth,
// show the caret when text is selected?
eIntID_ShowCaretDuringSelection,
// select textfields when focused via tab/accesskey?
eIntID_SelectTextfieldsOnKeyFocus,
// delay before submenus open
eIntID_SubmenuDelay,
// can popups overlap menu/task bar?
eIntID_MenusCanOverlapOSBar,
// should overlay scrollbars be used?
eIntID_UseOverlayScrollbars,
// allow H and V overlay scrollbars to overlap?
eIntID_AllowOverlayScrollbarsOverlap,
// show/hide scrollbars based on activity
eIntID_ShowHideScrollbars,
// skip navigating to disabled menu item?
eIntID_SkipNavigatingDisabledMenuItem,
// begin a drag if the mouse is moved further than the threshold while the
// button is down
eIntID_DragThresholdX,
eIntID_DragThresholdY,
// Accessibility theme being used?
eIntID_UseAccessibilityTheme,
// position of scroll arrows in a scrollbar
eIntID_ScrollArrowStyle,
// is scroll thumb proportional or fixed?
eIntID_ScrollSliderStyle,
// each button can take one of four values:
eIntID_ScrollButtonLeftMouseButtonAction,
// 0 - scrolls one line, 1 - scrolls one page
eIntID_ScrollButtonMiddleMouseButtonAction,
// 2 - scrolls to end, 3 - button ignored
eIntID_ScrollButtonRightMouseButtonAction,
// delay for opening spring loaded folders
eIntID_TreeOpenDelay,
// delay for closing spring loaded folders
eIntID_TreeCloseDelay,
// delay for triggering the tree scrolling
eIntID_TreeLazyScrollDelay,
// delay for scrolling the tree
eIntID_TreeScrollDelay,
// the maximum number of lines to be scrolled at ones
eIntID_TreeScrollLinesMax,
// What type of tab-order to use
eIntID_TabFocusModel,
// Should menu items blink when they're chosen?
eIntID_ChosenMenuItemsShouldBlink,
/*
* A Boolean value to determine whether the Windows default theme is
* being used.
*
* The value of this metric is not used on other platforms. These platforms
* should return NS_ERROR_NOT_IMPLEMENTED when queried for this metric.
*/
eIntID_WindowsDefaultTheme,
/*
* A Boolean value to determine whether the DWM compositor is being used
*
* This metric is not used on non-Windows platforms. These platforms
* should return NS_ERROR_NOT_IMPLEMENTED when queried for this metric.
*/
eIntID_DWMCompositor,
/*
* A Boolean value to determine whether Windows is themed (Classic vs.
* uxtheme)
*
* This is Windows-specific and is not implemented on other platforms
* (will return the default of NS_ERROR_FAILURE).
*/
eIntID_WindowsClassic,
/*
* A Boolean value to determine whether the current Windows desktop theme
* supports Aero Glass.
*
* This is Windows-specific and is not implemented on other platforms
* (will return the default of NS_ERROR_FAILURE).
*/
eIntID_WindowsGlass,
/*
* A Boolean value to determine whether the device is a touch enabled
* device. Currently this is only supported by the Windows 7 Touch API.
*
* Platforms that do not support this metric should return
* NS_ERROR_NOT_IMPLEMENTED when queried for this metric.
*/
eIntID_TouchEnabled,
/*
* A Boolean value to determine whether the Mac graphite theme is
* being used.
*
* The value of this metric is not used on other platforms. These platforms
* should return NS_ERROR_NOT_IMPLEMENTED when queried for this metric.
*/
eIntID_MacGraphiteTheme,
/*
* A Boolean value to determine whether the Mac OS X Yosemite-specific theming
* should be used.
*
* The value of this metric is not used on non-Mac platforms. These
* platforms should return NS_ERROR_NOT_IMPLEMENTED when queried for this
* metric.
*/
eIntID_MacYosemiteTheme,
/*
* eIntID_AlertNotificationOrigin indicates from which corner of the
* screen alerts slide in, and from which direction (horizontal/vertical).
* 0, the default, represents bottom right, sliding vertically.
* Use any bitwise combination of the following constants:
* NS_ALERT_HORIZONTAL (1), NS_ALERT_LEFT (2), NS_ALERT_TOP (4).
*
* 6 4
* +-----------+
* 7| |5
* | |
* 3| |1
* +-----------+
* 2 0
*/
eIntID_AlertNotificationOrigin,
/**
* If true, clicking on a scrollbar (not as in dragging the thumb) defaults
* to scrolling the view corresponding to the clicked point. Otherwise, we
* only do so if the scrollbar is clicked using the middle mouse button or
* if shift is pressed when the scrollbar is clicked.
*/
eIntID_ScrollToClick,
/**
* IME and spell checker underline styles, the values should be
* NS_DECORATION_LINE_STYLE_*. They are defined below.
*/
eIntID_IMERawInputUnderlineStyle,
eIntID_IMESelectedRawTextUnderlineStyle,
eIntID_IMEConvertedTextUnderlineStyle,
eIntID_IMESelectedConvertedTextUnderline,
eIntID_SpellCheckerUnderlineStyle,
/**
* If this metric != 0, support window dragging on the menubar.
*/
eIntID_MenuBarDrag,
/**
* Return the appropriate WindowsThemeIdentifier for the current theme.
*/
eIntID_WindowsThemeIdentifier,
/**
* Return an appropriate os version identifier.
*/
eIntID_OperatingSystemVersionIdentifier,
/**
* 0: scrollbar button repeats to scroll only when cursor is on the button.
* 1: scrollbar button repeats to scroll even if cursor is outside of it.
*/
eIntID_ScrollbarButtonAutoRepeatBehavior,
/**
* Delay before showing a tooltip.
*/
eIntID_TooltipDelay,
/*
* A Boolean value to determine whether Mac OS X Lion style swipe animations
* should be used.
*/
eIntID_SwipeAnimationEnabled,
/*
* A Boolean value to determine whether we have a color picker available
* for <input type="color"> to hook into.
*
* This lets us selectively enable the style for <input type="color">
* based on whether it's functional or not.
*/
eIntID_ColorPickerAvailable,
/*
* A boolean value indicating whether or not the device has a hardware
* home button. Used on gaia to determine whether a home button
* is shown.
*/
eIntID_PhysicalHomeButton,
/*
* Controls whether overlay scrollbars display when the user moves
* the mouse in a scrollable frame.
*/
eIntID_ScrollbarDisplayOnMouseMove,
/*
* Overlay scrollbar animation constants.
*/
eIntID_ScrollbarFadeBeginDelay,
eIntID_ScrollbarFadeDuration,
/**
* Distance in pixels to offset the context menu from the cursor
* on open.
*/
eIntID_ContextMenuOffsetVertical,
eIntID_ContextMenuOffsetHorizontal
};
/**
* Windows themes we currently detect.
*/
enum WindowsTheme {
eWindowsTheme_Generic = 0, // unrecognized theme
eWindowsTheme_Classic,
eWindowsTheme_Aero,
eWindowsTheme_LunaBlue,
eWindowsTheme_LunaOlive,
eWindowsTheme_LunaSilver,
eWindowsTheme_Royale,
eWindowsTheme_Zune,
eWindowsTheme_AeroLite
};
/**
* Operating system versions.
*/
enum OperatingSystemVersion {
eOperatingSystemVersion_WindowsXP = 0,
eOperatingSystemVersion_WindowsVista,
eOperatingSystemVersion_Windows7,
eOperatingSystemVersion_Windows8,
eOperatingSystemVersion_Windows10,
eOperatingSystemVersion_Unknown
};
enum {
eScrollArrow_None = 0,
eScrollArrow_StartBackward = 0x1000,
eScrollArrow_StartForward = 0x0100,
eScrollArrow_EndBackward = 0x0010,
eScrollArrow_EndForward = 0x0001
};
enum {
// single arrow at each end
eScrollArrowStyle_Single =
eScrollArrow_StartBackward | eScrollArrow_EndForward,
// both arrows at bottom/right, none at top/left
eScrollArrowStyle_BothAtBottom =
eScrollArrow_EndBackward | eScrollArrow_EndForward,
// both arrows at both ends
eScrollArrowStyle_BothAtEachEnd =
eScrollArrow_EndBackward | eScrollArrow_EndForward |
eScrollArrow_StartBackward | eScrollArrow_StartForward,
// both arrows at top/left, none at bottom/right
eScrollArrowStyle_BothAtTop =
eScrollArrow_StartBackward | eScrollArrow_StartForward
};
enum {
eScrollThumbStyle_Normal,
eScrollThumbStyle_Proportional
};
// When modifying this list, also modify nsXPLookAndFeel::sFloatPrefs
// in widget/xpwidgts/nsXPLookAndFeel.cpp.
enum FloatID {
eFloatID_IMEUnderlineRelativeSize,
eFloatID_SpellCheckerUnderlineRelativeSize,
// The width/height ratio of the cursor. If used, the CaretWidth int metric
// should be added to the calculated caret width.
eFloatID_CaretAspectRatio
};
// These constants must be kept in 1:1 correspondence with the
// NS_STYLE_FONT_* system font constants.
enum FontID {
eFont_Caption = 1, // css2
eFont_Icon,
eFont_Menu,
eFont_MessageBox,
eFont_SmallCaption,
eFont_StatusBar,
eFont_Window, // css3
eFont_Document,
eFont_Workspace,
eFont_Desktop,
eFont_Info,
eFont_Dialog,
eFont_Button,
eFont_PullDownMenu,
eFont_List,
eFont_Field,
eFont_Tooltips, // moz
eFont_Widget
};
/**
* GetColor() return a native color value (might be overwritten by prefs) for
* aID. Some platforms don't return an error even if the index doesn't
* match any system colors. And also some platforms may initialize the
* return value even when it returns an error. Therefore, if you want to
* use a color for the default value, you should use the other GetColor()
* which returns nscolor directly.
*
* NOTE:
* eColorID_TextSelectForeground might return NS_DONT_CHANGE_COLOR.
* eColorID_IME* might return NS_TRANSPARENT, NS_SAME_AS_FOREGROUND_COLOR or
* NS_40PERCENT_FOREGROUND_COLOR.
* These values have particular meaning. Then, they are not an actual
* color value.
*/
static nsresult GetColor(ColorID aID, nscolor* aResult);
/**
* This variant of GetColor() takes an extra Boolean parameter that allows
* the caller to ask that hard-coded color values be substituted for
* native colors (used when it is desireable to hide system colors to
* avoid system fingerprinting).
*/
static nsresult GetColor(ColorID aID, bool aUseStandinsForNativeColors,
nscolor* aResult);
/**
* GetInt() and GetFloat() return a int or float value for aID. The result
* might be distance, time, some flags or a int value which has particular
* meaning. See each document at definition of each ID for the detail.
* The result is always 0 when they return error. Therefore, if you want to
* use a value for the default value, you should use the other method which
* returns int or float directly.
*/
static nsresult GetInt(IntID aID, int32_t* aResult);
static nsresult GetFloat(FloatID aID, float* aResult);
static nscolor GetColor(ColorID aID, nscolor aDefault = NS_RGB(0, 0, 0))
{
nscolor result = NS_RGB(0, 0, 0);
if (NS_FAILED(GetColor(aID, &result))) {
return aDefault;
}
return result;
}
static int32_t GetInt(IntID aID, int32_t aDefault = 0)
{
int32_t result;
if (NS_FAILED(GetInt(aID, &result))) {
return aDefault;
}
return result;
}
static float GetFloat(FloatID aID, float aDefault = 0.0f)
{
float result;
if (NS_FAILED(GetFloat(aID, &result))) {
return aDefault;
}
return result;
}
/**
* Retrieve the name and style of a system-theme font. Returns true
* if the system theme specifies this font, false if a default should
* be used. In the latter case neither aName nor aStyle is modified.
*
* @param aID Which system-theme font is wanted.
* @param aName The name of the font to use.
* @param aStyle Styling to apply to the font.
* @param aDevPixPerCSSPixel Ratio of device pixels to CSS pixels
*/
static bool GetFont(FontID aID, nsString& aName, gfxFontStyle& aStyle,
float aDevPixPerCSSPixel);
/**
* GetPasswordCharacter() returns a unicode character which should be used
* for a masked character in password editor. E.g., '*'.
*/
static char16_t GetPasswordCharacter();
/**
* If the latest character in password field shouldn't be hidden by the
* result of GetPasswordCharacter(), GetEchoPassword() returns TRUE.
* Otherwise, FALSE.
*/
static bool GetEchoPassword();
/**
* The millisecond to mask password value.
* This value is only valid when GetEchoPassword() returns true.
*/
static uint32_t GetPasswordMaskDelay();
/**
* When system look and feel is changed, Refresh() must be called. Then,
* cached data would be released.
*/
static void Refresh();
/**
* If the implementation is caching values, these accessors allow the
* cache to be exported and imported.
*/
static nsTArray<LookAndFeelInt> GetIntCache();
static void SetIntCache(const nsTArray<LookAndFeelInt>& aLookAndFeelIntCache);
};
} // namespace mozilla
// On the Mac, GetColor(eColorID_TextSelectForeground, color) returns this
// constant to specify that the foreground color should not be changed
// (ie. a colored text keeps its colors when selected).
// Of course if other plaforms work like the Mac, they can use it too.
#define NS_DONT_CHANGE_COLOR NS_RGB(0x01, 0x01, 0x01)
// Similar with NS_DONT_CHANGE_COLOR, except NS_DONT_CHANGE_COLOR would returns
// complementary color if fg color is same as bg color.
// NS_CHANGE_COLOR_IF_SAME_AS_BG would returns eColorID_TextSelectForegroundCustom if
// fg and bg color are the same.
#define NS_CHANGE_COLOR_IF_SAME_AS_BG NS_RGB(0x02, 0x02, 0x02)
// ---------------------------------------------------------------------
// Special colors for eColorID_IME* and eColorID_SpellCheckerUnderline
// ---------------------------------------------------------------------
// For background color only.
#define NS_TRANSPARENT NS_RGBA(0x01, 0x00, 0x00, 0x00)
// For foreground color only.
#define NS_SAME_AS_FOREGROUND_COLOR NS_RGBA(0x02, 0x00, 0x00, 0x00)
#define NS_40PERCENT_FOREGROUND_COLOR NS_RGBA(0x03, 0x00, 0x00, 0x00)
#define NS_IS_SELECTION_SPECIAL_COLOR(c) ((c) == NS_TRANSPARENT || \
(c) == NS_SAME_AS_FOREGROUND_COLOR || \
(c) == NS_40PERCENT_FOREGROUND_COLOR)
// ------------------------------------------
// Bits for eIntID_AlertNotificationOrigin
// ------------------------------------------
#define NS_ALERT_HORIZONTAL 1
#define NS_ALERT_LEFT 2
#define NS_ALERT_TOP 4
#endif /* __LookAndFeel */

196
widget/MiscEvents.h Normal file
View file

@ -0,0 +1,196 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_MiscEvents_h__
#define mozilla_MiscEvents_h__
#include <stdint.h>
#include "mozilla/BasicEvents.h"
#include "nsCOMPtr.h"
#include "nsIAtom.h"
#include "nsITransferable.h"
namespace mozilla {
namespace dom {
class PBrowserParent;
class PBrowserChild;
} // namespace dom
/******************************************************************************
* mozilla::WidgetContentCommandEvent
******************************************************************************/
class WidgetContentCommandEvent : public WidgetGUIEvent
{
public:
virtual WidgetContentCommandEvent* AsContentCommandEvent() override
{
return this;
}
WidgetContentCommandEvent(bool aIsTrusted, EventMessage aMessage,
nsIWidget* aWidget,
bool aOnlyEnabledCheck = false)
: WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eContentCommandEventClass)
, mOnlyEnabledCheck(aOnlyEnabledCheck)
, mSucceeded(false)
, mIsEnabled(false)
{
}
virtual WidgetEvent* Duplicate() const override
{
// This event isn't an internal event of any DOM event.
NS_ASSERTION(!IsAllowedToDispatchDOMEvent(),
"WidgetQueryContentEvent needs to support Duplicate()");
MOZ_CRASH("WidgetQueryContentEvent doesn't support Duplicate()");
return nullptr;
}
// eContentCommandPasteTransferable
nsCOMPtr<nsITransferable> mTransferable; // [in]
// eContentCommandScroll
// for mScroll.mUnit
enum
{
eCmdScrollUnit_Line,
eCmdScrollUnit_Page,
eCmdScrollUnit_Whole
};
struct ScrollInfo
{
ScrollInfo() :
mAmount(0), mUnit(eCmdScrollUnit_Line), mIsHorizontal(false)
{
}
int32_t mAmount; // [in]
uint8_t mUnit; // [in]
bool mIsHorizontal; // [in]
} mScroll;
bool mOnlyEnabledCheck; // [in]
bool mSucceeded; // [out]
bool mIsEnabled; // [out]
void AssignContentCommandEventData(const WidgetContentCommandEvent& aEvent,
bool aCopyTargets)
{
AssignGUIEventData(aEvent, aCopyTargets);
mScroll = aEvent.mScroll;
mOnlyEnabledCheck = aEvent.mOnlyEnabledCheck;
mSucceeded = aEvent.mSucceeded;
mIsEnabled = aEvent.mIsEnabled;
}
};
/******************************************************************************
* mozilla::WidgetCommandEvent
*
* This sends a command to chrome. If you want to request what is performed
* in focused content, you should use WidgetContentCommandEvent instead.
*
* XXX Should be |WidgetChromeCommandEvent|?
******************************************************************************/
class WidgetCommandEvent : public WidgetGUIEvent
{
public:
virtual WidgetCommandEvent* AsCommandEvent() override { return this; }
WidgetCommandEvent(bool aIsTrusted, nsIAtom* aEventType,
nsIAtom* aCommand, nsIWidget* aWidget)
: WidgetGUIEvent(aIsTrusted, eUnidentifiedEvent, aWidget,
eCommandEventClass)
, mCommand(aCommand)
{
mSpecifiedEventType = aEventType;
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eCommandEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
WidgetCommandEvent* result =
new WidgetCommandEvent(false, mSpecifiedEventType, mCommand, nullptr);
result->AssignCommandEventData(*this, true);
result->mFlags = mFlags;
return result;
}
nsCOMPtr<nsIAtom> mCommand;
// XXX Not tested by test_assign_event_data.html
void AssignCommandEventData(const WidgetCommandEvent& aEvent,
bool aCopyTargets)
{
AssignGUIEventData(aEvent, aCopyTargets);
// mCommand must have been initialized with the constructor.
}
};
/******************************************************************************
* mozilla::WidgetPluginEvent
*
* This event delivers only a native event to focused plugin.
******************************************************************************/
class WidgetPluginEvent : public WidgetGUIEvent
{
private:
friend class dom::PBrowserParent;
friend class dom::PBrowserChild;
public:
virtual WidgetPluginEvent* AsPluginEvent() override { return this; }
WidgetPluginEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget)
: WidgetGUIEvent(aIsTrusted, aMessage, aWidget, ePluginEventClass)
, mRetargetToFocusedDocument(false)
{
}
virtual WidgetEvent* Duplicate() const override
{
// NOTE: PluginEvent has to be dispatched to nsIFrame::HandleEvent().
// So, this event needs to support Duplicate().
MOZ_ASSERT(mClass == ePluginEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
WidgetPluginEvent* result = new WidgetPluginEvent(false, mMessage, nullptr);
result->AssignPluginEventData(*this, true);
result->mFlags = mFlags;
return result;
}
// If true, this event needs to be retargeted to focused document.
// Otherwise, never retargeted. Defaults to false.
bool mRetargetToFocusedDocument;
void AssignPluginEventData(const WidgetPluginEvent& aEvent,
bool aCopyTargets)
{
AssignGUIEventData(aEvent, aCopyTargets);
mRetargetToFocusedDocument = aEvent.mRetargetToFocusedDocument;
}
protected:
WidgetPluginEvent()
{
}
};
} // namespace mozilla
#endif // mozilla_MiscEvents_h__

724
widget/MouseEvents.h Normal file
View file

@ -0,0 +1,724 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_MouseEvents_h__
#define mozilla_MouseEvents_h__
#include <stdint.h>
#include "mozilla/BasicEvents.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/dom/DataTransfer.h"
#include "nsCOMPtr.h"
#include "nsIDOMMouseEvent.h"
#include "nsIDOMWheelEvent.h"
/******************************************************************************
* nsDragDropEventStatus
******************************************************************************/
enum nsDragDropEventStatus
{
// The event is a enter
nsDragDropEventStatus_eDragEntered,
// The event is exit
nsDragDropEventStatus_eDragExited,
// The event is drop
nsDragDropEventStatus_eDrop
};
namespace mozilla {
namespace dom {
class PBrowserParent;
class PBrowserChild;
} // namespace dom
/******************************************************************************
* mozilla::WidgetPointerHelper
******************************************************************************/
class WidgetPointerHelper
{
public:
bool convertToPointer;
uint32_t pointerId;
uint32_t tiltX;
uint32_t tiltY;
bool retargetedByPointerCapture;
WidgetPointerHelper() : convertToPointer(true), pointerId(0), tiltX(0), tiltY(0),
retargetedByPointerCapture(false) {}
void AssignPointerHelperData(const WidgetPointerHelper& aEvent)
{
convertToPointer = aEvent.convertToPointer;
pointerId = aEvent.pointerId;
tiltX = aEvent.tiltX;
tiltY = aEvent.tiltY;
retargetedByPointerCapture = aEvent.retargetedByPointerCapture;
}
};
/******************************************************************************
* mozilla::WidgetMouseEventBase
******************************************************************************/
class WidgetMouseEventBase : public WidgetInputEvent
{
private:
friend class dom::PBrowserParent;
friend class dom::PBrowserChild;
protected:
WidgetMouseEventBase()
: button(0)
, buttons(0)
, pressure(0)
, hitCluster(false)
, inputSource(nsIDOMMouseEvent::MOZ_SOURCE_MOUSE)
{
}
WidgetMouseEventBase(bool aIsTrusted, EventMessage aMessage,
nsIWidget* aWidget, EventClassID aEventClassID)
: WidgetInputEvent(aIsTrusted, aMessage, aWidget, aEventClassID)
, button(0)
, buttons(0)
, pressure(0)
, hitCluster(false)
, inputSource(nsIDOMMouseEvent::MOZ_SOURCE_MOUSE)
{
}
public:
virtual WidgetMouseEventBase* AsMouseEventBase() override { return this; }
virtual WidgetEvent* Duplicate() const override
{
MOZ_CRASH("WidgetMouseEventBase must not be most-subclass");
}
/// The possible related target
nsCOMPtr<nsISupports> relatedTarget;
enum buttonType
{
eLeftButton = 0,
eMiddleButton = 1,
eRightButton = 2
};
// Pressed button ID of mousedown or mouseup event.
// This is set only when pressing a button causes the event.
int16_t button;
enum buttonsFlag {
eNoButtonFlag = 0x00,
eLeftButtonFlag = 0x01,
eRightButtonFlag = 0x02,
eMiddleButtonFlag = 0x04,
// typicall, "back" button being left side of 5-button
// mice, see "buttons" attribute document of DOM3 Events.
e4thButtonFlag = 0x08,
// typicall, "forward" button being right side of 5-button
// mice, see "buttons" attribute document of DOM3 Events.
e5thButtonFlag = 0x10
};
// Flags of all pressed buttons at the event fired.
// This is set at any mouse event, don't be confused with |button|.
int16_t buttons;
// Finger or touch pressure of event. It ranges between 0.0 and 1.0.
float pressure;
// Touch near a cluster of links (true)
bool hitCluster;
// Possible values at nsIDOMMouseEvent
uint16_t inputSource;
// ID of the canvas HitRegion
nsString region;
bool IsLeftButtonPressed() const { return !!(buttons & eLeftButtonFlag); }
bool IsRightButtonPressed() const { return !!(buttons & eRightButtonFlag); }
bool IsMiddleButtonPressed() const { return !!(buttons & eMiddleButtonFlag); }
bool Is4thButtonPressed() const { return !!(buttons & e4thButtonFlag); }
bool Is5thButtonPressed() const { return !!(buttons & e5thButtonFlag); }
void AssignMouseEventBaseData(const WidgetMouseEventBase& aEvent,
bool aCopyTargets)
{
AssignInputEventData(aEvent, aCopyTargets);
relatedTarget = aCopyTargets ? aEvent.relatedTarget : nullptr;
button = aEvent.button;
buttons = aEvent.buttons;
pressure = aEvent.pressure;
hitCluster = aEvent.hitCluster;
inputSource = aEvent.inputSource;
}
/**
* Returns true if left click event.
*/
bool IsLeftClickEvent() const
{
return mMessage == eMouseClick && button == eLeftButton;
}
};
/******************************************************************************
* mozilla::WidgetMouseEvent
******************************************************************************/
class WidgetMouseEvent : public WidgetMouseEventBase
, public WidgetPointerHelper
{
private:
friend class dom::PBrowserParent;
friend class dom::PBrowserChild;
public:
typedef bool ReasonType;
enum Reason : ReasonType
{
eReal,
eSynthesized
};
typedef bool ContextMenuTriggerType;
enum ContextMenuTrigger : ContextMenuTriggerType
{
eNormal,
eContextMenuKey
};
typedef bool ExitFromType;
enum ExitFrom : ExitFromType
{
eChild,
eTopLevel
};
protected:
WidgetMouseEvent()
: mReason(eReal)
, mContextMenuTrigger(eNormal)
, mExitFrom(eChild)
, mIgnoreRootScrollFrame(false)
, mClickCount(0)
{
}
WidgetMouseEvent(bool aIsTrusted,
EventMessage aMessage,
nsIWidget* aWidget,
EventClassID aEventClassID,
Reason aReason)
: WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, aEventClassID)
, mReason(aReason)
, mContextMenuTrigger(eNormal)
, mExitFrom(eChild)
, mIgnoreRootScrollFrame(false)
, mClickCount(0)
{
}
public:
virtual WidgetMouseEvent* AsMouseEvent() override { return this; }
WidgetMouseEvent(bool aIsTrusted,
EventMessage aMessage,
nsIWidget* aWidget,
Reason aReason,
ContextMenuTrigger aContextMenuTrigger = eNormal)
: WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, eMouseEventClass)
, mReason(aReason)
, mContextMenuTrigger(aContextMenuTrigger)
, mExitFrom(eChild)
, mIgnoreRootScrollFrame(false)
, mClickCount(0)
{
if (aMessage == eContextMenu) {
button = (mContextMenuTrigger == eNormal) ? eRightButton : eLeftButton;
}
}
#ifdef DEBUG
virtual ~WidgetMouseEvent()
{
NS_WARNING_ASSERTION(
mMessage != eContextMenu ||
button == ((mContextMenuTrigger == eNormal) ? eRightButton : eLeftButton),
"Wrong button set to eContextMenu event?");
}
#endif
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eMouseEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
WidgetMouseEvent* result =
new WidgetMouseEvent(false, mMessage, nullptr,
mReason, mContextMenuTrigger);
result->AssignMouseEventData(*this, true);
result->mFlags = mFlags;
return result;
}
// mReason indicates the reason why the event is fired:
// - Representing mouse operation.
// - Synthesized for emulating mousemove event when the content under the
// mouse cursor is scrolled.
Reason mReason;
// mContextMenuTrigger is valid only when mMessage is eContextMenu.
// This indicates if the context menu event is caused by context menu key or
// other reasons (typically, a click of right mouse button).
ContextMenuTrigger mContextMenuTrigger;
// mExitFrom is valid only when mMessage is eMouseExitFromWidget.
// This indicates if the mouse cursor exits from a top level widget or
// a child widget.
ExitFrom mExitFrom;
// Whether the event should ignore scroll frame bounds during dispatch.
bool mIgnoreRootScrollFrame;
// mClickCount may be non-zero value when mMessage is eMouseDown, eMouseUp,
// eMouseClick or eMouseDoubleClick. The number is count of mouse clicks.
// Otherwise, this must be 0.
uint32_t mClickCount;
void AssignMouseEventData(const WidgetMouseEvent& aEvent, bool aCopyTargets)
{
AssignMouseEventBaseData(aEvent, aCopyTargets);
AssignPointerHelperData(aEvent);
mIgnoreRootScrollFrame = aEvent.mIgnoreRootScrollFrame;
mClickCount = aEvent.mClickCount;
}
/**
* Returns true if the event is a context menu event caused by key.
*/
bool IsContextMenuKeyEvent() const
{
return mMessage == eContextMenu && mContextMenuTrigger == eContextMenuKey;
}
/**
* Returns true if the event is a real mouse event. Otherwise, i.e., it's
* a synthesized event by scroll or something, returns false.
*/
bool IsReal() const
{
return mReason == eReal;
}
};
/******************************************************************************
* mozilla::WidgetDragEvent
******************************************************************************/
class WidgetDragEvent : public WidgetMouseEvent
{
private:
friend class mozilla::dom::PBrowserParent;
friend class mozilla::dom::PBrowserChild;
protected:
WidgetDragEvent()
: mUserCancelled(false)
, mDefaultPreventedOnContent(false)
{
}
public:
virtual WidgetDragEvent* AsDragEvent() override { return this; }
WidgetDragEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget)
: WidgetMouseEvent(aIsTrusted, aMessage, aWidget, eDragEventClass, eReal)
, mUserCancelled(false)
, mDefaultPreventedOnContent(false)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eDragEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
WidgetDragEvent* result = new WidgetDragEvent(false, mMessage, nullptr);
result->AssignDragEventData(*this, true);
result->mFlags = mFlags;
return result;
}
// The dragging data.
nsCOMPtr<dom::DataTransfer> mDataTransfer;
// If this is true, user has cancelled the drag operation.
bool mUserCancelled;
// If this is true, the drag event's preventDefault() is called on content.
bool mDefaultPreventedOnContent;
// XXX Not tested by test_assign_event_data.html
void AssignDragEventData(const WidgetDragEvent& aEvent, bool aCopyTargets)
{
AssignMouseEventData(aEvent, aCopyTargets);
mDataTransfer = aEvent.mDataTransfer;
// XXX mUserCancelled isn't copied, is this intentionally?
mUserCancelled = false;
mDefaultPreventedOnContent = aEvent.mDefaultPreventedOnContent;
}
};
/******************************************************************************
* mozilla::WidgetMouseScrollEvent
*
* This is used for legacy DOM mouse scroll events, i.e.,
* DOMMouseScroll and MozMousePixelScroll event. These events are NOT hanbled
* by ESM even if widget dispatches them. Use new WidgetWheelEvent instead.
******************************************************************************/
class WidgetMouseScrollEvent : public WidgetMouseEventBase
{
private:
WidgetMouseScrollEvent()
: mDelta(0)
, mIsHorizontal(false)
{
}
public:
virtual WidgetMouseScrollEvent* AsMouseScrollEvent() override
{
return this;
}
WidgetMouseScrollEvent(bool aIsTrusted, EventMessage aMessage,
nsIWidget* aWidget)
: WidgetMouseEventBase(aIsTrusted, aMessage, aWidget,
eMouseScrollEventClass)
, mDelta(0)
, mIsHorizontal(false)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eMouseScrollEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
WidgetMouseScrollEvent* result =
new WidgetMouseScrollEvent(false, mMessage, nullptr);
result->AssignMouseScrollEventData(*this, true);
result->mFlags = mFlags;
return result;
}
// The delta value of mouse scroll event.
// If the event message is eLegacyMouseLineOrPageScroll, the value indicates
// scroll amount in lines. However, if the value is
// nsIDOMUIEvent::SCROLL_PAGE_UP or nsIDOMUIEvent::SCROLL_PAGE_DOWN, the
// value inducates one page scroll. If the event message is
// eLegacyMousePixelScroll, the value indicates scroll amount in pixels.
int32_t mDelta;
// If this is true, it may cause to scroll horizontally.
// Otherwise, vertically.
bool mIsHorizontal;
void AssignMouseScrollEventData(const WidgetMouseScrollEvent& aEvent,
bool aCopyTargets)
{
AssignMouseEventBaseData(aEvent, aCopyTargets);
mDelta = aEvent.mDelta;
mIsHorizontal = aEvent.mIsHorizontal;
}
};
/******************************************************************************
* mozilla::WidgetWheelEvent
******************************************************************************/
class WidgetWheelEvent : public WidgetMouseEventBase
{
private:
friend class mozilla::dom::PBrowserParent;
friend class mozilla::dom::PBrowserChild;
WidgetWheelEvent()
: mDeltaX(0.0)
, mDeltaY(0.0)
, mDeltaZ(0.0)
, mOverflowDeltaX(0.0)
, mOverflowDeltaY(0.0)
, mDeltaMode(nsIDOMWheelEvent::DOM_DELTA_PIXEL)
, mLineOrPageDeltaX(0)
, mLineOrPageDeltaY(0)
, mScrollType(SCROLL_DEFAULT)
, mCustomizedByUserPrefs(false)
, mIsMomentum(false)
, mIsNoLineOrPageDelta(false)
, mViewPortIsOverscrolled(false)
, mCanTriggerSwipe(false)
, mAllowToOverrideSystemScrollSpeed(false)
{
}
public:
virtual WidgetWheelEvent* AsWheelEvent() override { return this; }
WidgetWheelEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget)
: WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, eWheelEventClass)
, mDeltaX(0.0)
, mDeltaY(0.0)
, mDeltaZ(0.0)
, mOverflowDeltaX(0.0)
, mOverflowDeltaY(0.0)
, mDeltaMode(nsIDOMWheelEvent::DOM_DELTA_PIXEL)
, mLineOrPageDeltaX(0)
, mLineOrPageDeltaY(0)
, mScrollType(SCROLL_DEFAULT)
, mCustomizedByUserPrefs(false)
, mMayHaveMomentum(false)
, mIsMomentum(false)
, mIsNoLineOrPageDelta(false)
, mViewPortIsOverscrolled(false)
, mCanTriggerSwipe(false)
, mAllowToOverrideSystemScrollSpeed(true)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eWheelEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
WidgetWheelEvent* result = new WidgetWheelEvent(false, mMessage, nullptr);
result->AssignWheelEventData(*this, true);
result->mFlags = mFlags;
return result;
}
// On OS X, scroll gestures that start at the edge of the scrollable range
// can result in a swipe gesture. For the first wheel event of such a
// gesture, call TriggersSwipe() after the event has been processed
// in order to find out whether a swipe should be started.
bool TriggersSwipe() const
{
return mCanTriggerSwipe && mViewPortIsOverscrolled &&
this->mOverflowDeltaX != 0.0;
}
// NOTE: mDeltaX, mDeltaY and mDeltaZ may be customized by
// mousewheel.*.delta_multiplier_* prefs which are applied by
// EventStateManager. So, after widget dispatches this event,
// these delta values may have different values than before.
double mDeltaX;
double mDeltaY;
double mDeltaZ;
// overflowed delta values for scroll, these values are set by
// nsEventStateManger. If the default action of the wheel event isn't scroll,
// these values always zero. Otherwise, remaning delta values which are
// not used by scroll are set.
// NOTE: mDeltaX, mDeltaY and mDeltaZ may be modified by EventStateManager.
// However, mOverflowDeltaX and mOverflowDeltaY indicate unused original
// delta values which are not applied the delta_multiplier prefs.
// So, if widget wanted to know the actual direction to be scrolled,
// it would need to check the mDeltaX and mDeltaY.
double mOverflowDeltaX;
double mOverflowDeltaY;
// Should be one of nsIDOMWheelEvent::DOM_DELTA_*
uint32_t mDeltaMode;
// If widget sets mLineOrPageDelta, EventStateManager will dispatch
// eLegacyMouseLineOrPageScroll event for compatibility. Note that the delta
// value means pages if the mDeltaMode is DOM_DELTA_PAGE, otherwise, lines.
int32_t mLineOrPageDeltaX;
int32_t mLineOrPageDeltaY;
// When the default action for an wheel event is moving history or zooming,
// need to chose a delta value for doing it.
int32_t GetPreferredIntDelta()
{
if (!mLineOrPageDeltaX && !mLineOrPageDeltaY) {
return 0;
}
if (mLineOrPageDeltaY && !mLineOrPageDeltaX) {
return mLineOrPageDeltaY;
}
if (mLineOrPageDeltaX && !mLineOrPageDeltaY) {
return mLineOrPageDeltaX;
}
if ((mLineOrPageDeltaX < 0 && mLineOrPageDeltaY > 0) ||
(mLineOrPageDeltaX > 0 && mLineOrPageDeltaY < 0)) {
return 0; // We cannot guess the answer in this case.
}
return (Abs(mLineOrPageDeltaX) > Abs(mLineOrPageDeltaY)) ?
mLineOrPageDeltaX : mLineOrPageDeltaY;
}
// Scroll type
// The default value is SCROLL_DEFAULT, which means EventStateManager will
// select preferred scroll type automatically.
enum ScrollType : uint8_t
{
SCROLL_DEFAULT,
SCROLL_SYNCHRONOUSLY,
SCROLL_ASYNCHRONOUSELY,
SCROLL_SMOOTHLY
};
ScrollType mScrollType;
// If the delta values are computed from prefs, this value is true.
// Otherwise, i.e., they are computed from native events, false.
bool mCustomizedByUserPrefs;
// true if the momentum events directly tied to this event may follow it.
bool mMayHaveMomentum;
// true if the event is caused by momentum.
bool mIsMomentum;
// If device event handlers don't know when they should set mLineOrPageDeltaX
// and mLineOrPageDeltaY, this is true. Otherwise, false.
// If mIsNoLineOrPageDelta is true, ESM will generate
// eLegacyMouseLineOrPageScroll events when accumulated delta values reach
// a line height.
bool mIsNoLineOrPageDelta;
// Whether or not the parent of the currently overscrolled frame is the
// ViewPort. This is false in situations when an element on the page is being
// overscrolled (such as a text field), but true when the 'page' is being
// overscrolled.
bool mViewPortIsOverscrolled;
// The wheel event can trigger a swipe to start if it's overscrolling the
// viewport.
bool mCanTriggerSwipe;
// If mAllowToOverrideSystemScrollSpeed is true, the scroll speed may be
// overridden. Otherwise, the scroll speed won't be overridden even if
// it's enabled by the pref.
bool mAllowToOverrideSystemScrollSpeed;
void AssignWheelEventData(const WidgetWheelEvent& aEvent, bool aCopyTargets)
{
AssignMouseEventBaseData(aEvent, aCopyTargets);
mDeltaX = aEvent.mDeltaX;
mDeltaY = aEvent.mDeltaY;
mDeltaZ = aEvent.mDeltaZ;
mDeltaMode = aEvent.mDeltaMode;
mCustomizedByUserPrefs = aEvent.mCustomizedByUserPrefs;
mMayHaveMomentum = aEvent.mMayHaveMomentum;
mIsMomentum = aEvent.mIsMomentum;
mIsNoLineOrPageDelta = aEvent.mIsNoLineOrPageDelta;
mLineOrPageDeltaX = aEvent.mLineOrPageDeltaX;
mLineOrPageDeltaY = aEvent.mLineOrPageDeltaY;
mScrollType = aEvent.mScrollType;
mOverflowDeltaX = aEvent.mOverflowDeltaX;
mOverflowDeltaY = aEvent.mOverflowDeltaY;
mViewPortIsOverscrolled = aEvent.mViewPortIsOverscrolled;
mCanTriggerSwipe = aEvent.mCanTriggerSwipe;
mAllowToOverrideSystemScrollSpeed =
aEvent.mAllowToOverrideSystemScrollSpeed;
}
// System scroll speed settings may be too slow at using Gecko. In such
// case, we should override the scroll speed computed with system settings.
// Following methods return preferred delta values which are multiplied by
// factors specified by prefs. If system scroll speed shouldn't be
// overridden (e.g., this feature is disabled by pref), they return raw
// delta values.
double OverriddenDeltaX() const;
double OverriddenDeltaY() const;
// Compute the overridden delta value. This may be useful for suppressing
// too fast scroll by system scroll speed overriding when widget sets
// mAllowToOverrideSystemScrollSpeed.
static double ComputeOverriddenDelta(double aDelta, bool aIsForVertical);
private:
static bool sInitialized;
static bool sIsSystemScrollSpeedOverrideEnabled;
static int32_t sOverrideFactorX;
static int32_t sOverrideFactorY;
static void Initialize();
};
/******************************************************************************
* mozilla::WidgetPointerEvent
******************************************************************************/
class WidgetPointerEvent : public WidgetMouseEvent
{
friend class mozilla::dom::PBrowserParent;
friend class mozilla::dom::PBrowserChild;
WidgetPointerEvent()
: mWidth(1)
, mHeight(1)
, mIsPrimary(true)
{
}
public:
virtual WidgetPointerEvent* AsPointerEvent() override { return this; }
WidgetPointerEvent(bool aIsTrusted, EventMessage aMsg, nsIWidget* w)
: WidgetMouseEvent(aIsTrusted, aMsg, w, ePointerEventClass, eReal)
, mWidth(1)
, mHeight(1)
, mIsPrimary(true)
{
}
explicit WidgetPointerEvent(const WidgetMouseEvent& aEvent)
: WidgetMouseEvent(aEvent)
, mWidth(1)
, mHeight(1)
, mIsPrimary(true)
{
mClass = ePointerEventClass;
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == ePointerEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
WidgetPointerEvent* result =
new WidgetPointerEvent(false, mMessage, nullptr);
result->AssignPointerEventData(*this, true);
result->mFlags = mFlags;
return result;
}
uint32_t mWidth;
uint32_t mHeight;
bool mIsPrimary;
// XXX Not tested by test_assign_event_data.html
void AssignPointerEventData(const WidgetPointerEvent& aEvent,
bool aCopyTargets)
{
AssignMouseEventData(aEvent, aCopyTargets);
mWidth = aEvent.mWidth;
mHeight = aEvent.mHeight;
mIsPrimary = aEvent.mIsPrimary;
}
};
} // namespace mozilla
#endif // mozilla_MouseEvents_h__

View file

@ -0,0 +1,821 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
/**
* This header file defines simple code mapping between native scancode or
* something and DOM code name index.
* You must define NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX macro before include
* this.
*
* It must have two arguments, (aNativeKey, aCodeNameIndex).
* aNativeKey is a scancode value or something (depends on the platform).
* aCodeNameIndex is the widget::CodeNameIndex value.
*/
// Windows
#define CODE_MAP_WIN(aCPPCodeName, aNativeKey)
// Mac OS X
#define CODE_MAP_MAC(aCPPCodeName, aNativeKey)
// GTK and Qt on Linux
#define CODE_MAP_X11(aCPPCodeName, aNativeKey)
// Android and Gonk
#define CODE_MAP_ANDROID(aCPPCodeName, aNativeKey)
#if defined(XP_WIN)
#undef CODE_MAP_WIN
// aNativeKey is scan code
#define CODE_MAP_WIN(aCPPCodeName, aNativeKey) \
NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX(aNativeKey, \
CODE_NAME_INDEX_##aCPPCodeName)
#elif defined(XP_MACOSX)
#undef CODE_MAP_MAC
// aNativeKey is key code starting with kVK_.
#define CODE_MAP_MAC(aCPPCodeName, aNativeKey) \
NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX(aNativeKey, \
CODE_NAME_INDEX_##aCPPCodeName)
#elif defined(MOZ_WIDGET_GTK)
#undef CODE_MAP_X11
// aNativeKey is hardware_keycode of GDKEvent or nativeScanCode of QKeyEvent.
#define CODE_MAP_X11(aCPPCodeName, aNativeKey) \
NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX(aNativeKey, \
CODE_NAME_INDEX_##aCPPCodeName)
#elif defined(ANDROID)
#undef CODE_MAP_ANDROID
// aNativeKey is scan code
#define CODE_MAP_ANDROID(aCPPCodeName, aNativeKey) \
NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX(aNativeKey, \
CODE_NAME_INDEX_##aCPPCodeName)
#endif
// Writing system keys
CODE_MAP_WIN(Backquote, 0x0029)
CODE_MAP_MAC(Backquote, kVK_ANSI_Grave)
CODE_MAP_X11(Backquote, 0x0031)
CODE_MAP_ANDROID(Backquote, 0x0029)
CODE_MAP_WIN(Backslash, 0x002B)
CODE_MAP_MAC(Backslash, kVK_ANSI_Backslash)
CODE_MAP_X11(Backslash, 0x0033)
CODE_MAP_ANDROID(Backslash, 0x002B)
CODE_MAP_WIN(Backspace, 0x000E)
CODE_MAP_MAC(Backspace, kVK_Delete)
CODE_MAP_X11(Backspace, 0x0016)
CODE_MAP_ANDROID(Backspace, 0x000E)
CODE_MAP_WIN(BracketLeft, 0x001A)
CODE_MAP_MAC(BracketLeft, kVK_ANSI_LeftBracket)
CODE_MAP_X11(BracketLeft, 0x0022)
CODE_MAP_ANDROID(BracketLeft, 0x001A)
CODE_MAP_WIN(BracketRight, 0x001B)
CODE_MAP_MAC(BracketRight, kVK_ANSI_RightBracket)
CODE_MAP_X11(BracketRight, 0x0023)
CODE_MAP_ANDROID(BracketRight, 0x001B)
CODE_MAP_WIN(Comma, 0x0033)
CODE_MAP_MAC(Comma, kVK_ANSI_Comma)
CODE_MAP_X11(Comma, 0x003B)
CODE_MAP_ANDROID(Comma, 0x00033)
CODE_MAP_WIN(Digit0, 0x000B)
CODE_MAP_MAC(Digit0, kVK_ANSI_0)
CODE_MAP_X11(Digit0, 0x0013)
CODE_MAP_ANDROID(Digit0, 0x000B)
CODE_MAP_WIN(Digit1, 0x0002)
CODE_MAP_MAC(Digit1, kVK_ANSI_1)
CODE_MAP_X11(Digit1, 0x000A)
CODE_MAP_ANDROID(Digit1, 0x0002)
CODE_MAP_WIN(Digit2, 0x0003)
CODE_MAP_MAC(Digit2, kVK_ANSI_2)
CODE_MAP_X11(Digit2, 0x000B)
CODE_MAP_ANDROID(Digit2, 0x0003)
CODE_MAP_WIN(Digit3, 0x0004)
CODE_MAP_MAC(Digit3, kVK_ANSI_3)
CODE_MAP_X11(Digit3, 0x000C)
CODE_MAP_ANDROID(Digit3, 0x0004)
CODE_MAP_WIN(Digit4, 0x0005)
CODE_MAP_MAC(Digit4, kVK_ANSI_4)
CODE_MAP_X11(Digit4, 0x000D)
CODE_MAP_ANDROID(Digit4, 0x0005)
CODE_MAP_WIN(Digit5, 0x0006)
CODE_MAP_MAC(Digit5, kVK_ANSI_5)
CODE_MAP_X11(Digit5, 0x000E)
CODE_MAP_ANDROID(Digit5, 0x0006)
CODE_MAP_WIN(Digit6, 0x0007)
CODE_MAP_MAC(Digit6, kVK_ANSI_6)
CODE_MAP_X11(Digit6, 0x000F)
CODE_MAP_ANDROID(Digit6, 0x0007)
CODE_MAP_WIN(Digit7, 0x0008)
CODE_MAP_MAC(Digit7, kVK_ANSI_7)
CODE_MAP_X11(Digit7, 0x0010)
CODE_MAP_ANDROID(Digit7, 0x0008)
CODE_MAP_WIN(Digit8, 0x0009)
CODE_MAP_MAC(Digit8, kVK_ANSI_8)
CODE_MAP_X11(Digit8, 0x0011)
CODE_MAP_ANDROID(Digit8, 0x0009)
CODE_MAP_WIN(Digit9, 0x000A)
CODE_MAP_MAC(Digit9, kVK_ANSI_9)
CODE_MAP_X11(Digit9, 0x0012)
CODE_MAP_ANDROID(Digit9, 0x000A)
CODE_MAP_WIN(Equal, 0x000D)
CODE_MAP_MAC(Equal, kVK_ANSI_Equal)
CODE_MAP_X11(Equal, 0x0015)
CODE_MAP_ANDROID(Equal, 0x000D)
CODE_MAP_WIN(IntlBackslash, 0x0056)
CODE_MAP_MAC(IntlBackslash, kVK_ISO_Section)
CODE_MAP_X11(IntlBackslash, 0x005E)
CODE_MAP_ANDROID(IntlBackslash, 0x0056)
// Win: IntlHash's scan code is shared with "Backslash" key.
// Mac: IntlHash's virtual key code is shared with "Backslash" key.
// X11: IntlHash's scan code is shared with "Backslash" key.
// Android: IntlHash's scan code is shared with "Backslash" key.
CODE_MAP_WIN(IntlRo, 0x0073)
CODE_MAP_MAC(IntlRo, kVK_JIS_Underscore)
CODE_MAP_X11(IntlRo, 0x0061)
CODE_MAP_ANDROID(IntlRo, 0x0059)
CODE_MAP_WIN(IntlYen, 0x007D)
CODE_MAP_MAC(IntlYen, kVK_JIS_Yen)
CODE_MAP_X11(IntlYen, 0x0084)
CODE_MAP_ANDROID(IntlYen, 0x007C)
CODE_MAP_WIN(KeyA, 0x001E)
CODE_MAP_MAC(KeyA, kVK_ANSI_A)
CODE_MAP_X11(KeyA, 0x0026)
CODE_MAP_ANDROID(KeyA, 0x001E)
CODE_MAP_WIN(KeyB, 0x0030)
CODE_MAP_MAC(KeyB, kVK_ANSI_B)
CODE_MAP_X11(KeyB, 0x0038)
CODE_MAP_ANDROID(KeyB, 0x0030)
CODE_MAP_WIN(KeyC, 0x002E)
CODE_MAP_MAC(KeyC, kVK_ANSI_C)
CODE_MAP_X11(KeyC, 0x0036)
CODE_MAP_ANDROID(KeyC, 0x002E)
CODE_MAP_WIN(KeyD, 0x0020)
CODE_MAP_MAC(KeyD, kVK_ANSI_D)
CODE_MAP_X11(KeyD, 0x0028)
CODE_MAP_ANDROID(KeyD, 0x0020)
CODE_MAP_WIN(KeyE, 0x0012)
CODE_MAP_MAC(KeyE, kVK_ANSI_E)
CODE_MAP_X11(KeyE, 0x001A)
CODE_MAP_ANDROID(KeyE, 0x0012)
CODE_MAP_WIN(KeyF, 0x0021)
CODE_MAP_MAC(KeyF, kVK_ANSI_F)
CODE_MAP_X11(KeyF, 0x0029)
CODE_MAP_ANDROID(KeyF, 0x0021)
CODE_MAP_WIN(KeyG, 0x0022)
CODE_MAP_MAC(KeyG, kVK_ANSI_G)
CODE_MAP_X11(KeyG, 0x002A)
CODE_MAP_ANDROID(KeyG, 0x0022)
CODE_MAP_WIN(KeyH, 0x0023)
CODE_MAP_MAC(KeyH, kVK_ANSI_H)
CODE_MAP_X11(KeyH, 0x002B)
CODE_MAP_ANDROID(KeyH, 0x0023)
CODE_MAP_WIN(KeyI, 0x0017)
CODE_MAP_MAC(KeyI, kVK_ANSI_I)
CODE_MAP_X11(KeyI, 0x001F)
CODE_MAP_ANDROID(KeyI, 0x0017)
CODE_MAP_WIN(KeyJ, 0x0024)
CODE_MAP_MAC(KeyJ, kVK_ANSI_J)
CODE_MAP_X11(KeyJ, 0x002C)
CODE_MAP_ANDROID(KeyJ, 0x0024)
CODE_MAP_WIN(KeyK, 0x0025)
CODE_MAP_MAC(KeyK, kVK_ANSI_K)
CODE_MAP_X11(KeyK, 0x002D)
CODE_MAP_ANDROID(KeyK, 0x0025)
CODE_MAP_WIN(KeyL, 0x0026)
CODE_MAP_MAC(KeyL, kVK_ANSI_L)
CODE_MAP_X11(KeyL, 0x002E)
CODE_MAP_ANDROID(KeyL, 0x0026)
CODE_MAP_WIN(KeyM, 0x0032)
CODE_MAP_MAC(KeyM, kVK_ANSI_M)
CODE_MAP_X11(KeyM, 0x003A)
CODE_MAP_ANDROID(KeyM, 0x0032)
CODE_MAP_WIN(KeyN, 0x0031)
CODE_MAP_MAC(KeyN, kVK_ANSI_N)
CODE_MAP_X11(KeyN, 0x0039)
CODE_MAP_ANDROID(KeyN, 0x0031)
CODE_MAP_WIN(KeyO, 0x0018)
CODE_MAP_MAC(KeyO, kVK_ANSI_O)
CODE_MAP_X11(KeyO, 0x0020)
CODE_MAP_ANDROID(KeyO, 0x0018)
CODE_MAP_WIN(KeyP, 0x0019)
CODE_MAP_MAC(KeyP, kVK_ANSI_P)
CODE_MAP_X11(KeyP, 0x0021)
CODE_MAP_ANDROID(KeyP, 0x0019)
CODE_MAP_WIN(KeyQ, 0x0010)
CODE_MAP_MAC(KeyQ, kVK_ANSI_Q)
CODE_MAP_X11(KeyQ, 0x0018)
CODE_MAP_ANDROID(KeyQ, 0x0010)
CODE_MAP_WIN(KeyR, 0x0013)
CODE_MAP_MAC(KeyR, kVK_ANSI_R)
CODE_MAP_X11(KeyR, 0x001B)
CODE_MAP_ANDROID(KeyR, 0x0013)
CODE_MAP_WIN(KeyS, 0x001F)
CODE_MAP_MAC(KeyS, kVK_ANSI_S)
CODE_MAP_X11(KeyS, 0x0027)
CODE_MAP_ANDROID(KeyS, 0x001F)
CODE_MAP_WIN(KeyT, 0x0014)
CODE_MAP_MAC(KeyT, kVK_ANSI_T)
CODE_MAP_X11(KeyT, 0x001C)
CODE_MAP_ANDROID(KeyT, 0x0014)
CODE_MAP_WIN(KeyU, 0x0016)
CODE_MAP_MAC(KeyU, kVK_ANSI_U)
CODE_MAP_X11(KeyU, 0x001E)
CODE_MAP_ANDROID(KeyU, 0x0016)
CODE_MAP_WIN(KeyV, 0x002F)
CODE_MAP_MAC(KeyV, kVK_ANSI_V)
CODE_MAP_X11(KeyV, 0x0037)
CODE_MAP_ANDROID(KeyV, 0x002F)
CODE_MAP_WIN(KeyW, 0x0011)
CODE_MAP_MAC(KeyW, kVK_ANSI_W)
CODE_MAP_X11(KeyW, 0x0019)
CODE_MAP_ANDROID(KeyW, 0x0011)
CODE_MAP_WIN(KeyX, 0x002D)
CODE_MAP_MAC(KeyX, kVK_ANSI_X)
CODE_MAP_X11(KeyX, 0x0035)
CODE_MAP_ANDROID(KeyX, 0x002D)
CODE_MAP_WIN(KeyY, 0x0015)
CODE_MAP_MAC(KeyY, kVK_ANSI_Y)
CODE_MAP_X11(KeyY, 0x001D)
CODE_MAP_ANDROID(KeyY, 0x0015)
CODE_MAP_WIN(KeyZ, 0x002C)
CODE_MAP_MAC(KeyZ, kVK_ANSI_Z)
CODE_MAP_X11(KeyZ, 0x0034)
CODE_MAP_ANDROID(KeyZ, 0x002C)
CODE_MAP_WIN(Minus, 0x000C)
CODE_MAP_MAC(Minus, kVK_ANSI_Minus)
CODE_MAP_X11(Minus, 0x0014)
CODE_MAP_ANDROID(Minus, 0x000C)
CODE_MAP_WIN(Period, 0x0034)
CODE_MAP_MAC(Period, kVK_ANSI_Period)
CODE_MAP_X11(Period, 0x003C)
CODE_MAP_ANDROID(Period, 0x0034)
CODE_MAP_WIN(Quote, 0x0028)
CODE_MAP_MAC(Quote, kVK_ANSI_Quote)
CODE_MAP_X11(Quote, 0x0030)
CODE_MAP_ANDROID(Quote, 0x0028)
CODE_MAP_WIN(Semicolon, 0x0027)
CODE_MAP_MAC(Semicolon, kVK_ANSI_Semicolon)
CODE_MAP_X11(Semicolon, 0x002F)
CODE_MAP_ANDROID(Semicolon, 0x0027)
CODE_MAP_WIN(Slash, 0x0035)
CODE_MAP_MAC(Slash, kVK_ANSI_Slash)
CODE_MAP_X11(Slash, 0x003D)
CODE_MAP_ANDROID(Slash, 0x0035)
// Functional keys
CODE_MAP_WIN(AltLeft, 0x0038)
CODE_MAP_MAC(AltLeft, kVK_Option)
CODE_MAP_X11(AltLeft, 0x0040)
CODE_MAP_ANDROID(AltLeft, 0x0038)
CODE_MAP_WIN(AltRight, 0xE038)
CODE_MAP_MAC(AltRight, kVK_RightOption)
CODE_MAP_X11(AltRight, 0x006C)
CODE_MAP_ANDROID(AltRight, 0x0064)
CODE_MAP_WIN(CapsLock, 0x003A)
CODE_MAP_MAC(CapsLock, kVK_CapsLock)
CODE_MAP_X11(CapsLock, 0x0042)
CODE_MAP_ANDROID(CapsLock, 0x003A)
CODE_MAP_WIN(ContextMenu, 0xE05D)
CODE_MAP_MAC(ContextMenu, kVK_PC_ContextMenu)
CODE_MAP_X11(ContextMenu, 0x0087)
CODE_MAP_ANDROID(ContextMenu, 0x007F)
CODE_MAP_WIN(ControlLeft, 0x001D)
CODE_MAP_MAC(ControlLeft, kVK_Control)
CODE_MAP_X11(ControlLeft, 0x0025)
CODE_MAP_ANDROID(ControlLeft, 0x001D)
CODE_MAP_WIN(ControlRight, 0xE01D)
CODE_MAP_MAC(ControlRight, kVK_RightControl)
CODE_MAP_X11(ControlRight, 0x0069)
CODE_MAP_ANDROID(ControlRight, 0x0061)
CODE_MAP_WIN(Enter, 0x001C)
CODE_MAP_MAC(Enter, kVK_Return)
CODE_MAP_X11(Enter, 0x0024)
CODE_MAP_ANDROID(Enter, 0x001C)
CODE_MAP_WIN(OSLeft, 0xE05B)
CODE_MAP_MAC(OSLeft, kVK_Command)
CODE_MAP_X11(OSLeft, 0x0085)
CODE_MAP_ANDROID(OSLeft, 0x007D)
CODE_MAP_WIN(OSRight, 0xE05C)
CODE_MAP_MAC(OSRight, kVK_RightCommand)
CODE_MAP_X11(OSRight, 0x0086)
CODE_MAP_ANDROID(OSRight, 0x007E)
CODE_MAP_WIN(ShiftLeft, 0x002A)
CODE_MAP_MAC(ShiftLeft, kVK_Shift)
CODE_MAP_X11(ShiftLeft, 0x0032)
CODE_MAP_ANDROID(ShiftLeft, 0x002A)
CODE_MAP_WIN(ShiftRight, 0x0036)
CODE_MAP_MAC(ShiftRight, kVK_RightShift)
CODE_MAP_X11(ShiftRight, 0x003E)
CODE_MAP_ANDROID(ShiftRight, 0x0036)
CODE_MAP_WIN(Space, 0x0039)
CODE_MAP_MAC(Space, kVK_Space)
CODE_MAP_X11(Space, 0x0041)
CODE_MAP_ANDROID(Space, 0x0039)
CODE_MAP_WIN(Tab, 0x000F)
CODE_MAP_MAC(Tab, kVK_Tab)
CODE_MAP_X11(Tab, 0x0017)
CODE_MAP_ANDROID(Tab, 0x000F)
// IME keys
CODE_MAP_WIN(Convert, 0x0079)
CODE_MAP_X11(Convert, 0x0064)
CODE_MAP_ANDROID(Convert, 0x005C)
CODE_MAP_WIN(Lang1, 0x0072) // for non-Korean layout
CODE_MAP_WIN(Lang1, 0xE0F2) // for Korean layout
CODE_MAP_MAC(Lang1, kVK_JIS_Kana)
CODE_MAP_X11(Lang1, 0x0082)
CODE_MAP_ANDROID(Lang1, 0x007A)
CODE_MAP_WIN(Lang2, 0x0071) // for non-Korean layout
CODE_MAP_WIN(Lang2, 0xE0F1) // for Korean layout
CODE_MAP_MAC(Lang2, kVK_JIS_Eisu)
CODE_MAP_X11(Lang2, 0x0083)
CODE_MAP_ANDROID(Lang2, 0x007B)
CODE_MAP_WIN(KanaMode, 0x0070)
CODE_MAP_X11(KanaMode, 0x0065)
CODE_MAP_ANDROID(KanaMode, 0x005D)
CODE_MAP_WIN(NonConvert, 0x007B)
CODE_MAP_X11(NonConvert, 0x0066)
CODE_MAP_ANDROID(NonConvert, 0x005E)
// Control pad section
CODE_MAP_WIN(Delete, 0xE053)
CODE_MAP_MAC(Delete, kVK_ForwardDelete)
CODE_MAP_X11(Delete, 0x0077)
CODE_MAP_ANDROID(Delete, 0x006F)
CODE_MAP_WIN(End, 0xE04F)
CODE_MAP_MAC(End, kVK_End)
CODE_MAP_X11(End, 0x0073)
CODE_MAP_ANDROID(End, 0x006B)
CODE_MAP_MAC(Help, kVK_Help) // Insert key on PC keyboard
CODE_MAP_X11(Help, 0x0092) // Help key on Sun keyboard
CODE_MAP_ANDROID(Help, 0x008A) // Help key on Sun keyboard
CODE_MAP_WIN(Home, 0xE047)
CODE_MAP_MAC(Home, kVK_Home)
CODE_MAP_X11(Home, 0x006E)
CODE_MAP_ANDROID(Home, 0x0066)
CODE_MAP_WIN(Insert, 0xE052)
CODE_MAP_X11(Insert, 0x0076)
CODE_MAP_ANDROID(Insert, 0x006E)
CODE_MAP_WIN(PageDown, 0xE051)
CODE_MAP_MAC(PageDown, kVK_PageDown)
CODE_MAP_X11(PageDown, 0x0075)
CODE_MAP_ANDROID(PageDown, 0x006D)
CODE_MAP_WIN(PageUp, 0xE049)
CODE_MAP_MAC(PageUp, kVK_PageUp)
CODE_MAP_X11(PageUp, 0x0070)
CODE_MAP_ANDROID(PageUp, 0x0068)
// Arrow pad section
CODE_MAP_WIN(ArrowDown, 0xE050)
CODE_MAP_MAC(ArrowDown, kVK_DownArrow)
CODE_MAP_X11(ArrowDown, 0x0074)
CODE_MAP_ANDROID(ArrowDown, 0x006C)
CODE_MAP_WIN(ArrowLeft, 0xE04B)
CODE_MAP_MAC(ArrowLeft, kVK_LeftArrow)
CODE_MAP_X11(ArrowLeft, 0x0071)
CODE_MAP_ANDROID(ArrowLeft, 0x0069)
CODE_MAP_WIN(ArrowRight, 0xE04D)
CODE_MAP_MAC(ArrowRight, kVK_RightArrow)
CODE_MAP_X11(ArrowRight, 0x0072)
CODE_MAP_ANDROID(ArrowRight, 0x006A)
CODE_MAP_WIN(ArrowUp, 0xE048)
CODE_MAP_MAC(ArrowUp, kVK_UpArrow)
CODE_MAP_X11(ArrowUp, 0x006F)
CODE_MAP_ANDROID(ArrowUp, 0x0067)
// Numpad section
CODE_MAP_WIN(NumLock, 0xE045) // MSDN says 0x0045, though...
CODE_MAP_MAC(NumLock, kVK_ANSI_KeypadClear)
CODE_MAP_X11(NumLock, 0x004D)
CODE_MAP_ANDROID(NumLock, 0x0045)
CODE_MAP_WIN(Numpad0, 0x0052)
CODE_MAP_MAC(Numpad0, kVK_ANSI_Keypad0)
CODE_MAP_X11(Numpad0, 0x005A)
CODE_MAP_ANDROID(Numpad0, 0x0052)
CODE_MAP_WIN(Numpad1, 0x004F)
CODE_MAP_MAC(Numpad1, kVK_ANSI_Keypad1)
CODE_MAP_X11(Numpad1, 0x0057)
CODE_MAP_ANDROID(Numpad1, 0x004F)
CODE_MAP_WIN(Numpad2, 0x0050)
CODE_MAP_MAC(Numpad2, kVK_ANSI_Keypad2)
CODE_MAP_X11(Numpad2, 0x0058)
CODE_MAP_ANDROID(Numpad2, 0x0050)
CODE_MAP_WIN(Numpad3, 0x0051)
CODE_MAP_MAC(Numpad3, kVK_ANSI_Keypad3)
CODE_MAP_X11(Numpad3, 0x0059)
CODE_MAP_ANDROID(Numpad3, 0x0051)
CODE_MAP_WIN(Numpad4, 0x004B)
CODE_MAP_MAC(Numpad4, kVK_ANSI_Keypad4)
CODE_MAP_X11(Numpad4, 0x0053)
CODE_MAP_ANDROID(Numpad4, 0x004B)
CODE_MAP_WIN(Numpad5, 0x004C)
CODE_MAP_MAC(Numpad5, kVK_ANSI_Keypad5)
CODE_MAP_X11(Numpad5, 0x0054)
CODE_MAP_ANDROID(Numpad5, 0x004C)
CODE_MAP_WIN(Numpad6, 0x004D)
CODE_MAP_MAC(Numpad6, kVK_ANSI_Keypad6)
CODE_MAP_X11(Numpad6, 0x0055)
CODE_MAP_ANDROID(Numpad6, 0x004D)
CODE_MAP_WIN(Numpad7, 0x0047)
CODE_MAP_MAC(Numpad7, kVK_ANSI_Keypad7)
CODE_MAP_X11(Numpad7, 0x004F)
CODE_MAP_ANDROID(Numpad7, 0x0047)
CODE_MAP_WIN(Numpad8, 0x0048)
CODE_MAP_MAC(Numpad8, kVK_ANSI_Keypad8)
CODE_MAP_X11(Numpad8, 0x0050)
CODE_MAP_ANDROID(Numpad8, 0x0048)
CODE_MAP_WIN(Numpad9, 0x0049)
CODE_MAP_MAC(Numpad9, kVK_ANSI_Keypad9)
CODE_MAP_X11(Numpad9, 0x0051)
CODE_MAP_ANDROID(Numpad9, 0x0049)
CODE_MAP_WIN(NumpadAdd, 0x004E)
CODE_MAP_MAC(NumpadAdd, kVK_ANSI_KeypadPlus)
CODE_MAP_X11(NumpadAdd, 0x0056)
CODE_MAP_ANDROID(NumpadAdd, 0x004E)
CODE_MAP_WIN(NumpadComma, 0x007E)
CODE_MAP_MAC(NumpadComma, kVK_JIS_KeypadComma)
CODE_MAP_X11(NumpadComma, 0x0081)
CODE_MAP_ANDROID(NumpadComma, 0x0079)
CODE_MAP_WIN(NumpadDecimal, 0x0053)
CODE_MAP_MAC(NumpadDecimal, kVK_ANSI_KeypadDecimal)
CODE_MAP_X11(NumpadDecimal, 0x005B)
CODE_MAP_ANDROID(NumpadDecimal, 0x0053)
CODE_MAP_WIN(NumpadDivide, 0xE035)
CODE_MAP_MAC(NumpadDivide, kVK_ANSI_KeypadDivide)
CODE_MAP_X11(NumpadDivide, 0x006A)
CODE_MAP_ANDROID(NumpadDivide, 0x0062)
CODE_MAP_WIN(NumpadEnter, 0xE01C)
CODE_MAP_MAC(NumpadEnter, kVK_ANSI_KeypadEnter)
CODE_MAP_MAC(NumpadEnter, kVK_Powerbook_KeypadEnter)
CODE_MAP_X11(NumpadEnter, 0x0068)
CODE_MAP_ANDROID(NumpadEnter, 0x0060)
CODE_MAP_WIN(NumpadEqual, 0x0059)
CODE_MAP_MAC(NumpadEqual, kVK_ANSI_KeypadEquals)
CODE_MAP_X11(NumpadEqual, 0x007D)
CODE_MAP_ANDROID(NumpadEqual, 0x0075)
CODE_MAP_WIN(NumpadMultiply, 0x0037)
CODE_MAP_MAC(NumpadMultiply, kVK_ANSI_KeypadMultiply)
CODE_MAP_X11(NumpadMultiply, 0x003F)
CODE_MAP_ANDROID(NumpadMultiply, 0x0037)
CODE_MAP_WIN(NumpadSubtract, 0x004A)
CODE_MAP_MAC(NumpadSubtract, kVK_ANSI_KeypadMinus)
CODE_MAP_X11(NumpadSubtract, 0x0052)
CODE_MAP_ANDROID(NumpadSubtract, 0x004A)
// Function section
CODE_MAP_WIN(Escape, 0x0001)
CODE_MAP_MAC(Escape, kVK_Escape)
CODE_MAP_X11(Escape, 0x0009)
CODE_MAP_ANDROID(Escape, 0x0001)
CODE_MAP_WIN(F1, 0x003B)
CODE_MAP_MAC(F1, kVK_F1)
CODE_MAP_X11(F1, 0x0043)
CODE_MAP_ANDROID(F1, 0x003B)
CODE_MAP_WIN(F2, 0x003C)
CODE_MAP_MAC(F2, kVK_F2)
CODE_MAP_X11(F2, 0x0044)
CODE_MAP_ANDROID(F2, 0x003C)
CODE_MAP_WIN(F3, 0x003D)
CODE_MAP_MAC(F3, kVK_F3)
CODE_MAP_X11(F3, 0x0045)
CODE_MAP_ANDROID(F3, 0x003D)
CODE_MAP_WIN(F4, 0x003E)
CODE_MAP_MAC(F4, kVK_F4)
CODE_MAP_X11(F4, 0x0046)
CODE_MAP_ANDROID(F4, 0x003E)
CODE_MAP_WIN(F5, 0x003F)
CODE_MAP_MAC(F5, kVK_F5)
CODE_MAP_X11(F5, 0x0047)
CODE_MAP_ANDROID(F5, 0x003F)
CODE_MAP_WIN(F6, 0x0040)
CODE_MAP_MAC(F6, kVK_F6)
CODE_MAP_X11(F6, 0x0048)
CODE_MAP_ANDROID(F6, 0x0040)
CODE_MAP_WIN(F7, 0x0041)
CODE_MAP_MAC(F7, kVK_F7)
CODE_MAP_X11(F7, 0x0049)
CODE_MAP_ANDROID(F7, 0x0041)
CODE_MAP_WIN(F8, 0x0042)
CODE_MAP_MAC(F8, kVK_F8)
CODE_MAP_X11(F8, 0x004A)
CODE_MAP_ANDROID(F8, 0x0042)
CODE_MAP_WIN(F9, 0x0043)
CODE_MAP_MAC(F9, kVK_F9)
CODE_MAP_X11(F9, 0x004B)
CODE_MAP_ANDROID(F9, 0x0043)
CODE_MAP_WIN(F10, 0x0044)
CODE_MAP_MAC(F10, kVK_F10)
CODE_MAP_X11(F10, 0x004C)
CODE_MAP_ANDROID(F10, 0x0044)
CODE_MAP_WIN(F11, 0x0057)
CODE_MAP_MAC(F11, kVK_F11)
CODE_MAP_X11(F11, 0x005F)
CODE_MAP_ANDROID(F11, 0x0057)
CODE_MAP_WIN(F12, 0x0058)
CODE_MAP_MAC(F12, kVK_F12)
CODE_MAP_X11(F12, 0x0060)
CODE_MAP_ANDROID(F12, 0x0058)
CODE_MAP_WIN(F13, 0x0064)
CODE_MAP_MAC(F13, kVK_F13) // PrintScreen on PC keyboard
CODE_MAP_X11(F13, 0x00BF)
CODE_MAP_ANDROID(F13, 0x00B7)
CODE_MAP_WIN(F14, 0x0065)
CODE_MAP_MAC(F14, kVK_F14) // ScrollLock on PC keyboard
CODE_MAP_X11(F14, 0x00C0)
CODE_MAP_ANDROID(F14, 0x00B8)
CODE_MAP_WIN(F15, 0x0066)
CODE_MAP_MAC(F15, kVK_F15) // Pause on PC keyboard
CODE_MAP_X11(F15, 0x00C1)
CODE_MAP_ANDROID(F15, 0x00B9)
CODE_MAP_WIN(F16, 0x0067)
CODE_MAP_MAC(F16, kVK_F16)
CODE_MAP_X11(F16, 0x00C2)
CODE_MAP_ANDROID(F16, 0x00BA)
CODE_MAP_WIN(F17, 0x0068)
CODE_MAP_MAC(F17, kVK_F17)
CODE_MAP_X11(F17, 0x00C3)
CODE_MAP_ANDROID(F17, 0x00BB)
CODE_MAP_WIN(F18, 0x0069)
CODE_MAP_MAC(F18, kVK_F18)
CODE_MAP_X11(F18, 0x00C4)
CODE_MAP_ANDROID(F18, 0x00BC)
CODE_MAP_WIN(F19, 0x006A)
CODE_MAP_MAC(F19, kVK_F19)
CODE_MAP_X11(F19, 0x00C5)
CODE_MAP_ANDROID(F19, 0x00BD)
CODE_MAP_WIN(F20, 0x006B)
CODE_MAP_MAC(F20, kVK_F20)
CODE_MAP_X11(F20, 0x00C6)
CODE_MAP_ANDROID(F20, 0x00BE)
CODE_MAP_WIN(F21, 0x006C)
CODE_MAP_X11(F21, 0x00C7)
CODE_MAP_ANDROID(F21, 0x00BF)
CODE_MAP_WIN(F22, 0x006D)
CODE_MAP_X11(F22, 0x00C8)
CODE_MAP_ANDROID(F22, 0x00C0)
CODE_MAP_WIN(F23, 0x006E)
CODE_MAP_X11(F23, 0x00C9)
CODE_MAP_ANDROID(F23, 0x00C1)
CODE_MAP_WIN(F24, 0x0076)
CODE_MAP_X11(F24, 0x00CA)
CODE_MAP_ANDROID(F24, 0x00C2)
CODE_MAP_MAC(Fn, kVK_Function) // not available?
CODE_MAP_ANDROID(Fn, 0x01D0)
CODE_MAP_WIN(PrintScreen, 0xE037)
CODE_MAP_WIN(PrintScreen, 0x0054) // Alt + PrintScreen
CODE_MAP_X11(PrintScreen, 0x006B)
CODE_MAP_ANDROID(PrintScreen, 0x0063)
CODE_MAP_WIN(ScrollLock, 0x0046)
CODE_MAP_X11(ScrollLock, 0x004E)
CODE_MAP_ANDROID(ScrollLock, 0x0046)
CODE_MAP_WIN(Pause, 0x0045)
CODE_MAP_WIN(Pause, 0xE046) // Ctrl + Pause
CODE_MAP_X11(Pause, 0x007F)
CODE_MAP_ANDROID(Pause, 0x0077)
// Media keys
CODE_MAP_WIN(BrowserBack, 0xE06A)
CODE_MAP_X11(BrowserBack, 0x00A6)
CODE_MAP_ANDROID(BrowserBack, 0x009E)
CODE_MAP_WIN(BrowserFavorites, 0xE066)
CODE_MAP_X11(BrowserFavorites, 0x00A4)
CODE_MAP_ANDROID(BrowserFavorites, 0x009C)
CODE_MAP_WIN(BrowserForward, 0xE069)
CODE_MAP_X11(BrowserForward, 0x00A7)
CODE_MAP_ANDROID(BrowserForward, 0x009F)
CODE_MAP_WIN(BrowserHome, 0xE032)
CODE_MAP_X11(BrowserHome, 0x00B4)
// CODE_MAP_ANDROID(BrowserHome) // not available? works as Home key.
CODE_MAP_WIN(BrowserRefresh, 0xE067)
CODE_MAP_X11(BrowserRefresh, 0x00B5)
CODE_MAP_ANDROID(BrowserRefresh, 0x00AD)
CODE_MAP_WIN(BrowserSearch, 0xE065)
CODE_MAP_X11(BrowserSearch, 0x00E1)
CODE_MAP_ANDROID(BrowserSearch, 0x00D9)
CODE_MAP_WIN(BrowserStop, 0xE068)
CODE_MAP_X11(BrowserStop, 0x0088)
CODE_MAP_ANDROID(BrowserStop, 0x0080)
// CODE_MAP_WIN(Eject) // not available?
// CODE_MAP_MAC(Eject) // not available?
CODE_MAP_X11(Eject, 0x00A9)
CODE_MAP_ANDROID(Eject, 0x00A1)
CODE_MAP_WIN(LaunchApp1, 0xE06B)
CODE_MAP_X11(LaunchApp1, 0x0098)
CODE_MAP_ANDROID(LaunchApp1, 0x0090)
CODE_MAP_WIN(LaunchApp2, 0xE021)
CODE_MAP_X11(LaunchApp2, 0x0094)
// CODE_MAP_ANDROID(LaunchApp2) // not available?
CODE_MAP_WIN(LaunchMail, 0xE06C)
CODE_MAP_X11(LaunchMail, 0x00A3)
// CODE_MAP_ANDROID(LaunchMail) // not available?
CODE_MAP_WIN(MediaPlayPause, 0xE022)
CODE_MAP_X11(MediaPlayPause, 0x00AC)
CODE_MAP_ANDROID(MediaPlayPause, 0x00A4)
CODE_MAP_WIN(MediaSelect, 0xE06D)
CODE_MAP_X11(MediaSelect, 0x00B3)
// CODE_MAP_ANDROID(MediaSelect) // not available?
CODE_MAP_WIN(MediaStop, 0xE024)
CODE_MAP_X11(MediaStop, 0x00AE)
CODE_MAP_ANDROID(MediaStop, 0x00A6)
CODE_MAP_WIN(MediaTrackNext, 0xE019)
CODE_MAP_X11(MediaTrackNext, 0x00AB)
CODE_MAP_ANDROID(MediaTrackNext, 0x00A3)
CODE_MAP_WIN(MediaTrackPrevious, 0xE010)
CODE_MAP_X11(MediaTrackPrevious, 0x00AD)
CODE_MAP_ANDROID(MediaTrackPrevious, 0x00A5)
CODE_MAP_WIN(Power, 0xE05E)
CODE_MAP_MAC(Power, 0x007F) // On 10.7 and 10.8 only
// CODE_MAP_X11(Power) // not available?
CODE_MAP_ANDROID(Power, 0x0074)
// CODE_MAP_WIN(Sleep) // not available?
// CODE_MAP_X11(Sleep) // not available?
CODE_MAP_ANDROID(Sleep, 0x008E)
CODE_MAP_WIN(VolumeDown, 0xE02E)
CODE_MAP_MAC(VolumeDown, kVK_VolumeDown) // not available?
CODE_MAP_X11(VolumeDown, 0x007A)
CODE_MAP_ANDROID(VolumeDown, 0x0072)
CODE_MAP_WIN(VolumeMute, 0xE020)
CODE_MAP_MAC(VolumeMute, kVK_Mute) // not available?
CODE_MAP_X11(VolumeMute, 0x0079)
CODE_MAP_ANDROID(VolumeMute, 0x0071)
CODE_MAP_WIN(VolumeUp, 0xE030)
CODE_MAP_MAC(VolumeUp, kVK_VolumeUp) // not available?
CODE_MAP_X11(VolumeUp, 0x007B)
CODE_MAP_ANDROID(VolumeUp, 0x0073) // side of body, not on keyboard
// CODE_MAP_WIN(WakeUp) // not available?
CODE_MAP_X11(WakeUp, 0x0097)
CODE_MAP_ANDROID(WakeUp, 0x008F)
// Legacy editing keys
CODE_MAP_X11(Again, 0x0089) // Again key on Sun keyboard
CODE_MAP_ANDROID(Again, 0x0081) // Again key on Sun keyboard
CODE_MAP_X11(Copy, 0x008D) // Copy key on Sun keyboard
CODE_MAP_ANDROID(Copy, 0x0085) // Copy key on Sun keyboard
CODE_MAP_X11(Cut, 0x0091) // Cut key on Sun keyboard
CODE_MAP_ANDROID(Cut, 0x0089) // Cut key on Sun keyboard
CODE_MAP_X11(Find, 0x0090) // Find key on Sun keyboard
CODE_MAP_ANDROID(Find, 0x0088) // Find key on Sun keyboard
CODE_MAP_X11(Open, 0x008E) // Open key on Sun keyboard
CODE_MAP_ANDROID(Open, 0x0086) // Open key on Sun keyboard
CODE_MAP_X11(Paste, 0x008F) // Paste key on Sun keyboard
CODE_MAP_ANDROID(Paste, 0x0087) // Paste key on Sun keyboard
CODE_MAP_X11(Props, 0x008A) // Props key on Sun keyboard
CODE_MAP_ANDROID(Props, 0x0082) // Props key on Sun keyboard
CODE_MAP_X11(Select, 0x008C) // Front key on Sun keyboard
CODE_MAP_ANDROID(Select, 0x0084) // Front key on Sun keyboard
CODE_MAP_X11(Undo, 0x008B) // Undo key on Sun keyboard
CODE_MAP_ANDROID(Undo, 0x0083) // Undo key on Sun keyboard
#undef CODE_MAP_WIN
#undef CODE_MAP_MAC
#undef CODE_MAP_X11
#undef CODE_MAP_ANDROID

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,28 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
/* 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 protocol PCompositorBridge;
// This file is a stub, for platforms that do not yet support out-of-process
// compositing or do not need specialized types to do so.
namespace mozilla {
namespace widget {
sync protocol PCompositorWidget
{
manager PCompositorBridge;
parent:
async __delete__();
child:
async ObserveVsync();
async UnobserveVsync();
};
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,18 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
/* 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/. */
// This file is a stub, for platforms that do not yet support out-of-process
// compositing or do not need specialized types to do so.
namespace mozilla {
namespace widget {
struct CompositorWidgetInitData
{
};
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,195 @@
/* 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 "PluginWidgetProxy.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/plugins/PluginWidgetChild.h"
#include "mozilla/plugins/PluginInstanceParent.h"
#include "nsDebug.h"
#define PWLOG(...)
// #define PWLOG(...) printf_stderr(__VA_ARGS__)
/* static */
already_AddRefed<nsIWidget>
nsIWidget::CreatePluginProxyWidget(TabChild* aTabChild,
mozilla::plugins::PluginWidgetChild* aActor)
{
nsCOMPtr<nsIWidget> widget =
new mozilla::widget::PluginWidgetProxy(aTabChild, aActor);
return widget.forget();
}
namespace mozilla {
namespace widget {
using mozilla::plugins::PluginInstanceParent;
NS_IMPL_ISUPPORTS_INHERITED(PluginWidgetProxy, PuppetWidget, nsIWidget)
#define ENSURE_CHANNEL do { \
if (!mActor) { \
NS_WARNING("called on an invalid channel."); \
return NS_ERROR_FAILURE; \
} \
} while (0)
PluginWidgetProxy::PluginWidgetProxy(dom::TabChild* aTabChild,
mozilla::plugins::PluginWidgetChild* aActor) :
PuppetWidget(aTabChild),
mActor(aActor),
mCachedPluginPort(0)
{
// See ChannelDestroyed() in the header
mActor->SetWidget(this);
}
PluginWidgetProxy::~PluginWidgetProxy()
{
PWLOG("PluginWidgetProxy::~PluginWidgetProxy()\n");
}
nsresult
PluginWidgetProxy::Create(nsIWidget* aParent,
nsNativeWidget aNativeParent,
const LayoutDeviceIntRect& aRect,
nsWidgetInitData* aInitData)
{
ENSURE_CHANNEL;
PWLOG("PluginWidgetProxy::Create()\n");
nsresult rv = NS_ERROR_UNEXPECTED;
uint64_t scrollCaptureId;
uintptr_t pluginInstanceId;
mActor->SendCreate(&rv, &scrollCaptureId, &pluginInstanceId);
if (NS_FAILED(rv)) {
NS_WARNING("failed to create chrome widget, plugins won't paint.");
return rv;
}
BaseCreate(aParent, aInitData);
mParent = aParent;
mBounds = aRect;
mEnabled = true;
mVisible = true;
#if defined(XP_WIN)
PluginInstanceParent* instance =
PluginInstanceParent::LookupPluginInstanceByID(pluginInstanceId);
if (instance) {
Unused << NS_WARN_IF(NS_FAILED(instance->SetScrollCaptureId(scrollCaptureId)));
}
#endif
return NS_OK;
}
NS_IMETHODIMP
PluginWidgetProxy::SetParent(nsIWidget* aNewParent)
{
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
nsIWidget* parent = GetParent();
if (parent) {
parent->RemoveChild(this);
}
if (aNewParent) {
aNewParent->AddChild(this);
}
mParent = aNewParent;
return NS_OK;
}
nsIWidget*
PluginWidgetProxy::GetParent(void)
{
return mParent.get();
}
void
PluginWidgetProxy::Destroy()
{
PWLOG("PluginWidgetProxy::Destroy()\n");
if (mActor) {
// Communicate that the layout widget has been torn down before the sub
// protocol.
mActor->ProxyShutdown();
mActor = nullptr;
}
PuppetWidget::Destroy();
}
void
PluginWidgetProxy::GetWindowClipRegion(nsTArray<LayoutDeviceIntRect>* aRects)
{
if (mClipRects && mClipRectCount) {
aRects->AppendElements(mClipRects.get(), mClipRectCount);
}
}
void*
PluginWidgetProxy::GetNativeData(uint32_t aDataType)
{
if (!mActor) {
return nullptr;
}
auto tab = static_cast<mozilla::dom::TabChild*>(mActor->Manager());
if (tab && tab->IsDestroyed()) {
return nullptr;
}
switch (aDataType) {
case NS_NATIVE_PLUGIN_PORT:
case NS_NATIVE_WINDOW:
case NS_NATIVE_SHAREABLE_WINDOW:
break;
default:
NS_WARNING("PluginWidgetProxy::GetNativeData received request for unsupported data type.");
return nullptr;
}
// The parent side window handle or xid never changes so we can
// cache this for our lifetime.
if (mCachedPluginPort) {
return (void*)mCachedPluginPort;
}
mActor->SendGetNativePluginPort(&mCachedPluginPort);
PWLOG("PluginWidgetProxy::GetNativeData %p\n", (void*)mCachedPluginPort);
return (void*)mCachedPluginPort;
}
#if defined(XP_WIN)
void
PluginWidgetProxy::SetNativeData(uint32_t aDataType, uintptr_t aVal)
{
if (!mActor) {
return;
}
auto tab = static_cast<mozilla::dom::TabChild*>(mActor->Manager());
if (tab && tab->IsDestroyed()) {
return;
}
switch (aDataType) {
case NS_NATIVE_CHILD_WINDOW:
mActor->SendSetNativeChildWindow(aVal);
break;
default:
NS_ERROR("SetNativeData called with unsupported data type.");
}
}
#endif
NS_IMETHODIMP
PluginWidgetProxy::SetFocus(bool aRaise)
{
ENSURE_CHANNEL;
PWLOG("PluginWidgetProxy::SetFocus(%d)\n", aRaise);
mActor->SendSetFocus(aRaise);
return NS_OK;
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,78 @@
/* 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/. */
#ifndef mozilla_widget_RemotePlugin_h__
#define mozilla_widget_RemotePlugin_h__
#include "PuppetWidget.h"
#include "mozilla/dom/TabChild.h"
/*
* PluginWidgetProxy is a nsIWidget wrapper we hand around in plugin and layout
* code. It wraps a native widget it creates in the chrome process. Since this
* is for plugins, only a limited set of the widget apis need to be overridden,
* the rest of the implementation is in PuppetWidget or nsBaseWidget.
*/
namespace mozilla {
namespace plugins {
class PluginWidgetChild;
} // namespace plugins
namespace widget {
class PluginWidgetProxy final : public PuppetWidget
{
public:
explicit PluginWidgetProxy(dom::TabChild* aTabChild,
mozilla::plugins::PluginWidgetChild* aChannel);
protected:
virtual ~PluginWidgetProxy();
public:
NS_DECL_ISUPPORTS_INHERITED
// nsIWidget
using PuppetWidget::Create; // for Create signature not overridden here
virtual MOZ_MUST_USE nsresult Create(nsIWidget* aParent,
nsNativeWidget aNativeParent,
const LayoutDeviceIntRect& aRect,
nsWidgetInitData* aInitData = nullptr)
override;
virtual void Destroy() override;
NS_IMETHOD SetFocus(bool aRaise = false) override;
NS_IMETHOD SetParent(nsIWidget* aNewParent) override;
virtual nsIWidget* GetParent(void) override;
virtual void* GetNativeData(uint32_t aDataType) override;
#if defined(XP_WIN)
void SetNativeData(uint32_t aDataType, uintptr_t aVal) override;
#endif
virtual nsTransparencyMode GetTransparencyMode() override
{ return eTransparencyOpaque; }
virtual void GetWindowClipRegion(nsTArray<LayoutDeviceIntRect>* aRects) override;
public:
/**
* When tabs are closed PPluginWidget can terminate before plugin code is
* finished tearing us down. When this happens plugin calls over mActor
* fail triggering an abort in the content process. To protect against this
* the connection tells us when it is torn down here so we can avoid making
* calls while content finishes tearing us down.
*/
void ChannelDestroyed() { mActor = nullptr; }
private:
// Our connection with the chrome widget, created on PBrowser.
mozilla::plugins::PluginWidgetChild* mActor;
// PuppetWidget does not implement parent apis, but we need
// them for plugin widgets.
nsCOMPtr<nsIWidget> mParent;
uintptr_t mCachedPluginPort;
};
} // namespace widget
} // namespace mozilla
#endif

View file

@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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 "PuppetBidiKeyboard.h"
using namespace mozilla::widget;
NS_IMPL_ISUPPORTS(PuppetBidiKeyboard, nsIBidiKeyboard)
PuppetBidiKeyboard::PuppetBidiKeyboard() : nsIBidiKeyboard()
{
}
PuppetBidiKeyboard::~PuppetBidiKeyboard()
{
}
NS_IMETHODIMP
PuppetBidiKeyboard::Reset()
{
return NS_OK;
}
NS_IMETHODIMP
PuppetBidiKeyboard::IsLangRTL(bool* aIsRTL)
{
*aIsRTL = mIsLangRTL;
return NS_OK;
}
void
PuppetBidiKeyboard::SetBidiKeyboardInfo(bool aIsLangRTL,
bool aHaveBidiKeyboards)
{
mIsLangRTL = aIsLangRTL;
mHaveBidiKeyboards = aHaveBidiKeyboards;
}
NS_IMETHODIMP
PuppetBidiKeyboard::GetHaveBidiKeyboards(bool* aResult)
{
*aResult = mHaveBidiKeyboards;
return NS_OK;
}

View file

@ -0,0 +1,36 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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/. */
#ifndef mozilla_widget_PuppetBidiKeyboard_h_
#define mozilla_widget_PuppetBidiKeyboard_h_
#include "nsIBidiKeyboard.h"
namespace mozilla {
namespace widget {
class PuppetBidiKeyboard final : public nsIBidiKeyboard
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIBIDIKEYBOARD
PuppetBidiKeyboard();
void SetBidiKeyboardInfo(bool aIsLangRTL, bool aHaveBidiKeyboards);
private:
~PuppetBidiKeyboard();
bool mIsLangRTL;
bool mHaveBidiKeyboards;
};
} // namespace widget
} // namespace mozilla
#endif // mozilla_widget_PuppetBidiKeyboard_h_

1580
widget/PuppetWidget.cpp Normal file

File diff suppressed because it is too large Load diff

463
widget/PuppetWidget.h Normal file
View file

@ -0,0 +1,463 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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/. */
/**
* This "puppet widget" isn't really a platform widget. It's intended
* to be used in widgetless rendering contexts, such as sandboxed
* content processes. If any "real" widgetry is needed, the request
* is forwarded to and/or data received from elsewhere.
*/
#ifndef mozilla_widget_PuppetWidget_h__
#define mozilla_widget_PuppetWidget_h__
#include "mozilla/gfx/2D.h"
#include "mozilla/RefPtr.h"
#include "nsBaseScreen.h"
#include "nsBaseWidget.h"
#include "nsCOMArray.h"
#include "nsIKeyEventInPluginCallback.h"
#include "nsIScreenManager.h"
#include "nsThreadUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/ContentCache.h"
#include "mozilla/EventForwards.h"
namespace mozilla {
namespace dom {
class TabChild;
} // namespace dom
namespace widget {
struct AutoCacheNativeKeyCommands;
class PuppetWidget : public nsBaseWidget
{
typedef mozilla::dom::TabChild TabChild;
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef nsBaseWidget Base;
typedef mozilla::CSSRect CSSRect;
// The width and height of the "widget" are clamped to this.
static const size_t kMaxDimension;
public:
explicit PuppetWidget(TabChild* aTabChild);
protected:
virtual ~PuppetWidget();
public:
NS_DECL_ISUPPORTS_INHERITED
// PuppetWidget creation is infallible, hence InfallibleCreate(), which
// Create() calls.
using nsBaseWidget::Create; // for Create signature not overridden here
virtual nsresult Create(nsIWidget* aParent,
nsNativeWidget aNativeParent,
const LayoutDeviceIntRect& aRect,
nsWidgetInitData* aInitData = nullptr)
override;
void InfallibleCreate(nsIWidget* aParent,
nsNativeWidget aNativeParent,
const LayoutDeviceIntRect& aRect,
nsWidgetInitData* aInitData = nullptr);
void InitIMEState();
virtual already_AddRefed<nsIWidget>
CreateChild(const LayoutDeviceIntRect& aRect,
nsWidgetInitData* aInitData = nullptr,
bool aForceUseIWidgetParent = false) override;
virtual void Destroy() override;
NS_IMETHOD Show(bool aState) override;
virtual bool IsVisible() const override
{ return mVisible; }
virtual void ConstrainPosition(bool /*ignored aAllowSlop*/,
int32_t* aX,
int32_t* aY) override
{ *aX = kMaxDimension; *aY = kMaxDimension; }
// Widget position is controlled by the parent process via TabChild.
NS_IMETHOD Move(double aX, double aY) override
{ return NS_OK; }
NS_IMETHOD Resize(double aWidth,
double aHeight,
bool aRepaint) override;
NS_IMETHOD Resize(double aX,
double aY,
double aWidth,
double aHeight,
bool aRepaint) override
{
if (mBounds.x != aX || mBounds.y != aY) {
NotifyWindowMoved(aX, aY);
}
mBounds.x = aX;
mBounds.y = aY;
return Resize(aWidth, aHeight, aRepaint);
}
// XXX/cjones: copying gtk behavior here; unclear what disabling a
// widget is supposed to entail
NS_IMETHOD Enable(bool aState) override
{ mEnabled = aState; return NS_OK; }
virtual bool IsEnabled() const override
{ return mEnabled; }
NS_IMETHOD SetFocus(bool aRaise = false) override;
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
NS_IMETHOD Invalidate(const LayoutDeviceIntRect& aRect) override;
// PuppetWidgets don't have native data, as they're purely nonnative.
virtual void* GetNativeData(uint32_t aDataType) override;
#if defined(XP_WIN)
void SetNativeData(uint32_t aDataType, uintptr_t aVal) override;
#endif
// PuppetWidgets don't have any concept of titles.
NS_IMETHOD SetTitle(const nsAString& aTitle) override
{ return NS_ERROR_UNEXPECTED; }
virtual LayoutDeviceIntPoint WidgetToScreenOffset() override
{ return LayoutDeviceIntPoint::FromUnknownPoint(GetWindowPosition() + GetChromeDimensions()); }
int32_t RoundsWidgetCoordinatesTo() override;
void InitEvent(WidgetGUIEvent& aEvent,
LayoutDeviceIntPoint* aPoint = nullptr);
NS_IMETHOD DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus) override;
nsEventStatus DispatchInputEvent(WidgetInputEvent* aEvent) override;
void SetConfirmedTargetAPZC(uint64_t aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets) const override;
void UpdateZoomConstraints(const uint32_t& aPresShellId,
const FrameMetrics::ViewID& aViewId,
const mozilla::Maybe<ZoomConstraints>& aConstraints) override;
bool AsyncPanZoomEnabled() const override;
NS_IMETHOD_(bool)
ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
const mozilla::WidgetKeyboardEvent& aEvent,
DoCommandCallback aCallback,
void* aCallbackData) override;
friend struct AutoCacheNativeKeyCommands;
//
// nsBaseWidget methods we override
//
// Documents loaded in child processes are always subdocuments of
// other docs in an ancestor process. To ensure that the
// backgrounds of those documents are painted like those of
// same-process subdocuments, we force the widget here to be
// transparent, which in turn will cause layout to use a transparent
// backstop background color.
virtual nsTransparencyMode GetTransparencyMode() override
{ return eTransparencyTransparent; }
virtual LayerManager*
GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT) override;
// This is used after a compositor reset.
LayerManager* RecreateLayerManager(PLayerTransactionChild* aShadowManager);
NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
const InputContextAction& aAction) override;
NS_IMETHOD_(InputContext) GetInputContext() override;
NS_IMETHOD_(NativeIMEContext) GetNativeIMEContext() override;
virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
NS_IMETHOD SetCursor(nsCursor aCursor) override;
NS_IMETHOD SetCursor(imgIContainer* aCursor,
uint32_t aHotspotX, uint32_t aHotspotY) override;
virtual void ClearCachedCursor() override;
// Gets the DPI of the screen corresponding to this widget.
// Contacts the parent process which gets the DPI from the
// proper widget there. TODO: Handle DPI changes that happen
// later on.
virtual float GetDPI() override;
virtual double GetDefaultScaleInternal() override;
virtual bool NeedsPaint() override;
// Paint the widget immediately if any paints are queued up.
void PaintNowIfNeeded();
virtual TabChild* GetOwningTabChild() override { return mTabChild; }
void UpdateBackingScaleCache(float aDpi, int32_t aRounding, double aScale)
{
mDPI = aDpi;
mRounding = aRounding;
mDefaultScale = aScale;
}
nsIntSize GetScreenDimensions();
// Get the size of the chrome of the window that this tab belongs to.
nsIntPoint GetChromeDimensions();
// Get the screen position of the application window.
nsIntPoint GetWindowPosition();
virtual LayoutDeviceIntRect GetScreenBounds() override;
NS_IMETHOD StartPluginIME(const mozilla::WidgetKeyboardEvent& aKeyboardEvent,
int32_t aPanelX, int32_t aPanelY,
nsString& aCommitted) override;
virtual void SetPluginFocused(bool& aFocused) override;
virtual void DefaultProcOfPluginEvent(
const mozilla::WidgetPluginEvent& aEvent) override;
virtual nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
int32_t aNativeKeyCode,
uint32_t aModifierFlags,
const nsAString& aCharacters,
const nsAString& aUnmodifiedCharacters,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
uint32_t aNativeMessage,
uint32_t aModifierFlags,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeMouseScrollEvent(LayoutDeviceIntPoint aPoint,
uint32_t aNativeMessage,
double aDeltaX,
double aDeltaY,
double aDeltaZ,
uint32_t aModifierFlags,
uint32_t aAdditionalFlags,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeTouchPoint(uint32_t aPointerId,
TouchPointerState aPointerState,
LayoutDeviceIntPoint aPoint,
double aPointerPressure,
uint32_t aPointerOrientation,
nsIObserver* aObserver) override;
virtual nsresult SynthesizeNativeTouchTap(LayoutDeviceIntPoint aPoint,
bool aLongTap,
nsIObserver* aObserver) override;
virtual nsresult ClearNativeTouchSequence(nsIObserver* aObserver) override;
virtual uint32_t GetMaxTouchPoints() const override;
virtual void StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics) override;
virtual void SetCandidateWindowForPlugin(
const CandidateWindowPosition& aPosition) override;
virtual void ZoomToRect(const uint32_t& aPresShellId,
const FrameMetrics::ViewID& aViewId,
const CSSRect& aRect,
const uint32_t& aFlags) override;
virtual bool HasPendingInputEvent() override;
void HandledWindowedPluginKeyEvent(const NativeEventData& aKeyEventData,
bool aIsConsumed);
virtual nsresult OnWindowedPluginKeyEvent(
const NativeEventData& aKeyEventData,
nsIKeyEventInPluginCallback* aCallback) override;
virtual void LookUpDictionary(
const nsAString& aText,
const nsTArray<mozilla::FontRange>& aFontRangeArray,
const bool aIsVertical,
const LayoutDeviceIntPoint& aPoint) override;
protected:
virtual nsresult NotifyIMEInternal(
const IMENotification& aIMENotification) override;
private:
nsresult Paint();
void SetChild(PuppetWidget* aChild);
nsresult RequestIMEToCommitComposition(bool aCancel);
nsresult NotifyIMEOfFocusChange(const IMENotification& aIMENotification);
nsresult NotifyIMEOfSelectionChange(const IMENotification& aIMENotification);
nsresult NotifyIMEOfCompositionUpdate(const IMENotification& aIMENotification);
nsresult NotifyIMEOfTextChange(const IMENotification& aIMENotification);
nsresult NotifyIMEOfMouseButtonEvent(const IMENotification& aIMENotification);
nsresult NotifyIMEOfPositionChange(const IMENotification& aIMENotification);
bool CacheEditorRect();
bool CacheCompositionRects(uint32_t& aStartOffset,
nsTArray<LayoutDeviceIntRect>& aRectArray,
uint32_t& aTargetCauseOffset);
bool GetCaretRect(LayoutDeviceIntRect& aCaretRect, uint32_t aCaretOffset);
uint32_t GetCaretOffset();
nsIWidgetListener* GetCurrentWidgetListener();
class PaintTask : public Runnable {
public:
NS_DECL_NSIRUNNABLE
explicit PaintTask(PuppetWidget* widget) : mWidget(widget) {}
void Revoke() { mWidget = nullptr; }
private:
PuppetWidget* mWidget;
};
class MemoryPressureObserver : public nsIObserver {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
explicit MemoryPressureObserver(PuppetWidget* aWidget) : mWidget(aWidget) {}
void Remove();
private:
virtual ~MemoryPressureObserver() {}
PuppetWidget* mWidget;
};
friend class MemoryPressureObserver;
// TabChild normally holds a strong reference to this PuppetWidget
// or its root ancestor, but each PuppetWidget also needs a
// reference back to TabChild (e.g. to delegate nsIWidget IME calls
// to chrome) So we hold a weak reference to TabChild here. Since
// it's possible for TabChild to outlive the PuppetWidget, we clear
// this weak reference in Destroy()
TabChild* mTabChild;
// The "widget" to which we delegate events if we don't have an
// event handler.
RefPtr<PuppetWidget> mChild;
LayoutDeviceIntRegion mDirtyRegion;
nsRevocableEventPtr<PaintTask> mPaintTask;
RefPtr<MemoryPressureObserver> mMemoryPressureObserver;
// XXX/cjones: keeping this around until we teach LayerManager to do
// retained-content-only transactions
RefPtr<DrawTarget> mDrawTarget;
// IME
nsIMEUpdatePreference mIMEPreferenceOfParent;
InputContext mInputContext;
// mNativeIMEContext is initialized when this dispatches every composition
// event both from parent process's widget and TextEventDispatcher in same
// process. If it hasn't been started composition yet, this isn't necessary
// for XP code since there is no TextComposition instance which is caused by
// the PuppetWidget instance.
NativeIMEContext mNativeIMEContext;
ContentCacheInChild mContentCache;
// The DPI of the screen corresponding to this widget
float mDPI;
int32_t mRounding;
double mDefaultScale;
// Precomputed answers for ExecuteNativeKeyBinding
InfallibleTArray<mozilla::CommandInt> mSingleLineCommands;
InfallibleTArray<mozilla::CommandInt> mMultiLineCommands;
InfallibleTArray<mozilla::CommandInt> mRichTextCommands;
nsCOMPtr<imgIContainer> mCustomCursor;
uint32_t mCursorHotspotX, mCursorHotspotY;
nsCOMArray<nsIKeyEventInPluginCallback> mKeyEventInPluginCallbacks;
protected:
bool mEnabled;
bool mVisible;
private:
bool mNeedIMEStateInit;
bool mNativeKeyCommandsValid;
};
struct AutoCacheNativeKeyCommands
{
explicit AutoCacheNativeKeyCommands(PuppetWidget* aWidget)
: mWidget(aWidget)
{
mSavedValid = mWidget->mNativeKeyCommandsValid;
mSavedSingleLine = mWidget->mSingleLineCommands;
mSavedMultiLine = mWidget->mMultiLineCommands;
mSavedRichText = mWidget->mRichTextCommands;
}
void Cache(const InfallibleTArray<mozilla::CommandInt>& aSingleLineCommands,
const InfallibleTArray<mozilla::CommandInt>& aMultiLineCommands,
const InfallibleTArray<mozilla::CommandInt>& aRichTextCommands)
{
mWidget->mNativeKeyCommandsValid = true;
mWidget->mSingleLineCommands = aSingleLineCommands;
mWidget->mMultiLineCommands = aMultiLineCommands;
mWidget->mRichTextCommands = aRichTextCommands;
}
void CacheNoCommands()
{
mWidget->mNativeKeyCommandsValid = true;
mWidget->mSingleLineCommands.Clear();
mWidget->mMultiLineCommands.Clear();
mWidget->mRichTextCommands.Clear();
}
~AutoCacheNativeKeyCommands()
{
mWidget->mNativeKeyCommandsValid = mSavedValid;
mWidget->mSingleLineCommands = mSavedSingleLine;
mWidget->mMultiLineCommands = mSavedMultiLine;
mWidget->mRichTextCommands = mSavedRichText;
}
private:
PuppetWidget* mWidget;
bool mSavedValid;
InfallibleTArray<mozilla::CommandInt> mSavedSingleLine;
InfallibleTArray<mozilla::CommandInt> mSavedMultiLine;
InfallibleTArray<mozilla::CommandInt> mSavedRichText;
};
class PuppetScreen : public nsBaseScreen
{
public:
explicit PuppetScreen(void* nativeScreen);
~PuppetScreen();
NS_IMETHOD GetId(uint32_t* aId) override;
NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight) override;
NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight) override;
NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) override;
NS_IMETHOD GetColorDepth(int32_t* aColorDepth) override;
NS_IMETHOD GetRotation(uint32_t* aRotation) override;
NS_IMETHOD SetRotation(uint32_t aRotation) override;
};
class PuppetScreenManager final : public nsIScreenManager
{
~PuppetScreenManager();
public:
PuppetScreenManager();
NS_DECL_ISUPPORTS
NS_DECL_NSISCREENMANAGER
protected:
nsCOMPtr<nsIScreen> mOneScreen;
};
} // namespace widget
} // namespace mozilla
#endif // mozilla_widget_PuppetWidget_h__

189
widget/ScreenProxy.cpp Normal file
View file

@ -0,0 +1,189 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* 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 "mozilla/Unused.h"
#include "nsContentUtils.h"
#include "nsIAppShell.h"
#include "nsScreenManagerProxy.h"
#include "nsServiceManagerUtils.h"
#include "nsWidgetsCID.h"
#include "ScreenProxy.h"
namespace mozilla {
namespace widget {
using namespace mozilla::dom;
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
ScreenProxy::ScreenProxy(nsScreenManagerProxy* aScreenManager, ScreenDetails aDetails)
: mContentsScaleFactor(0)
, mScreenManager(aScreenManager)
, mId(0)
, mPixelDepth(0)
, mColorDepth(0)
, mCacheValid(false)
, mCacheWillInvalidate(false)
{
PopulateByDetails(aDetails);
}
NS_IMETHODIMP
ScreenProxy::GetId(uint32_t *outId)
{
*outId = mId;
return NS_OK;
}
NS_IMETHODIMP
ScreenProxy::GetRect(int32_t *outLeft,
int32_t *outTop,
int32_t *outWidth,
int32_t *outHeight)
{
if (!EnsureCacheIsValid()) {
return NS_ERROR_FAILURE;
}
*outLeft = mRect.x;
*outTop = mRect.y;
*outWidth = mRect.width;
*outHeight = mRect.height;
return NS_OK;
}
NS_IMETHODIMP
ScreenProxy::GetRectDisplayPix(int32_t *outLeft,
int32_t *outTop,
int32_t *outWidth,
int32_t *outHeight)
{
if (!EnsureCacheIsValid()) {
return NS_ERROR_FAILURE;
}
*outLeft = mRectDisplayPix.x;
*outTop = mRectDisplayPix.y;
*outWidth = mRectDisplayPix.width;
*outHeight = mRectDisplayPix.height;
return NS_OK;
}
NS_IMETHODIMP
ScreenProxy::GetAvailRect(int32_t *outLeft,
int32_t *outTop,
int32_t *outWidth,
int32_t *outHeight)
{
if (!EnsureCacheIsValid()) {
return NS_ERROR_FAILURE;
}
*outLeft = mAvailRect.x;
*outTop = mAvailRect.y;
*outWidth = mAvailRect.width;
*outHeight = mAvailRect.height;
return NS_OK;
}
NS_IMETHODIMP
ScreenProxy::GetAvailRectDisplayPix(int32_t *outLeft,
int32_t *outTop,
int32_t *outWidth,
int32_t *outHeight)
{
if (!EnsureCacheIsValid()) {
return NS_ERROR_FAILURE;
}
*outLeft = mAvailRectDisplayPix.x;
*outTop = mAvailRectDisplayPix.y;
*outWidth = mAvailRectDisplayPix.width;
*outHeight = mAvailRectDisplayPix.height;
return NS_OK;
}
NS_IMETHODIMP
ScreenProxy::GetPixelDepth(int32_t *aPixelDepth)
{
if (!EnsureCacheIsValid()) {
return NS_ERROR_FAILURE;
}
*aPixelDepth = mPixelDepth;
return NS_OK;
}
NS_IMETHODIMP
ScreenProxy::GetColorDepth(int32_t *aColorDepth)
{
if (!EnsureCacheIsValid()) {
return NS_ERROR_FAILURE;
}
*aColorDepth = mColorDepth;
return NS_OK;
}
void
ScreenProxy::PopulateByDetails(ScreenDetails aDetails)
{
mId = aDetails.id();
mRect = nsIntRect(aDetails.rect());
mRectDisplayPix = nsIntRect(aDetails.rectDisplayPix());
mAvailRect = nsIntRect(aDetails.availRect());
mAvailRectDisplayPix = nsIntRect(aDetails.availRectDisplayPix());
mPixelDepth = aDetails.pixelDepth();
mColorDepth = aDetails.colorDepth();
mContentsScaleFactor = aDetails.contentsScaleFactor();
}
bool
ScreenProxy::EnsureCacheIsValid()
{
if (mCacheValid) {
return true;
}
bool success = false;
// Kick off a synchronous IPC call to the parent to get the
// most up-to-date information.
ScreenDetails details;
Unused << mScreenManager->SendScreenRefresh(mId, &details, &success);
if (!success) {
NS_WARNING("Updating a ScreenProxy in the child process failed on parent side.");
return false;
}
PopulateByDetails(details);
mCacheValid = true;
InvalidateCacheOnNextTick();
return true;
}
void
ScreenProxy::InvalidateCacheOnNextTick()
{
if (mCacheWillInvalidate) {
return;
}
mCacheWillInvalidate = true;
nsContentUtils::RunInStableState(NewRunnableMethod(this, &ScreenProxy::InvalidateCache));
}
void
ScreenProxy::InvalidateCache()
{
mCacheValid = false;
mCacheWillInvalidate = false;
}
} // namespace widget
} // namespace mozilla

71
widget/ScreenProxy.h Normal file
View file

@ -0,0 +1,71 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* 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/. */
#ifndef mozilla_widget_ScreenProxy_h
#define mozilla_widget_ScreenProxy_h
#include "nsBaseScreen.h"
#include "mozilla/dom/PScreenManagerChild.h"
#include "mozilla/dom/TabChild.h"
class nsScreenManagerProxy;
namespace mozilla {
namespace widget {
class ScreenProxy : public nsBaseScreen
{
public:
ScreenProxy(nsScreenManagerProxy* aScreenManager,
mozilla::dom::ScreenDetails aDetails);
~ScreenProxy() {};
NS_IMETHOD GetId(uint32_t* aId) override;
NS_IMETHOD GetRect(int32_t* aLeft,
int32_t* aTop,
int32_t* aWidth,
int32_t* aHeight) override;
NS_IMETHOD GetRectDisplayPix(int32_t* aLeft,
int32_t* aTop,
int32_t* aWidth,
int32_t* aHeight) override;
NS_IMETHOD GetAvailRect(int32_t* aLeft,
int32_t* aTop,
int32_t* aWidth,
int32_t* aHeight) override;
NS_IMETHOD GetAvailRectDisplayPix(int32_t* aLeft,
int32_t* aTop,
int32_t* aWidth,
int32_t* aHeight) override;
NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth) override;
NS_IMETHOD GetColorDepth(int32_t* aColorDepth) override;
private:
void PopulateByDetails(mozilla::dom::ScreenDetails aDetails);
bool EnsureCacheIsValid();
void InvalidateCacheOnNextTick();
void InvalidateCache();
double mContentsScaleFactor;
RefPtr<nsScreenManagerProxy> mScreenManager;
uint32_t mId;
int32_t mPixelDepth;
int32_t mColorDepth;
nsIntRect mRect;
nsIntRect mRectDisplayPix;
nsIntRect mAvailRect;
nsIntRect mAvailRectDisplayPix;
bool mCacheValid;
bool mCacheWillInvalidate;
};
} // namespace widget
} // namespace mozilla
#endif

View file

@ -0,0 +1,178 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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 "WidgetUtils.h"
#include "mozilla/TextEvents.h"
#include "nsIBaseWindow.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShell.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsPIDOMWindow.h"
namespace mozilla {
namespace widget {
// static
void
WidgetUtils::Shutdown()
{
WidgetKeyboardEvent::Shutdown();
}
// static
already_AddRefed<nsIWidget>
WidgetUtils::DOMWindowToWidget(nsPIDOMWindowOuter* aDOMWindow)
{
nsCOMPtr<nsIWidget> widget;
nsCOMPtr<nsPIDOMWindowOuter> window = aDOMWindow;
if (window) {
nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(window->GetDocShell()));
while (!widget && baseWin) {
baseWin->GetParentWidget(getter_AddRefs(widget));
if (!widget) {
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(baseWin));
if (!docShellAsItem)
return nullptr;
nsCOMPtr<nsIDocShellTreeItem> parent;
docShellAsItem->GetParent(getter_AddRefs(parent));
window = do_GetInterface(parent);
if (!window)
return nullptr;
baseWin = do_QueryInterface(window->GetDocShell());
}
}
}
return widget.forget();
}
// static
uint32_t
WidgetUtils::ComputeKeyCodeFromChar(uint32_t aCharCode)
{
if (aCharCode >= 'A' && aCharCode <= 'Z') {
return aCharCode - 'A' + NS_VK_A;
}
if (aCharCode >= 'a' && aCharCode <= 'z') {
return aCharCode - 'a' + NS_VK_A;
}
if (aCharCode >= '0' && aCharCode <= '9') {
return aCharCode - '0' + NS_VK_0;
}
switch (aCharCode) {
case ' ': return NS_VK_SPACE;
case '\t': return NS_VK_TAB;
case ':': return NS_VK_COLON;
case ';': return NS_VK_SEMICOLON;
case '<': return NS_VK_LESS_THAN;
case '=': return NS_VK_EQUALS;
case '>': return NS_VK_GREATER_THAN;
case '?': return NS_VK_QUESTION_MARK;
case '@': return NS_VK_AT;
case '^': return NS_VK_CIRCUMFLEX;
case '!': return NS_VK_EXCLAMATION;
case '"': return NS_VK_DOUBLE_QUOTE;
case '#': return NS_VK_HASH;
case '$': return NS_VK_DOLLAR;
case '%': return NS_VK_PERCENT;
case '&': return NS_VK_AMPERSAND;
case '_': return NS_VK_UNDERSCORE;
case '(': return NS_VK_OPEN_PAREN;
case ')': return NS_VK_CLOSE_PAREN;
case '*': return NS_VK_ASTERISK;
case '+': return NS_VK_PLUS;
case '|': return NS_VK_PIPE;
case '-': return NS_VK_HYPHEN_MINUS;
case '{': return NS_VK_OPEN_CURLY_BRACKET;
case '}': return NS_VK_CLOSE_CURLY_BRACKET;
case '~': return NS_VK_TILDE;
case ',': return NS_VK_COMMA;
case '.': return NS_VK_PERIOD;
case '/': return NS_VK_SLASH;
case '`': return NS_VK_BACK_QUOTE;
case '[': return NS_VK_OPEN_BRACKET;
case '\\': return NS_VK_BACK_SLASH;
case ']': return NS_VK_CLOSE_BRACKET;
case '\'': return NS_VK_QUOTE;
}
return 0;
}
// static
void
WidgetUtils::GetLatinCharCodeForKeyCode(uint32_t aKeyCode,
bool aIsCapsLock,
uint32_t* aUnshiftedCharCode,
uint32_t* aShiftedCharCode)
{
MOZ_ASSERT(aUnshiftedCharCode && aShiftedCharCode,
"aUnshiftedCharCode and aShiftedCharCode must not be NULL");
if (aKeyCode >= NS_VK_A && aKeyCode <= NS_VK_Z) {
*aUnshiftedCharCode = *aShiftedCharCode = aKeyCode;
if (aIsCapsLock) {
*aShiftedCharCode += 0x20;
} else {
*aUnshiftedCharCode += 0x20;
}
return;
}
// aShiftedCharCode must be zero for non-alphabet keys.
*aShiftedCharCode = 0;
if (aKeyCode >= NS_VK_0 && aKeyCode <= NS_VK_9) {
*aUnshiftedCharCode = aKeyCode;
return;
}
switch (aKeyCode) {
case NS_VK_SPACE: *aUnshiftedCharCode = ' '; break;
case NS_VK_COLON: *aUnshiftedCharCode = ':'; break;
case NS_VK_SEMICOLON: *aUnshiftedCharCode = ';'; break;
case NS_VK_LESS_THAN: *aUnshiftedCharCode = '<'; break;
case NS_VK_EQUALS: *aUnshiftedCharCode = '='; break;
case NS_VK_GREATER_THAN: *aUnshiftedCharCode = '>'; break;
case NS_VK_QUESTION_MARK: *aUnshiftedCharCode = '?'; break;
case NS_VK_AT: *aUnshiftedCharCode = '@'; break;
case NS_VK_CIRCUMFLEX: *aUnshiftedCharCode = '^'; break;
case NS_VK_EXCLAMATION: *aUnshiftedCharCode = '!'; break;
case NS_VK_DOUBLE_QUOTE: *aUnshiftedCharCode = '"'; break;
case NS_VK_HASH: *aUnshiftedCharCode = '#'; break;
case NS_VK_DOLLAR: *aUnshiftedCharCode = '$'; break;
case NS_VK_PERCENT: *aUnshiftedCharCode = '%'; break;
case NS_VK_AMPERSAND: *aUnshiftedCharCode = '&'; break;
case NS_VK_UNDERSCORE: *aUnshiftedCharCode = '_'; break;
case NS_VK_OPEN_PAREN: *aUnshiftedCharCode = '('; break;
case NS_VK_CLOSE_PAREN: *aUnshiftedCharCode = ')'; break;
case NS_VK_ASTERISK: *aUnshiftedCharCode = '*'; break;
case NS_VK_PLUS: *aUnshiftedCharCode = '+'; break;
case NS_VK_PIPE: *aUnshiftedCharCode = '|'; break;
case NS_VK_HYPHEN_MINUS: *aUnshiftedCharCode = '-'; break;
case NS_VK_OPEN_CURLY_BRACKET: *aUnshiftedCharCode = '{'; break;
case NS_VK_CLOSE_CURLY_BRACKET: *aUnshiftedCharCode = '}'; break;
case NS_VK_TILDE: *aUnshiftedCharCode = '~'; break;
case NS_VK_COMMA: *aUnshiftedCharCode = ','; break;
case NS_VK_PERIOD: *aUnshiftedCharCode = '.'; break;
case NS_VK_SLASH: *aUnshiftedCharCode = '/'; break;
case NS_VK_BACK_QUOTE: *aUnshiftedCharCode = '`'; break;
case NS_VK_OPEN_BRACKET: *aUnshiftedCharCode = '['; break;
case NS_VK_BACK_SLASH: *aUnshiftedCharCode = '\\'; break;
case NS_VK_CLOSE_BRACKET: *aUnshiftedCharCode = ']'; break;
case NS_VK_QUOTE: *aUnshiftedCharCode = '\''; break;
default: *aUnshiftedCharCode = 0; break;
}
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,231 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef SystemTimeConverter_h
#define SystemTimeConverter_h
#include <limits>
#include "mozilla/TimeStamp.h"
#include "mozilla/TypeTraits.h"
namespace mozilla {
// Utility class that converts time values represented as an unsigned integral
// number of milliseconds from one time source (e.g. a native event time) to
// corresponding mozilla::TimeStamp objects.
//
// This class handles wrapping of integer values and skew between the time
// source and mozilla::TimeStamp values.
//
// It does this by using an historical reference time recorded in both time
// scales (i.e. both as a numerical time value and as a TimeStamp).
//
// For performance reasons, this class is careful to minimize calls to the
// native "current time" function (e.g. gdk_x11_server_get_time) since this can
// be slow.
template <typename Time>
class SystemTimeConverter {
public:
SystemTimeConverter()
: mReferenceTime(Time(0))
, mReferenceTimeStamp() // Initializes to the null timestamp
, mLastBackwardsSkewCheck(Time(0))
, kTimeRange(std::numeric_limits<Time>::max())
, kTimeHalfRange(kTimeRange / 2)
, kBackwardsSkewCheckInterval(Time(2000))
{
static_assert(!IsSigned<Time>::value, "Expected Time to be unsigned");
}
template <typename CurrentTimeGetter>
mozilla::TimeStamp
GetTimeStampFromSystemTime(Time aTime,
CurrentTimeGetter& aCurrentTimeGetter) {
// If the reference time is not set, use the current time value to fill
// it in.
if (mReferenceTimeStamp.IsNull()) {
UpdateReferenceTime(aTime, aCurrentTimeGetter);
}
TimeStamp roughlyNow = TimeStamp::Now();
// Check for skew between the source of Time values and TimeStamp values.
// We do this by comparing two durations (both in ms):
//
// i. The duration from the reference time to the passed-in time.
// (timeDelta in the diagram below)
// ii. The duration from the reference timestamp to the current time
// based on TimeStamp::Now.
// (timeStampDelta in the diagram below)
//
// Normally, we'd expect (ii) to be slightly larger than (i) to account
// for the time taken between generating the event and processing it.
//
// If (ii) - (i) is negative then the source of Time values is getting
// "ahead" of TimeStamp. We call this "forwards" skew below.
//
// For the reverse case, if (ii) - (i) is positive (and greater than some
// tolerance factor), then we may have "backwards" skew. This is often
// the case when we have a backlog of events and by the time we process
// them, the time given by the system is comparatively "old".
//
// We call the absolute difference between (i) and (ii), "deltaFromNow".
//
// Graphically:
//
// mReferenceTime aTime
// Time scale: ........+.......................*........
// |--------timeDelta------|
//
// mReferenceTimeStamp roughlyNow
// TimeStamp scale: ........+...........................*....
// |------timeStampDelta-------|
//
// |---|
// deltaFromNow
//
Time deltaFromNow;
bool newer = IsTimeNewerThanTimestamp(aTime, roughlyNow, &deltaFromNow);
// Tolerance when detecting clock skew.
static const Time kTolerance = 30;
// Check for forwards skew
if (newer) {
// Make aTime correspond to roughlyNow
UpdateReferenceTime(aTime, roughlyNow);
// We didn't have backwards skew so don't bother checking for
// backwards skew again for a little while.
mLastBackwardsSkewCheck = aTime;
return roughlyNow;
}
if (deltaFromNow <= kTolerance) {
// If the time between event times and TimeStamp values is within
// the tolerance then assume we don't have clock skew so we can
// avoid checking for backwards skew for a while.
mLastBackwardsSkewCheck = aTime;
} else if (aTime - mLastBackwardsSkewCheck > kBackwardsSkewCheckInterval) {
aCurrentTimeGetter.GetTimeAsyncForPossibleBackwardsSkew(roughlyNow);
mLastBackwardsSkewCheck = aTime;
}
// Finally, calculate the timestamp
return roughlyNow - TimeDuration::FromMilliseconds(deltaFromNow);
}
void
CompensateForBackwardsSkew(Time aReferenceTime,
const TimeStamp &aLowerBound) {
// Check if we actually have backwards skew. Backwards skew looks like
// the following:
//
// mReferenceTime
// Time: ..+...a...b...c..........................
//
// mReferenceTimeStamp
// TimeStamp: ..+.....a.....b.....c....................
//
// Converted
// time: ......a'..b'..c'.........................
//
// What we need to do is bring mReferenceTime "forwards".
//
// Suppose when we get (c), we detect possible backwards skew and trigger
// an async request for the current time (which is passed in here as
// aReferenceTime).
//
// We end up with something like the following:
//
// mReferenceTime aReferenceTime
// Time: ..+...a...b...c...v......................
//
// mReferenceTimeStamp
// TimeStamp: ..+.....a.....b.....c..........x.........
// ^ ^
// aLowerBound TimeStamp::Now()
//
// If the duration (aLowerBound - mReferenceTimeStamp) is greater than
// (aReferenceTime - mReferenceTime) then we know we have backwards skew.
//
// If that's not the case, then we probably just got caught behind
// temporarily.
Time delta;
if (IsTimeNewerThanTimestamp(aReferenceTime, aLowerBound, &delta)) {
return;
}
// We have backwards skew; the equivalent TimeStamp for aReferenceTime lies
// somewhere between aLowerBound (which was the TimeStamp when we triggered
// the async request for the current time) and TimeStamp::Now().
//
// If aReferenceTime was waiting in the event queue for a long time, the
// equivalent TimeStamp might be much closer to aLowerBound than
// TimeStamp::Now() so for now we just set it to aLowerBound. That's
// guaranteed to be at least somewhat of an improvement.
UpdateReferenceTime(aReferenceTime, aLowerBound);
}
private:
template <typename CurrentTimeGetter>
void
UpdateReferenceTime(Time aReferenceTime,
const CurrentTimeGetter& aCurrentTimeGetter) {
Time currentTime = aCurrentTimeGetter.GetCurrentTime();
TimeStamp currentTimeStamp = TimeStamp::Now();
Time timeSinceReference = currentTime - aReferenceTime;
TimeStamp referenceTimeStamp =
currentTimeStamp - TimeDuration::FromMilliseconds(timeSinceReference);
UpdateReferenceTime(aReferenceTime, referenceTimeStamp);
}
void
UpdateReferenceTime(Time aReferenceTime,
const TimeStamp& aReferenceTimeStamp) {
mReferenceTime = aReferenceTime;
mReferenceTimeStamp = aReferenceTimeStamp;
}
bool
IsTimeNewerThanTimestamp(Time aTime, TimeStamp aTimeStamp, Time* aDelta)
{
Time timeDelta = aTime - mReferenceTime;
// Cast the result to signed 64-bit integer first since that should be
// enough to hold the range of values returned by ToMilliseconds() and
// the result of converting from double to an integer-type when the value
// is outside the integer range is undefined.
// Then we do an implicit cast to Time (typically an unsigned 32-bit
// integer) which wraps times outside that range.
Time timeStampDelta =
static_cast<int64_t>((aTimeStamp - mReferenceTimeStamp).ToMilliseconds());
Time timeToTimeStamp = timeStampDelta - timeDelta;
bool isNewer = false;
if (timeToTimeStamp == 0) {
*aDelta = 0;
} else if (timeToTimeStamp < kTimeHalfRange) {
*aDelta = timeToTimeStamp;
} else {
isNewer = true;
*aDelta = timeDelta - timeStampDelta;
}
return isNewer;
}
Time mReferenceTime;
TimeStamp mReferenceTimeStamp;
Time mLastBackwardsSkewCheck;
const Time kTimeRange;
const Time kTimeHalfRange;
const Time kBackwardsSkewCheckInterval;
};
} // namespace mozilla
#endif /* SystemTimeConverter_h */

View file

@ -0,0 +1,780 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "mozilla/Preferences.h"
#include "mozilla/TextEvents.h"
#include "mozilla/TextEventDispatcher.h"
#include "nsIDocShell.h"
#include "nsIFrame.h"
#include "nsIPresShell.h"
#include "nsIWidget.h"
#include "nsPIDOMWindow.h"
#include "nsView.h"
namespace mozilla {
namespace widget {
/******************************************************************************
* TextEventDispatcher
*****************************************************************************/
bool TextEventDispatcher::sDispatchKeyEventsDuringComposition = false;
TextEventDispatcher::TextEventDispatcher(nsIWidget* aWidget)
: mWidget(aWidget)
, mDispatchingEvent(0)
, mInputTransactionType(eNoInputTransaction)
, mIsComposing(false)
{
MOZ_RELEASE_ASSERT(mWidget, "aWidget must not be nullptr");
static bool sInitialized = false;
if (!sInitialized) {
Preferences::AddBoolVarCache(
&sDispatchKeyEventsDuringComposition,
"dom.keyboardevent.dispatch_during_composition",
false);
sInitialized = true;
}
}
nsresult
TextEventDispatcher::BeginInputTransaction(
TextEventDispatcherListener* aListener)
{
return BeginInputTransactionInternal(aListener,
eSameProcessSyncInputTransaction);
}
nsresult
TextEventDispatcher::BeginTestInputTransaction(
TextEventDispatcherListener* aListener,
bool aIsAPZAware)
{
return BeginInputTransactionInternal(aListener,
aIsAPZAware ? eAsyncTestInputTransaction :
eSameProcessSyncTestInputTransaction);
}
nsresult
TextEventDispatcher::BeginNativeInputTransaction()
{
if (NS_WARN_IF(!mWidget)) {
return NS_ERROR_FAILURE;
}
RefPtr<TextEventDispatcherListener> listener =
mWidget->GetNativeTextEventDispatcherListener();
if (NS_WARN_IF(!listener)) {
return NS_ERROR_FAILURE;
}
return BeginInputTransactionInternal(listener, eNativeInputTransaction);
}
nsresult
TextEventDispatcher::BeginInputTransactionInternal(
TextEventDispatcherListener* aListener,
InputTransactionType aType)
{
if (NS_WARN_IF(!aListener)) {
return NS_ERROR_INVALID_ARG;
}
nsCOMPtr<TextEventDispatcherListener> listener = do_QueryReferent(mListener);
if (listener) {
if (listener == aListener && mInputTransactionType == aType) {
return NS_OK;
}
// If this has composition or is dispatching an event, any other listener
// can steal ownership. Especially, if the latter case is allowed,
// nobody cannot begin input transaction with this if a modal dialog is
// opened during dispatching an event.
if (IsComposing() || IsDispatchingEvent()) {
return NS_ERROR_ALREADY_INITIALIZED;
}
}
mListener = do_GetWeakReference(aListener);
mInputTransactionType = aType;
if (listener && listener != aListener) {
listener->OnRemovedFrom(this);
}
return NS_OK;
}
void
TextEventDispatcher::EndInputTransaction(TextEventDispatcherListener* aListener)
{
if (NS_WARN_IF(IsComposing()) || NS_WARN_IF(IsDispatchingEvent())) {
return;
}
mInputTransactionType = eNoInputTransaction;
nsCOMPtr<TextEventDispatcherListener> listener = do_QueryReferent(mListener);
if (NS_WARN_IF(!listener)) {
return;
}
if (NS_WARN_IF(listener != aListener)) {
return;
}
mListener = nullptr;
listener->OnRemovedFrom(this);
}
void
TextEventDispatcher::OnDestroyWidget()
{
mWidget = nullptr;
mPendingComposition.Clear();
nsCOMPtr<TextEventDispatcherListener> listener = do_QueryReferent(mListener);
mListener = nullptr;
mInputTransactionType = eNoInputTransaction;
if (listener) {
listener->OnRemovedFrom(this);
}
}
nsresult
TextEventDispatcher::GetState() const
{
nsCOMPtr<TextEventDispatcherListener> listener = do_QueryReferent(mListener);
if (!listener) {
return NS_ERROR_NOT_INITIALIZED;
}
if (!mWidget || mWidget->Destroyed()) {
return NS_ERROR_NOT_AVAILABLE;
}
return NS_OK;
}
void
TextEventDispatcher::InitEvent(WidgetGUIEvent& aEvent) const
{
aEvent.mTime = PR_IntervalNow();
aEvent.mRefPoint = LayoutDeviceIntPoint(0, 0);
aEvent.mFlags.mIsSynthesizedForTests = IsForTests();
if (aEvent.mClass != eCompositionEventClass) {
return;
}
void* pseudoIMEContext = GetPseudoIMEContext();
if (pseudoIMEContext) {
aEvent.AsCompositionEvent()->mNativeIMEContext.
InitWithRawNativeIMEContext(pseudoIMEContext);
}
#ifdef DEBUG
else {
MOZ_ASSERT(!XRE_IsContentProcess(),
"Why did the content process start native event transaction?");
MOZ_ASSERT(aEvent.AsCompositionEvent()->mNativeIMEContext.IsValid(),
"Native IME context shouldn't be invalid");
}
#endif // #ifdef DEBUG
}
nsresult
TextEventDispatcher::DispatchEvent(nsIWidget* aWidget,
WidgetGUIEvent& aEvent,
nsEventStatus& aStatus)
{
MOZ_ASSERT(!aEvent.AsInputEvent(), "Use DispatchInputEvent()");
RefPtr<TextEventDispatcher> kungFuDeathGrip(this);
nsCOMPtr<nsIWidget> widget(aWidget);
mDispatchingEvent++;
nsresult rv = widget->DispatchEvent(&aEvent, aStatus);
mDispatchingEvent--;
return rv;
}
nsresult
TextEventDispatcher::DispatchInputEvent(nsIWidget* aWidget,
WidgetInputEvent& aEvent,
nsEventStatus& aStatus)
{
RefPtr<TextEventDispatcher> kungFuDeathGrip(this);
nsCOMPtr<nsIWidget> widget(aWidget);
mDispatchingEvent++;
// If the event is dispatched via nsIWidget::DispatchInputEvent(), it
// sends the event to the parent process first since APZ needs to handle it
// first. However, some callers (e.g., keyboard apps on B2G and tests
// expecting synchronous dispatch) don't want this to do that.
nsresult rv = NS_OK;
if (ShouldSendInputEventToAPZ()) {
aStatus = widget->DispatchInputEvent(&aEvent);
} else {
rv = widget->DispatchEvent(&aEvent, aStatus);
}
mDispatchingEvent--;
return rv;
}
nsresult
TextEventDispatcher::StartComposition(nsEventStatus& aStatus,
const WidgetEventTime* aEventTime)
{
aStatus = nsEventStatus_eIgnore;
nsresult rv = GetState();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (NS_WARN_IF(mIsComposing)) {
return NS_ERROR_FAILURE;
}
mIsComposing = true;
WidgetCompositionEvent compositionStartEvent(true, eCompositionStart,
mWidget);
InitEvent(compositionStartEvent);
if (aEventTime) {
compositionStartEvent.AssignEventTime(*aEventTime);
}
rv = DispatchEvent(mWidget, compositionStartEvent, aStatus);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
nsresult
TextEventDispatcher::StartCompositionAutomaticallyIfNecessary(
nsEventStatus& aStatus,
const WidgetEventTime* aEventTime)
{
if (IsComposing()) {
return NS_OK;
}
nsresult rv = StartComposition(aStatus, aEventTime);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// If started composition has already been committed, we shouldn't dispatch
// the compositionchange event.
if (!IsComposing()) {
aStatus = nsEventStatus_eConsumeNoDefault;
return NS_OK;
}
// Note that the widget might be destroyed during a call of
// StartComposition(). In such case, we shouldn't keep dispatching next
// event.
rv = GetState();
if (NS_FAILED(rv)) {
MOZ_ASSERT(rv != NS_ERROR_NOT_INITIALIZED,
"aDispatcher must still be initialized in this case");
aStatus = nsEventStatus_eConsumeNoDefault;
return NS_OK; // Don't throw exception in this case
}
aStatus = nsEventStatus_eIgnore;
return NS_OK;
}
nsresult
TextEventDispatcher::CommitComposition(nsEventStatus& aStatus,
const nsAString* aCommitString,
const WidgetEventTime* aEventTime)
{
aStatus = nsEventStatus_eIgnore;
nsresult rv = GetState();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// When there is no composition, caller shouldn't try to commit composition
// with non-existing composition string nor commit composition with empty
// string.
if (NS_WARN_IF(!IsComposing() &&
(!aCommitString || aCommitString->IsEmpty()))) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIWidget> widget(mWidget);
rv = StartCompositionAutomaticallyIfNecessary(aStatus, aEventTime);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (aStatus == nsEventStatus_eConsumeNoDefault) {
return NS_OK;
}
// End current composition and make this free for other IMEs.
mIsComposing = false;
EventMessage message = aCommitString ? eCompositionCommit :
eCompositionCommitAsIs;
WidgetCompositionEvent compositionCommitEvent(true, message, widget);
InitEvent(compositionCommitEvent);
if (aEventTime) {
compositionCommitEvent.AssignEventTime(*aEventTime);
}
if (message == eCompositionCommit) {
compositionCommitEvent.mData = *aCommitString;
// Don't send CRLF, replace it with LF here.
compositionCommitEvent.mData.ReplaceSubstring(NS_LITERAL_STRING("\r\n"),
NS_LITERAL_STRING("\n"));
}
rv = DispatchEvent(widget, compositionCommitEvent, aStatus);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
nsresult
TextEventDispatcher::NotifyIME(const IMENotification& aIMENotification)
{
nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
// First, send the notification to current input transaction's listener.
nsCOMPtr<TextEventDispatcherListener> listener = do_QueryReferent(mListener);
if (listener) {
rv = listener->NotifyIME(this, aIMENotification);
}
if (mInputTransactionType == eNativeInputTransaction || !mWidget) {
return rv;
}
// If current input transaction isn't for native event handler, we should
// send the notification to the native text event dispatcher listener
// since native event handler may need to do something from
// TextEventDispatcherListener::NotifyIME() even before there is no
// input transaction yet. For example, native IME handler may need to
// create new context at receiving NOTIFY_IME_OF_FOCUS. In this case,
// mListener may not be initialized since input transaction should be
// initialized immediately before dispatching every WidgetKeyboardEvent
// and WidgetCompositionEvent (dispatching events always occurs after
// focus move).
nsCOMPtr<TextEventDispatcherListener> nativeListener =
mWidget->GetNativeTextEventDispatcherListener();
if (!nativeListener) {
return rv;
}
switch (aIMENotification.mMessage) {
case REQUEST_TO_COMMIT_COMPOSITION:
case REQUEST_TO_CANCEL_COMPOSITION:
// It's not necessary to notify native IME of requests.
return rv;
default: {
// Even if current input transaction's listener returns NS_OK or
// something, we need to notify native IME of notifications because
// when user typing after TIP does something, the changed information
// is necessary for them.
nsresult rv2 =
nativeListener->NotifyIME(this, aIMENotification);
// But return the result from current listener except when the
// notification isn't handled.
return rv == NS_ERROR_NOT_IMPLEMENTED ? rv2 : rv;
}
}
}
bool
TextEventDispatcher::DispatchKeyboardEvent(
EventMessage aMessage,
const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus,
void* aData)
{
return DispatchKeyboardEventInternal(aMessage, aKeyboardEvent, aStatus,
aData);
}
bool
TextEventDispatcher::DispatchKeyboardEventInternal(
EventMessage aMessage,
const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus,
void* aData,
uint32_t aIndexOfKeypress,
bool aNeedsCallback)
{
// Note that this method is also used for dispatching key events on a plugin
// because key events on a plugin should be dispatched same as normal key
// events. Then, only some handlers which need to intercept key events
// before the focused plugin (e.g., reserved shortcut key handlers) can
// consume the events.
MOZ_ASSERT(WidgetKeyboardEvent::IsKeyDownOrKeyDownOnPlugin(aMessage) ||
WidgetKeyboardEvent::IsKeyUpOrKeyUpOnPlugin(aMessage) ||
aMessage == eKeyPress, "Invalid aMessage value");
nsresult rv = GetState();
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
// If the key shouldn't cause keypress events, don't this patch them.
if (aMessage == eKeyPress && !aKeyboardEvent.ShouldCauseKeypressEvents()) {
return false;
}
// Basically, key events shouldn't be dispatched during composition.
// Note that plugin process has different IME context. Therefore, we don't
// need to check our composition state when the key event is fired on a
// plugin.
if (IsComposing() && !WidgetKeyboardEvent::IsKeyEventOnPlugin(aMessage)) {
// However, if we need to behave like other browsers, we need the keydown
// and keyup events. Note that this behavior is also allowed by D3E spec.
// FYI: keypress events must not be fired during composition.
if (!sDispatchKeyEventsDuringComposition || aMessage == eKeyPress) {
return false;
}
// XXX If there was mOnlyContentDispatch for this case, it might be useful
// because our chrome doesn't assume that key events are fired during
// composition.
}
WidgetKeyboardEvent keyEvent(true, aMessage, mWidget);
InitEvent(keyEvent);
keyEvent.AssignKeyEventData(aKeyboardEvent, false);
if (aStatus == nsEventStatus_eConsumeNoDefault) {
// If the key event should be dispatched as consumed event, marking it here.
// This is useful to prevent double action. E.g., when the key was already
// handled by system, our chrome shouldn't handle it.
keyEvent.PreventDefaultBeforeDispatch();
}
// Corrects each member for the specific key event type.
if (keyEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING) {
MOZ_ASSERT(!aIndexOfKeypress,
"aIndexOfKeypress must be 0 for non-printable key");
// If the keyboard event isn't caused by printable key, its charCode should
// be 0.
keyEvent.SetCharCode(0);
} else {
if (WidgetKeyboardEvent::IsKeyDownOrKeyDownOnPlugin(aMessage) ||
WidgetKeyboardEvent::IsKeyUpOrKeyUpOnPlugin(aMessage)) {
MOZ_RELEASE_ASSERT(!aIndexOfKeypress,
"aIndexOfKeypress must be 0 for either eKeyDown or eKeyUp");
} else {
MOZ_RELEASE_ASSERT(
!aIndexOfKeypress || aIndexOfKeypress < keyEvent.mKeyValue.Length(),
"aIndexOfKeypress must be 0 - mKeyValue.Length() - 1");
}
wchar_t ch =
keyEvent.mKeyValue.IsEmpty() ? 0 : keyEvent.mKeyValue[aIndexOfKeypress];
keyEvent.SetCharCode(static_cast<uint32_t>(ch));
if (aMessage == eKeyPress) {
// keyCode of eKeyPress events of printable keys should be always 0.
keyEvent.mKeyCode = 0;
// eKeyPress events are dispatched for every character.
// So, each key value of eKeyPress events should be a character.
if (ch) {
keyEvent.mKeyValue.Assign(ch);
} else {
keyEvent.mKeyValue.Truncate();
}
}
}
if (WidgetKeyboardEvent::IsKeyUpOrKeyUpOnPlugin(aMessage)) {
// mIsRepeat of keyup event must be false.
keyEvent.mIsRepeat = false;
}
// mIsComposing should be initialized later.
keyEvent.mIsComposing = false;
if (mInputTransactionType == eNativeInputTransaction) {
// Copy mNativeKeyEvent here because for safety for other users of
// AssignKeyEventData(), it doesn't copy this.
keyEvent.mNativeKeyEvent = aKeyboardEvent.mNativeKeyEvent;
} else {
// If it's not a keyboard event for native key event, we should ensure that
// mNativeKeyEvent and mPluginEvent are null/empty.
keyEvent.mNativeKeyEvent = nullptr;
keyEvent.mPluginEvent.Clear();
}
// TODO: Manage mUniqueId here.
// Request the alternative char codes for the key event.
// eKeyDown also needs alternative char codes because nsXBLWindowKeyHandler
// needs to check if a following keypress event is reserved by chrome for
// stopping propagation of its preceding keydown event.
keyEvent.mAlternativeCharCodes.Clear();
if ((WidgetKeyboardEvent::IsKeyDownOrKeyDownOnPlugin(aMessage) ||
aMessage == eKeyPress) &&
(aNeedsCallback || keyEvent.IsControl() || keyEvent.IsAlt() ||
keyEvent.IsMeta() || keyEvent.IsOS())) {
nsCOMPtr<TextEventDispatcherListener> listener =
do_QueryReferent(mListener);
if (listener) {
DebugOnly<WidgetKeyboardEvent> original(keyEvent);
listener->WillDispatchKeyboardEvent(this, keyEvent, aIndexOfKeypress,
aData);
MOZ_ASSERT(keyEvent.mMessage ==
static_cast<WidgetKeyboardEvent&>(original).mMessage);
MOZ_ASSERT(keyEvent.mKeyCode ==
static_cast<WidgetKeyboardEvent&>(original).mKeyCode);
MOZ_ASSERT(keyEvent.mLocation ==
static_cast<WidgetKeyboardEvent&>(original).mLocation);
MOZ_ASSERT(keyEvent.mIsRepeat ==
static_cast<WidgetKeyboardEvent&>(original).mIsRepeat);
MOZ_ASSERT(keyEvent.mIsComposing ==
static_cast<WidgetKeyboardEvent&>(original).mIsComposing);
MOZ_ASSERT(keyEvent.mKeyNameIndex ==
static_cast<WidgetKeyboardEvent&>(original).mKeyNameIndex);
MOZ_ASSERT(keyEvent.mCodeNameIndex ==
static_cast<WidgetKeyboardEvent&>(original).mCodeNameIndex);
MOZ_ASSERT(keyEvent.mKeyValue ==
static_cast<WidgetKeyboardEvent&>(original).mKeyValue);
MOZ_ASSERT(keyEvent.mCodeValue ==
static_cast<WidgetKeyboardEvent&>(original).mCodeValue);
}
}
DispatchInputEvent(mWidget, keyEvent, aStatus);
return true;
}
bool
TextEventDispatcher::MaybeDispatchKeypressEvents(
const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus,
void* aData,
bool aNeedsCallback)
{
// If the key event was consumed, keypress event shouldn't be fired.
if (aStatus == nsEventStatus_eConsumeNoDefault) {
return false;
}
// If the key shouldn't cause keypress events, don't fire them.
if (!aKeyboardEvent.ShouldCauseKeypressEvents()) {
return false;
}
// If the key isn't a printable key or just inputting one character or
// no character, we should dispatch only one keypress. Otherwise, i.e.,
// if the key is a printable key and inputs multiple characters, keypress
// event should be dispatched the count of inputting characters times.
size_t keypressCount =
aKeyboardEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING ?
1 : std::max(static_cast<nsAString::size_type>(1),
aKeyboardEvent.mKeyValue.Length());
bool isDispatched = false;
bool consumed = false;
for (size_t i = 0; i < keypressCount; i++) {
aStatus = nsEventStatus_eIgnore;
if (!DispatchKeyboardEventInternal(eKeyPress, aKeyboardEvent,
aStatus, aData, i, aNeedsCallback)) {
// The widget must have been gone.
break;
}
isDispatched = true;
if (!consumed) {
consumed = (aStatus == nsEventStatus_eConsumeNoDefault);
}
}
// If one of the keypress event was consumed, return ConsumeNoDefault.
if (consumed) {
aStatus = nsEventStatus_eConsumeNoDefault;
}
return isDispatched;
}
/******************************************************************************
* TextEventDispatcher::PendingComposition
*****************************************************************************/
TextEventDispatcher::PendingComposition::PendingComposition()
{
Clear();
}
void
TextEventDispatcher::PendingComposition::Clear()
{
mString.Truncate();
mClauses = nullptr;
mCaret.mRangeType = TextRangeType::eUninitialized;
}
void
TextEventDispatcher::PendingComposition::EnsureClauseArray()
{
if (mClauses) {
return;
}
mClauses = new TextRangeArray();
}
nsresult
TextEventDispatcher::PendingComposition::SetString(const nsAString& aString)
{
mString = aString;
return NS_OK;
}
nsresult
TextEventDispatcher::PendingComposition::AppendClause(
uint32_t aLength,
TextRangeType aTextRangeType)
{
if (NS_WARN_IF(!aLength)) {
return NS_ERROR_INVALID_ARG;
}
switch (aTextRangeType) {
case TextRangeType::eRawClause:
case TextRangeType::eSelectedRawClause:
case TextRangeType::eConvertedClause:
case TextRangeType::eSelectedClause: {
EnsureClauseArray();
TextRange textRange;
textRange.mStartOffset =
mClauses->IsEmpty() ? 0 : mClauses->LastElement().mEndOffset;
textRange.mEndOffset = textRange.mStartOffset + aLength;
textRange.mRangeType = aTextRangeType;
mClauses->AppendElement(textRange);
return NS_OK;
}
default:
return NS_ERROR_INVALID_ARG;
}
}
nsresult
TextEventDispatcher::PendingComposition::SetCaret(uint32_t aOffset,
uint32_t aLength)
{
mCaret.mStartOffset = aOffset;
mCaret.mEndOffset = mCaret.mStartOffset + aLength;
mCaret.mRangeType = TextRangeType::eCaret;
return NS_OK;
}
nsresult
TextEventDispatcher::PendingComposition::Set(const nsAString& aString,
const TextRangeArray* aRanges)
{
Clear();
nsAutoString str(aString);
// Don't expose CRLF to web contents, instead, use LF.
str.ReplaceSubstring(NS_LITERAL_STRING("\r\n"), NS_LITERAL_STRING("\n"));
nsresult rv = SetString(str);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!aRanges || aRanges->IsEmpty()) {
// Create dummy range if aString isn't empty.
if (!aString.IsEmpty()) {
rv = AppendClause(str.Length(), TextRangeType::eRawClause);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
return NS_OK;
}
// Adjust offsets in the ranges for XP linefeed character (only \n).
// XXX Following code is the safest approach. However, it wastes performance.
// For ensuring the clauses do not overlap each other, we should redesign
// TextRange later.
for (uint32_t i = 0; i < aRanges->Length(); ++i) {
TextRange range = aRanges->ElementAt(i);
TextRange nativeRange = range;
if (nativeRange.mStartOffset > 0) {
nsAutoString preText(Substring(aString, 0, nativeRange.mStartOffset));
preText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"),
NS_LITERAL_STRING("\n"));
range.mStartOffset = preText.Length();
}
if (nativeRange.Length() == 0) {
range.mEndOffset = range.mStartOffset;
} else {
nsAutoString clause(
Substring(aString, nativeRange.mStartOffset, nativeRange.Length()));
clause.ReplaceSubstring(NS_LITERAL_STRING("\r\n"),
NS_LITERAL_STRING("\n"));
range.mEndOffset = range.mStartOffset + clause.Length();
}
if (range.mRangeType == TextRangeType::eCaret) {
mCaret = range;
} else {
EnsureClauseArray();
mClauses->AppendElement(range);
}
}
return NS_OK;
}
nsresult
TextEventDispatcher::PendingComposition::Flush(
TextEventDispatcher* aDispatcher,
nsEventStatus& aStatus,
const WidgetEventTime* aEventTime)
{
aStatus = nsEventStatus_eIgnore;
nsresult rv = aDispatcher->GetState();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (mClauses && !mClauses->IsEmpty() &&
mClauses->LastElement().mEndOffset != mString.Length()) {
NS_WARNING("Sum of length of the all clauses must be same as the string "
"length");
Clear();
return NS_ERROR_ILLEGAL_VALUE;
}
if (mCaret.mRangeType == TextRangeType::eCaret) {
if (mCaret.mEndOffset > mString.Length()) {
NS_WARNING("Caret position is out of the composition string");
Clear();
return NS_ERROR_ILLEGAL_VALUE;
}
EnsureClauseArray();
mClauses->AppendElement(mCaret);
}
RefPtr<TextEventDispatcher> kungFuDeathGrip(aDispatcher);
nsCOMPtr<nsIWidget> widget(aDispatcher->mWidget);
WidgetCompositionEvent compChangeEvent(true, eCompositionChange, widget);
aDispatcher->InitEvent(compChangeEvent);
if (aEventTime) {
compChangeEvent.AssignEventTime(*aEventTime);
}
compChangeEvent.mData = mString;
if (mClauses) {
MOZ_ASSERT(!mClauses->IsEmpty(),
"mClauses must be non-empty array when it's not nullptr");
compChangeEvent.mRanges = mClauses;
}
// While this method dispatches a composition event, some other event handler
// cause more clauses to be added. So, we should clear pending composition
// before dispatching the event.
Clear();
rv = aDispatcher->StartCompositionAutomaticallyIfNecessary(aStatus,
aEventTime);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (aStatus == nsEventStatus_eConsumeNoDefault) {
return NS_OK;
}
rv = aDispatcher->DispatchEvent(widget, compChangeEvent, aStatus);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,486 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_textcompositionsynthesizer_h_
#define mozilla_textcompositionsynthesizer_h_
#include "mozilla/RefPtr.h"
#include "nsString.h"
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "mozilla/TextEventDispatcherListener.h"
#include "mozilla/TextRange.h"
class nsIWidget;
namespace mozilla {
namespace widget {
struct IMENotification;
/**
* TextEventDispatcher is a helper class for dispatching widget events defined
* in TextEvents.h. Currently, this is a helper for dispatching
* WidgetCompositionEvent and WidgetKeyboardEvent. This manages the behavior
* of them for conforming to DOM Level 3 Events.
* An instance of this class is created by nsIWidget instance and owned by it.
* This is typically created only by the top level widgets because only they
* handle IME.
*/
class TextEventDispatcher final
{
~TextEventDispatcher()
{
}
NS_INLINE_DECL_REFCOUNTING(TextEventDispatcher)
public:
explicit TextEventDispatcher(nsIWidget* aWidget);
/**
* Initializes the instance for IME or automated test. Either IME or tests
* need to call one of them before starting composition. If they return
* NS_ERROR_ALREADY_INITIALIZED, it means that the listener already listens
* notifications from TextEventDispatcher for same purpose (for IME or tests).
* If this returns another error, the caller shouldn't keep starting
* composition.
*
* @param aListener Specify the listener to listen notifications and
* requests. This must not be null.
* NOTE: aListener is stored as weak reference in
* TextEventDispatcher. See mListener
* definition below.
*/
nsresult BeginInputTransaction(TextEventDispatcherListener* aListener);
nsresult BeginTestInputTransaction(TextEventDispatcherListener* aListener,
bool aIsAPZAware);
nsresult BeginNativeInputTransaction();
/**
* EndInputTransaction() should be called when the listener stops using
* the TextEventDispatcher.
*
* @param aListener The listener using the TextEventDispatcher instance.
*/
void EndInputTransaction(TextEventDispatcherListener* aListener);
/**
* OnDestroyWidget() is called when mWidget is being destroyed.
*/
void OnDestroyWidget();
nsIWidget* GetWidget() const { return mWidget; }
/**
* GetState() returns current state of this class.
*
* @return NS_OK: Fine to compose text.
* NS_ERROR_NOT_INITIALIZED: BeginInputTransaction() or
* BeginInputTransactionForTests()
* should be called.
* NS_ERROR_NOT_AVAILABLE: The widget isn't available for
* composition.
*/
nsresult GetState() const;
/**
* IsComposing() returns true after calling StartComposition() and before
* calling CommitComposition().
*/
bool IsComposing() const { return mIsComposing; }
/**
* IsInNativeInputTransaction() returns true if native IME handler began a
* transaction and it's not finished yet.
*/
bool IsInNativeInputTransaction() const
{
return mInputTransactionType == eNativeInputTransaction;
}
/**
* IsDispatchingEvent() returns true while this instance dispatching an event.
*/
bool IsDispatchingEvent() const { return mDispatchingEvent > 0; }
/**
* GetPseudoIMEContext() returns pseudo native IME context if there is an
* input transaction whose type is not for native event handler.
* Otherwise, returns nullptr.
*/
void* GetPseudoIMEContext() const
{
if (mInputTransactionType == eNoInputTransaction ||
mInputTransactionType == eNativeInputTransaction) {
return nullptr;
}
return const_cast<TextEventDispatcher*>(this);
}
/**
* StartComposition() starts composition explicitly.
*
* @param aEventTime If this is not nullptr, WidgetCompositionEvent will
* be initialized with this. Otherwise, initialized
* with the time at initializing.
*/
nsresult StartComposition(nsEventStatus& aStatus,
const WidgetEventTime* aEventTime = nullptr);
/**
* CommitComposition() commits composition.
*
* @param aCommitString If this is null, commits with the last composition
* string. Otherwise, commits the composition with
* this value.
* @param aEventTime If this is not nullptr, WidgetCompositionEvent will
* be initialized with this. Otherwise, initialized
* with the time at initializing.
*/
nsresult CommitComposition(nsEventStatus& aStatus,
const nsAString* aCommitString = nullptr,
const WidgetEventTime* aEventTime = nullptr);
/**
* SetPendingCompositionString() sets new composition string which will be
* dispatched with eCompositionChange event by calling Flush().
*
* @param aString New composition string.
*/
nsresult SetPendingCompositionString(const nsAString& aString)
{
return mPendingComposition.SetString(aString);
}
/**
* AppendClauseToPendingComposition() appends a clause information to
* the pending composition string.
*
* @param aLength Length of the clause.
* @param aTextRangeType One of TextRangeType::eRawClause,
* TextRangeType::eSelectedRawClause,
* TextRangeType::eConvertedClause or
* TextRangeType::eSelectedClause.
*/
nsresult AppendClauseToPendingComposition(uint32_t aLength,
TextRangeType aTextRangeType)
{
return mPendingComposition.AppendClause(aLength, aTextRangeType);
}
/**
* SetCaretInPendingComposition() sets caret position in the pending
* composition string and its length. This is optional. If IME doesn't
* want to show caret, it shouldn't need to call this.
*
* @param aOffset Offset of the caret in the pending composition
* string. This should not be larger than the length
* of the pending composition string.
* @param aLength Caret width. If this is 0, caret will be collapsed.
* Note that Gecko doesn't supported wide caret yet,
* therefore, this is ignored for now.
*/
nsresult SetCaretInPendingComposition(uint32_t aOffset,
uint32_t aLength)
{
return mPendingComposition.SetCaret(aOffset, aLength);
}
/**
* SetPendingComposition() is useful if native IME handler already creates
* array of clauses and/or caret information.
*
* @param aString Composition string. This may include native line
* breakers since they will be replaced with XP line
* breakers automatically.
* @param aRanges This should include the ranges of clauses and/or
* a range of caret. Note that this method allows
* some ranges overlap each other and the range order
* is not from start to end.
*/
nsresult SetPendingComposition(const nsAString& aString,
const TextRangeArray* aRanges)
{
return mPendingComposition.Set(aString, aRanges);
}
/**
* FlushPendingComposition() sends the pending composition string
* to the widget of the store DOM window. Before calling this, IME needs to
* set pending composition string with SetPendingCompositionString(),
* AppendClauseToPendingComposition() and/or
* SetCaretInPendingComposition().
*
* @param aEventTime If this is not nullptr, WidgetCompositionEvent will
* be initialized with this. Otherwise, initialized
* with the time at initializing.
*/
nsresult FlushPendingComposition(nsEventStatus& aStatus,
const WidgetEventTime* aEventTime = nullptr)
{
return mPendingComposition.Flush(this, aStatus, aEventTime);
}
/**
* ClearPendingComposition() makes this instance forget pending composition.
*/
void ClearPendingComposition()
{
mPendingComposition.Clear();
}
/**
* GetPendingCompositionClauses() returns text ranges which was appended by
* AppendClauseToPendingComposition() or SetPendingComposition().
*/
const TextRangeArray* GetPendingCompositionClauses() const
{
return mPendingComposition.GetClauses();
}
/**
* @see nsIWidget::NotifyIME()
*/
nsresult NotifyIME(const IMENotification& aIMENotification);
/**
* DispatchKeyboardEvent() maybe dispatches aKeyboardEvent.
*
* @param aMessage Must be eKeyDown or eKeyUp.
* Use MaybeDispatchKeypressEvents() for dispatching
* eKeyPress.
* @param aKeyboardEvent A keyboard event.
* @param aStatus If dispatching event should be marked as consumed,
* set nsEventStatus_eConsumeNoDefault. Otherwise,
* set nsEventStatus_eIgnore. After dispatching
* a event and it's consumed this returns
* nsEventStatus_eConsumeNoDefault.
* @param aData Calling this method may cause calling
* WillDispatchKeyboardEvent() of the listener.
* aData will be set to its argument.
* @return true if an event is dispatched. Otherwise, false.
*/
bool DispatchKeyboardEvent(EventMessage aMessage,
const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus,
void* aData = nullptr);
/**
* MaybeDispatchKeypressEvents() maybe dispatches a keypress event which is
* generated from aKeydownEvent.
*
* @param aKeyboardEvent A keyboard event.
* @param aStatus Sets the result when the caller dispatches
* aKeyboardEvent. Note that if the value is
* nsEventStatus_eConsumeNoDefault, this does NOT
* dispatch keypress events.
* When this method dispatches one or more keypress
* events and one of them is consumed, this returns
* nsEventStatus_eConsumeNoDefault.
* @param aData Calling this method may cause calling
* WillDispatchKeyboardEvent() of the listener.
* aData will be set to its argument.
* @param aNeedsCallback Set true when caller needs to initialize each
* eKeyPress event immediately before dispatch.
* Then, WillDispatchKeyboardEvent() is always called.
* @return true if one or more events are dispatched.
* Otherwise, false.
*/
bool MaybeDispatchKeypressEvents(const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus,
void* aData = nullptr,
bool aNeedsCallback = false);
private:
// mWidget is owner of the instance. When this is created, this is set.
// And when mWidget is released, this is cleared by OnDestroyWidget().
// Note that mWidget may be destroyed already (i.e., mWidget->Destroyed() may
// return true).
nsIWidget* mWidget;
// mListener is a weak reference to TextEventDispatcherListener. That might
// be referred by JS. Therefore, the listener might be difficult to release
// itself if this is a strong reference. Additionally, it's difficult to
// check if a method to uninstall the listener is called by valid instance.
// So, using weak reference is the best way in this case.
nsWeakPtr mListener;
// mPendingComposition stores new composition string temporarily.
// These values will be used for dispatching eCompositionChange event
// in Flush(). When Flush() is called, the members will be cleared
// automatically.
class PendingComposition
{
public:
PendingComposition();
nsresult SetString(const nsAString& aString);
nsresult AppendClause(uint32_t aLength, TextRangeType aTextRangeType);
nsresult SetCaret(uint32_t aOffset, uint32_t aLength);
nsresult Set(const nsAString& aString, const TextRangeArray* aRanges);
nsresult Flush(TextEventDispatcher* aDispatcher,
nsEventStatus& aStatus,
const WidgetEventTime* aEventTime);
const TextRangeArray* GetClauses() const { return mClauses; }
void Clear();
private:
nsString mString;
RefPtr<TextRangeArray> mClauses;
TextRange mCaret;
void EnsureClauseArray();
};
PendingComposition mPendingComposition;
// While dispatching an event, this is incremented.
uint16_t mDispatchingEvent;
enum InputTransactionType : uint8_t
{
// No input transaction has been started.
eNoInputTransaction,
// Input transaction for native IME or keyboard event handler. Note that
// keyboard events may be dispatched via parent process if there is.
eNativeInputTransaction,
// Input transaction for automated tests which are APZ-aware. Note that
// keyboard events may be dispatched via parent process if there is.
eAsyncTestInputTransaction,
// Input transaction for automated tests which assume events are fired
// synchronously. I.e., keyboard events are always dispatched in the
// current process.
eSameProcessSyncTestInputTransaction,
// Input transaction for Others (must be IME on B2G). Events are fired
// synchronously because TextInputProcessor which is the only user of
// this input transaction type supports only keyboard apps on B2G.
// Keyboard apps on B2G doesn't want to dispatch keyboard events to
// chrome process. Therefore, this should dispatch key events only in
// the current process.
eSameProcessSyncInputTransaction
};
InputTransactionType mInputTransactionType;
bool IsForTests() const
{
return mInputTransactionType == eAsyncTestInputTransaction ||
mInputTransactionType == eSameProcessSyncTestInputTransaction;
}
// ShouldSendInputEventToAPZ() returns true when WidgetInputEvent should
// be dispatched via its parent process (if there is) for APZ. Otherwise,
// when the input transaction is for IME of B2G or automated tests which
// isn't APZ-aware, WidgetInputEvent should be dispatched form current
// process directly.
bool ShouldSendInputEventToAPZ() const
{
switch (mInputTransactionType) {
case eNativeInputTransaction:
case eAsyncTestInputTransaction:
return true;
case eSameProcessSyncTestInputTransaction:
case eSameProcessSyncInputTransaction:
return false;
case eNoInputTransaction:
NS_WARNING("Why does the caller need to dispatch an event when "
"there is no input transaction?");
return true;
default:
MOZ_CRASH("Define the behavior of new InputTransactionType");
}
}
// See IsComposing().
bool mIsComposing;
// If this is true, keydown and keyup events are dispatched even when there
// is a composition.
static bool sDispatchKeyEventsDuringComposition;
nsresult BeginInputTransactionInternal(
TextEventDispatcherListener* aListener,
InputTransactionType aType);
/**
* InitEvent() initializes aEvent. This must be called before dispatching
* the event.
*/
void InitEvent(WidgetGUIEvent& aEvent) const;
/**
* DispatchEvent() dispatches aEvent on aWidget.
*/
nsresult DispatchEvent(nsIWidget* aWidget,
WidgetGUIEvent& aEvent,
nsEventStatus& aStatus);
/**
* DispatchInputEvent() dispatches aEvent on aWidget.
*/
nsresult DispatchInputEvent(nsIWidget* aWidget,
WidgetInputEvent& aEvent,
nsEventStatus& aStatus);
/**
* StartCompositionAutomaticallyIfNecessary() starts composition if it hasn't
* been started it yet.
*
* @param aStatus If it succeeded to start composition normally, this
* returns nsEventStatus_eIgnore. Otherwise, e.g.,
* the composition is canceled during dispatching
* compositionstart event, this returns
* nsEventStatus_eConsumeNoDefault. In this case,
* the caller shouldn't keep doing its job.
* @param aEventTime If this is not nullptr, WidgetCompositionEvent will
* be initialized with this. Otherwise, initialized
* with the time at initializing.
* @return Only when something unexpected occurs, this returns
* an error. Otherwise, returns NS_OK even if aStatus
* is nsEventStatus_eConsumeNoDefault.
*/
nsresult StartCompositionAutomaticallyIfNecessary(
nsEventStatus& aStatus,
const WidgetEventTime* aEventTime);
/**
* DispatchKeyboardEventInternal() maybe dispatches aKeyboardEvent.
*
* @param aMessage Must be eKeyDown, eKeyUp or eKeyPress.
* @param aKeyboardEvent A keyboard event. If aMessage is eKeyPress and
* the event is for second or later character, its
* mKeyValue should be empty string.
* @param aStatus If dispatching event should be marked as consumed,
* set nsEventStatus_eConsumeNoDefault. Otherwise,
* set nsEventStatus_eIgnore. After dispatching
* a event and it's consumed this returns
* nsEventStatus_eConsumeNoDefault.
* @param aData Calling this method may cause calling
* WillDispatchKeyboardEvent() of the listener.
* aData will be set to its argument.
* @param aIndexOfKeypress This must be 0 if aMessage isn't eKeyPress or
* aKeyboard.mKeyNameIndex isn't
* KEY_NAME_INDEX_USE_STRING. Otherwise, i.e.,
* when an eKeyPress event causes inputting
* text, this must be between 0 and
* mKeyValue.Length() - 1 since keypress events
* sending only one character per event.
* @param aNeedsCallback Set true when caller needs to initialize each
* eKeyPress event immediately before dispatch.
* Then, WillDispatchKeyboardEvent() is always called.
* @return true if an event is dispatched. Otherwise, false.
*/
bool DispatchKeyboardEventInternal(EventMessage aMessage,
const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus,
void* aData,
uint32_t aIndexOfKeypress = 0,
bool aNeedsCallback = false);
};
} // namespace widget
} // namespace mozilla
#endif // #ifndef mozilla_widget_textcompositionsynthesizer_h_

View file

@ -0,0 +1,89 @@
/* 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/. */
#ifndef mozilla_textinputdispatcherlistener_h_
#define mozilla_textinputdispatcherlistener_h_
#include "nsWeakReference.h"
namespace mozilla {
namespace widget {
class TextEventDispatcher;
struct IMENotification;
#define NS_TEXT_INPUT_PROXY_LISTENER_IID \
{ 0xf2226f55, 0x6ddb, 0x40d5, \
{ 0x8a, 0x24, 0xce, 0x4d, 0x5b, 0x38, 0x15, 0xf0 } };
class TextEventDispatcherListener : public nsSupportsWeakReference
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_TEXT_INPUT_PROXY_LISTENER_IID)
/**
* NotifyIME() is called by TextEventDispatcher::NotifyIME(). This is a
* notification or request to IME. See document of nsIWidget::NotifyIME()
* for the detail.
*/
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
const IMENotification& aNotification) = 0;
/**
* OnRemovedFrom() is called when the TextEventDispatcher stops working and
* is releasing the listener.
*/
NS_IMETHOD_(void) OnRemovedFrom(
TextEventDispatcher* aTextEventDispatcher) = 0;
/**
* WillDispatchKeyboardEvent() may be called immediately before
* TextEventDispatcher dispatching a keyboard event. This is called only
* during calling TextEventDispatcher::DispatchKeyboardEvent() or
* TextEventDispatcher::MaybeDispatchKeypressEvents(). But this may not
* be called if TextEventDispatcher thinks that the keyboard event doesn't
* need alternative char codes.
*
* This method can overwrite any members of aKeyboardEvent which is already
* initialized by TextEventDispatcher. If it's necessary, this method should
* overwrite the charCode when Control key is pressed. TextEventDispatcher
* computes charCode from mKeyValue. However, when Control key is pressed,
* charCode should be an ASCII char. In such case, this method needs to
* overwrite it properly.
*
* @param aTextEventDispatcher Pointer to the caller.
* @param aKeyboardEvent The event trying to dispatch.
* This is already initialized, but if it's
* necessary, this method should overwrite the
* members and set alternative char codes.
* @param aIndexOfKeypress When aKeyboardEvent is eKeyPress event,
* it may be a sequence of keypress events
* if the key causes multiple characters.
* In such case, this indicates the index from
* first keypress event.
* If aKeyboardEvent is the first eKeyPress or
* other events, this value is 0.
* @param aData The pointer which was specified at calling
* the method of TextEventDispatcher.
* For example, if you do:
* |TextEventDispatcher->DispatchKeyboardEvent(
* eKeyDown, event, status, this);|
* Then, aData of this method becomes |this|.
* Finally, you can use it like:
* |static_cast<NativeEventHandler*>(aData)|
*/
NS_IMETHOD_(void) WillDispatchKeyboardEvent(
TextEventDispatcher* aTextEventDispatcher,
WidgetKeyboardEvent& aKeyboardEvent,
uint32_t aIndexOfKeypress,
void* aData) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(TextEventDispatcherListener,
NS_TEXT_INPUT_PROXY_LISTENER_IID)
} // namespace widget
} // namespace mozilla
#endif // #ifndef mozilla_textinputdispatcherlistener_h_

1014
widget/TextEvents.h Normal file

File diff suppressed because it is too large Load diff

314
widget/TextRange.h Normal file
View file

@ -0,0 +1,314 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_TextRage_h_
#define mozilla_TextRage_h_
#include <stdint.h>
#include "mozilla/EventForwards.h"
#include "nsColor.h"
#include "nsISelectionController.h"
#include "nsITextInputProcessor.h"
#include "nsStyleConsts.h"
#include "nsTArray.h"
namespace mozilla {
/******************************************************************************
* mozilla::TextRangeStyle
******************************************************************************/
struct TextRangeStyle
{
enum
{
LINESTYLE_NONE = NS_STYLE_TEXT_DECORATION_STYLE_NONE,
LINESTYLE_SOLID = NS_STYLE_TEXT_DECORATION_STYLE_SOLID,
LINESTYLE_DOTTED = NS_STYLE_TEXT_DECORATION_STYLE_DOTTED,
LINESTYLE_DASHED = NS_STYLE_TEXT_DECORATION_STYLE_DASHED,
LINESTYLE_DOUBLE = NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE,
LINESTYLE_WAVY = NS_STYLE_TEXT_DECORATION_STYLE_WAVY
};
enum
{
DEFINED_NONE = 0x00,
DEFINED_LINESTYLE = 0x01,
DEFINED_FOREGROUND_COLOR = 0x02,
DEFINED_BACKGROUND_COLOR = 0x04,
DEFINED_UNDERLINE_COLOR = 0x08
};
// Initialize all members, because TextRange instances may be compared by
// memcomp.
TextRangeStyle()
{
Clear();
}
void Clear()
{
mDefinedStyles = DEFINED_NONE;
mLineStyle = LINESTYLE_NONE;
mIsBoldLine = false;
mForegroundColor = mBackgroundColor = mUnderlineColor = NS_RGBA(0, 0, 0, 0);
}
bool IsDefined() const { return mDefinedStyles != DEFINED_NONE; }
bool IsLineStyleDefined() const
{
return (mDefinedStyles & DEFINED_LINESTYLE) != 0;
}
bool IsForegroundColorDefined() const
{
return (mDefinedStyles & DEFINED_FOREGROUND_COLOR) != 0;
}
bool IsBackgroundColorDefined() const
{
return (mDefinedStyles & DEFINED_BACKGROUND_COLOR) != 0;
}
bool IsUnderlineColorDefined() const
{
return (mDefinedStyles & DEFINED_UNDERLINE_COLOR) != 0;
}
bool IsNoChangeStyle() const
{
return !IsForegroundColorDefined() && !IsBackgroundColorDefined() &&
IsLineStyleDefined() && mLineStyle == LINESTYLE_NONE;
}
bool Equals(const TextRangeStyle& aOther) const
{
if (mDefinedStyles != aOther.mDefinedStyles)
return false;
if (IsLineStyleDefined() && (mLineStyle != aOther.mLineStyle ||
!mIsBoldLine != !aOther.mIsBoldLine))
return false;
if (IsForegroundColorDefined() &&
(mForegroundColor != aOther.mForegroundColor))
return false;
if (IsBackgroundColorDefined() &&
(mBackgroundColor != aOther.mBackgroundColor))
return false;
if (IsUnderlineColorDefined() &&
(mUnderlineColor != aOther.mUnderlineColor))
return false;
return true;
}
bool operator !=(const TextRangeStyle &aOther) const
{
return !Equals(aOther);
}
bool operator ==(const TextRangeStyle &aOther) const
{
return Equals(aOther);
}
uint8_t mDefinedStyles;
uint8_t mLineStyle; // DEFINED_LINESTYLE
bool mIsBoldLine; // DEFINED_LINESTYLE
nscolor mForegroundColor; // DEFINED_FOREGROUND_COLOR
nscolor mBackgroundColor; // DEFINED_BACKGROUND_COLOR
nscolor mUnderlineColor; // DEFINED_UNDERLINE_COLOR
};
/******************************************************************************
* mozilla::TextRange
******************************************************************************/
enum class TextRangeType : RawTextRangeType
{
eUninitialized = 0x00,
eCaret = 0x01,
eRawClause = nsITextInputProcessor::ATTR_RAW_CLAUSE,
eSelectedRawClause = nsITextInputProcessor::ATTR_SELECTED_RAW_CLAUSE,
eConvertedClause = nsITextInputProcessor::ATTR_CONVERTED_CLAUSE,
eSelectedClause = nsITextInputProcessor::ATTR_SELECTED_CLAUSE
};
bool IsValidRawTextRangeValue(RawTextRangeType aRawTextRangeValue);
RawTextRangeType ToRawTextRangeType(TextRangeType aTextRangeType);
TextRangeType ToTextRangeType(RawTextRangeType aRawTextRangeType);
const char* ToChar(TextRangeType aTextRangeType);
SelectionType ToSelectionType(TextRangeType aTextRangeType);
inline RawSelectionType ToRawSelectionType(TextRangeType aTextRangeType)
{
return ToRawSelectionType(ToSelectionType(aTextRangeType));
}
struct TextRange
{
TextRange()
: mStartOffset(0)
, mEndOffset(0)
, mRangeType(TextRangeType::eUninitialized)
{
}
uint32_t mStartOffset;
// XXX Storing end offset makes the initializing code very complicated.
// We should replace it with mLength.
uint32_t mEndOffset;
TextRangeStyle mRangeStyle;
TextRangeType mRangeType;
uint32_t Length() const { return mEndOffset - mStartOffset; }
bool IsClause() const
{
return mRangeType != TextRangeType::eCaret;
}
bool Equals(const TextRange& aOther) const
{
return mStartOffset == aOther.mStartOffset &&
mEndOffset == aOther.mEndOffset &&
mRangeType == aOther.mRangeType &&
mRangeStyle == aOther.mRangeStyle;
}
void RemoveCharacter(uint32_t aOffset)
{
if (mStartOffset > aOffset) {
--mStartOffset;
--mEndOffset;
} else if (mEndOffset > aOffset) {
--mEndOffset;
}
}
};
/******************************************************************************
* mozilla::TextRangeArray
******************************************************************************/
class TextRangeArray final : public AutoTArray<TextRange, 10>
{
friend class WidgetCompositionEvent;
~TextRangeArray() {}
NS_INLINE_DECL_REFCOUNTING(TextRangeArray)
const TextRange* GetTargetClause() const
{
for (uint32_t i = 0; i < Length(); ++i) {
const TextRange& range = ElementAt(i);
if (range.mRangeType == TextRangeType::eSelectedRawClause ||
range.mRangeType == TextRangeType::eSelectedClause) {
return &range;
}
}
return nullptr;
}
// Returns target clause offset. If there are selected clauses, this returns
// the first selected clause offset. Otherwise, 0.
uint32_t TargetClauseOffset() const
{
const TextRange* range = GetTargetClause();
return range ? range->mStartOffset : 0;
}
// Returns target clause length. If there are selected clauses, this returns
// the first selected clause length. Otherwise, UINT32_MAX.
uint32_t TargetClauseLength() const
{
const TextRange* range = GetTargetClause();
return range ? range->Length() : UINT32_MAX;
}
public:
bool IsComposing() const
{
for (uint32_t i = 0; i < Length(); ++i) {
if (ElementAt(i).IsClause()) {
return true;
}
}
return false;
}
bool Equals(const TextRangeArray& aOther) const
{
size_t len = Length();
if (len != aOther.Length()) {
return false;
}
for (size_t i = 0; i < len; i++) {
if (!ElementAt(i).Equals(aOther.ElementAt(i))) {
return false;
}
}
return true;
}
void RemoveCharacter(uint32_t aOffset)
{
for (size_t i = 0, len = Length(); i < len; i++) {
ElementAt(i).RemoveCharacter(aOffset);
}
}
bool HasCaret() const
{
for (const TextRange& range : *this) {
if (range.mRangeType == TextRangeType::eCaret) {
return true;
}
}
return false;
}
bool HasClauses() const
{
for (const TextRange& range : *this) {
if (range.IsClause()) {
return true;
}
}
return false;
}
uint32_t GetCaretPosition() const
{
for (const TextRange& range : *this) {
if (range.mRangeType == TextRangeType::eCaret) {
return range.mStartOffset;
}
}
return UINT32_MAX;
}
const TextRange* GetFirstClause() const
{
for (const TextRange& range : *this) {
// Look for the range of a clause whose start offset is 0 because the
// first clause's start offset is always 0.
if (range.IsClause() && !range.mStartOffset) {
return &range;
}
}
MOZ_ASSERT(!HasClauses());
return nullptr;
}
};
} // namespace mozilla
#endif // mozilla_TextRage_h_

220
widget/TouchEvents.h Normal file
View file

@ -0,0 +1,220 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_TouchEvents_h__
#define mozilla_TouchEvents_h__
#include <stdint.h>
#include "mozilla/dom/Touch.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/RefPtr.h"
#include "nsIDOMSimpleGestureEvent.h"
#include "nsTArray.h"
namespace mozilla {
/******************************************************************************
* mozilla::WidgetGestureNotifyEvent
*
* This event is the first event generated when the user touches
* the screen with a finger, and it's meant to decide what kind
* of action we'll use for that touch interaction.
*
* The event is dispatched to the layout and based on what is underneath
* the initial contact point it's then decided if we should pan
* (finger scrolling) or drag the target element.
******************************************************************************/
class WidgetGestureNotifyEvent : public WidgetGUIEvent
{
public:
virtual WidgetGestureNotifyEvent* AsGestureNotifyEvent() override
{
return this;
}
WidgetGestureNotifyEvent(bool aIsTrusted, EventMessage aMessage,
nsIWidget *aWidget)
: WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eGestureNotifyEventClass)
, mPanDirection(ePanNone)
, mDisplayPanFeedback(false)
{
}
virtual WidgetEvent* Duplicate() const override
{
// XXX Looks like this event is handled only in PostHandleEvent() of
// EventStateManager. Therefore, it might be possible to handle this
// in PreHandleEvent() and not to dispatch as a DOM event into the DOM
// tree like ContentQueryEvent. Then, this event doesn't need to
// support Duplicate().
MOZ_ASSERT(mClass == eGestureNotifyEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
WidgetGestureNotifyEvent* result =
new WidgetGestureNotifyEvent(false, mMessage, nullptr);
result->AssignGestureNotifyEventData(*this, true);
result->mFlags = mFlags;
return result;
}
typedef int8_t PanDirectionType;
enum PanDirection : PanDirectionType
{
ePanNone,
ePanVertical,
ePanHorizontal,
ePanBoth
};
PanDirection mPanDirection;
bool mDisplayPanFeedback;
void AssignGestureNotifyEventData(const WidgetGestureNotifyEvent& aEvent,
bool aCopyTargets)
{
AssignGUIEventData(aEvent, aCopyTargets);
mPanDirection = aEvent.mPanDirection;
mDisplayPanFeedback = aEvent.mDisplayPanFeedback;
}
};
/******************************************************************************
* mozilla::WidgetSimpleGestureEvent
******************************************************************************/
class WidgetSimpleGestureEvent : public WidgetMouseEventBase
{
public:
virtual WidgetSimpleGestureEvent* AsSimpleGestureEvent() override
{
return this;
}
WidgetSimpleGestureEvent(bool aIsTrusted, EventMessage aMessage,
nsIWidget* aWidget)
: WidgetMouseEventBase(aIsTrusted, aMessage, aWidget,
eSimpleGestureEventClass)
, mAllowedDirections(0)
, mDirection(0)
, mClickCount(0)
, mDelta(0.0)
{
}
WidgetSimpleGestureEvent(const WidgetSimpleGestureEvent& aOther)
: WidgetMouseEventBase(aOther.IsTrusted(), aOther.mMessage,
aOther.mWidget, eSimpleGestureEventClass)
, mAllowedDirections(aOther.mAllowedDirections)
, mDirection(aOther.mDirection)
, mClickCount(0)
, mDelta(aOther.mDelta)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eSimpleGestureEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
WidgetSimpleGestureEvent* result =
new WidgetSimpleGestureEvent(false, mMessage, nullptr);
result->AssignSimpleGestureEventData(*this, true);
result->mFlags = mFlags;
return result;
}
// See nsIDOMSimpleGestureEvent for values
uint32_t mAllowedDirections;
// See nsIDOMSimpleGestureEvent for values
uint32_t mDirection;
// The number of taps for tap events
uint32_t mClickCount;
// Delta for magnify and rotate events
double mDelta;
// XXX Not tested by test_assign_event_data.html
void AssignSimpleGestureEventData(const WidgetSimpleGestureEvent& aEvent,
bool aCopyTargets)
{
AssignMouseEventBaseData(aEvent, aCopyTargets);
// mAllowedDirections isn't copied
mDirection = aEvent.mDirection;
mDelta = aEvent.mDelta;
mClickCount = aEvent.mClickCount;
}
};
/******************************************************************************
* mozilla::WidgetTouchEvent
******************************************************************************/
class WidgetTouchEvent : public WidgetInputEvent
{
public:
typedef nsTArray<RefPtr<mozilla::dom::Touch>> TouchArray;
typedef AutoTArray<RefPtr<mozilla::dom::Touch>, 10> AutoTouchArray;
virtual WidgetTouchEvent* AsTouchEvent() override { return this; }
WidgetTouchEvent()
{
MOZ_COUNT_CTOR(WidgetTouchEvent);
}
WidgetTouchEvent(const WidgetTouchEvent& aOther)
: WidgetInputEvent(aOther.IsTrusted(), aOther.mMessage, aOther.mWidget,
eTouchEventClass)
{
MOZ_COUNT_CTOR(WidgetTouchEvent);
mModifiers = aOther.mModifiers;
mTime = aOther.mTime;
mTimeStamp = aOther.mTimeStamp;
mTouches.AppendElements(aOther.mTouches);
mFlags.mCancelable = mMessage != eTouchCancel;
mFlags.mHandledByAPZ = aOther.mFlags.mHandledByAPZ;
}
WidgetTouchEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget)
: WidgetInputEvent(aIsTrusted, aMessage, aWidget, eTouchEventClass)
{
MOZ_COUNT_CTOR(WidgetTouchEvent);
mFlags.mCancelable = mMessage != eTouchCancel;
}
virtual ~WidgetTouchEvent()
{
MOZ_COUNT_DTOR(WidgetTouchEvent);
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eTouchEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
WidgetTouchEvent* result = new WidgetTouchEvent(false, mMessage, nullptr);
result->AssignTouchEventData(*this, true);
result->mFlags = mFlags;
return result;
}
TouchArray mTouches;
void AssignTouchEventData(const WidgetTouchEvent& aEvent, bool aCopyTargets)
{
AssignInputEventData(aEvent, aCopyTargets);
// Assign*EventData() assume that they're called only new instance.
MOZ_ASSERT(mTouches.IsEmpty());
mTouches.AppendElements(aEvent.mTouches);
}
};
} // namespace mozilla
#endif // mozilla_TouchEvents_h__

187
widget/VsyncDispatcher.cpp Normal file
View file

@ -0,0 +1,187 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "MainThreadUtils.h"
#include "VsyncDispatcher.h"
#include "VsyncSource.h"
#include "gfxPlatform.h"
#include "mozilla/layers/Compositor.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/CompositorThread.h"
#ifdef MOZ_ENABLE_PROFILER_SPS
#include "GeckoProfiler.h"
#include "ProfilerMarkers.h"
#endif
namespace mozilla {
CompositorVsyncDispatcher::CompositorVsyncDispatcher()
: mCompositorObserverLock("CompositorObserverLock")
, mDidShutdown(false)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
}
CompositorVsyncDispatcher::~CompositorVsyncDispatcher()
{
MOZ_ASSERT(XRE_IsParentProcess());
// We auto remove this vsync dispatcher from the vsync source in the nsBaseWidget
}
void
CompositorVsyncDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
{
// In vsync thread
#ifdef MOZ_ENABLE_PROFILER_SPS
layers::CompositorBridgeParent::PostInsertVsyncProfilerMarker(aVsyncTimestamp);
#endif
MutexAutoLock lock(mCompositorObserverLock);
if (mCompositorVsyncObserver) {
mCompositorVsyncObserver->NotifyVsync(aVsyncTimestamp);
}
}
void
CompositorVsyncDispatcher::ObserveVsync(bool aEnable)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(XRE_IsParentProcess());
if (mDidShutdown) {
return;
}
if (aEnable) {
gfxPlatform::GetPlatform()->GetHardwareVsync()->AddCompositorVsyncDispatcher(this);
} else {
gfxPlatform::GetPlatform()->GetHardwareVsync()->RemoveCompositorVsyncDispatcher(this);
}
}
void
CompositorVsyncDispatcher::SetCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
{
// When remote compositing or running gtests, vsync observation is
// initiated on the main thread. Otherwise, it is initiated from the compositor
// thread.
MOZ_ASSERT(NS_IsMainThread() || CompositorThreadHolder::IsInCompositorThread());
{ // scope lock
MutexAutoLock lock(mCompositorObserverLock);
mCompositorVsyncObserver = aVsyncObserver;
}
bool observeVsync = aVsyncObserver != nullptr;
nsCOMPtr<nsIRunnable> vsyncControl = NewRunnableMethod<bool>(this,
&CompositorVsyncDispatcher::ObserveVsync,
observeVsync);
NS_DispatchToMainThread(vsyncControl);
}
void
CompositorVsyncDispatcher::Shutdown()
{
// Need to explicitly remove CompositorVsyncDispatcher when the nsBaseWidget shuts down.
// Otherwise, we would get dead vsync notifications between when the nsBaseWidget
// shuts down and the CompositorBridgeParent shuts down.
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
ObserveVsync(false);
mDidShutdown = true;
{ // scope lock
MutexAutoLock lock(mCompositorObserverLock);
mCompositorVsyncObserver = nullptr;
}
}
RefreshTimerVsyncDispatcher::RefreshTimerVsyncDispatcher()
: mRefreshTimersLock("RefreshTimers lock")
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
}
RefreshTimerVsyncDispatcher::~RefreshTimerVsyncDispatcher()
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
}
void
RefreshTimerVsyncDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
{
MutexAutoLock lock(mRefreshTimersLock);
for (size_t i = 0; i < mChildRefreshTimers.Length(); i++) {
mChildRefreshTimers[i]->NotifyVsync(aVsyncTimestamp);
}
if (mParentRefreshTimer) {
mParentRefreshTimer->NotifyVsync(aVsyncTimestamp);
}
}
void
RefreshTimerVsyncDispatcher::SetParentRefreshTimer(VsyncObserver* aVsyncObserver)
{
MOZ_ASSERT(NS_IsMainThread());
{ // lock scope because UpdateVsyncStatus runs on main thread and will deadlock
MutexAutoLock lock(mRefreshTimersLock);
mParentRefreshTimer = aVsyncObserver;
}
UpdateVsyncStatus();
}
void
RefreshTimerVsyncDispatcher::AddChildRefreshTimer(VsyncObserver* aVsyncObserver)
{
{ // scope lock - called on pbackground thread
MutexAutoLock lock(mRefreshTimersLock);
MOZ_ASSERT(aVsyncObserver);
if (!mChildRefreshTimers.Contains(aVsyncObserver)) {
mChildRefreshTimers.AppendElement(aVsyncObserver);
}
}
UpdateVsyncStatus();
}
void
RefreshTimerVsyncDispatcher::RemoveChildRefreshTimer(VsyncObserver* aVsyncObserver)
{
{ // scope lock - called on pbackground thread
MutexAutoLock lock(mRefreshTimersLock);
MOZ_ASSERT(aVsyncObserver);
mChildRefreshTimers.RemoveElement(aVsyncObserver);
}
UpdateVsyncStatus();
}
void
RefreshTimerVsyncDispatcher::UpdateVsyncStatus()
{
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(NewRunnableMethod(this,
&RefreshTimerVsyncDispatcher::UpdateVsyncStatus));
return;
}
gfx::VsyncSource::Display& display = gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay();
display.NotifyRefreshTimerVsyncStatus(NeedsVsync());
}
bool
RefreshTimerVsyncDispatcher::NeedsVsync()
{
MOZ_ASSERT(NS_IsMainThread());
MutexAutoLock lock(mRefreshTimersLock);
return (mParentRefreshTimer != nullptr) || !mChildRefreshTimers.IsEmpty();
}
} // namespace mozilla

103
widget/VsyncDispatcher.h Normal file
View file

@ -0,0 +1,103 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_widget_VsyncDispatcher_h
#define mozilla_widget_VsyncDispatcher_h
#include "mozilla/Mutex.h"
#include "mozilla/TimeStamp.h"
#include "nsISupportsImpl.h"
#include "nsTArray.h"
#include "mozilla/RefPtr.h"
namespace mozilla {
class VsyncObserver
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncObserver)
public:
// The method called when a vsync occurs. Return true if some work was done.
// In general, this vsync notification will occur on the hardware vsync
// thread from VsyncSource. But it might also be called on PVsync ipc thread
// if this notification is cross process. Thus all observer should check the
// thread model before handling the real task.
virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) = 0;
protected:
VsyncObserver() {}
virtual ~VsyncObserver() {}
}; // VsyncObserver
// Used to dispatch vsync events in the parent process to compositors.
//
// When the compositor is in-process, CompositorWidgets own a
// CompositorVsyncDispatcher, and directly attach the compositor's observer
// to it.
//
// When the compositor is out-of-process, the CompositorWidgetDelegate owns
// the vsync dispatcher instead. The widget receives vsync observer/unobserve
// commands via IPDL, and uses this to attach a CompositorWidgetVsyncObserver.
// This observer forwards vsync notifications (on the vsync thread) to a
// dedicated vsync I/O thread, which then forwards the notification to the
// compositor thread in the compositor process.
class CompositorVsyncDispatcher final
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorVsyncDispatcher)
public:
CompositorVsyncDispatcher();
// Called on the vsync thread when a hardware vsync occurs
void NotifyVsync(TimeStamp aVsyncTimestamp);
// Compositor vsync observers must be added/removed on the compositor thread
void SetCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
void Shutdown();
private:
virtual ~CompositorVsyncDispatcher();
void ObserveVsync(bool aEnable);
Mutex mCompositorObserverLock;
RefPtr<VsyncObserver> mCompositorVsyncObserver;
bool mDidShutdown;
};
// Dispatch vsync event to ipc actor parent and chrome RefreshTimer.
class RefreshTimerVsyncDispatcher final
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefreshTimerVsyncDispatcher)
public:
RefreshTimerVsyncDispatcher();
// Please check CompositorVsyncDispatcher::NotifyVsync().
void NotifyVsync(TimeStamp aVsyncTimestamp);
// Set chrome process's RefreshTimer to this dispatcher.
// This function can be called from any thread.
void SetParentRefreshTimer(VsyncObserver* aVsyncObserver);
// Add or remove the content process' RefreshTimer to this dispatcher. This
// will be a no-op for AddChildRefreshTimer() if the observer is already
// registered.
// These functions can be called from any thread.
void AddChildRefreshTimer(VsyncObserver* aVsyncObserver);
void RemoveChildRefreshTimer(VsyncObserver* aVsyncObserver);
private:
virtual ~RefreshTimerVsyncDispatcher();
void UpdateVsyncStatus();
bool NeedsVsync();
Mutex mRefreshTimersLock;
RefPtr<VsyncObserver> mParentRefreshTimer;
nsTArray<RefPtr<VsyncObserver>> mChildRefreshTimers;
};
} // namespace mozilla
#endif // mozilla_widget_VsyncDispatcher_h

1075
widget/WidgetEventImpl.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
/* 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/. */
#ifndef mozilla_WidgetMessageUtils_h
#define mozilla_WidgetMessageUtils_h
#include "ipc/IPCMessageUtils.h"
#include "mozilla/LookAndFeel.h"
namespace IPC {
template<>
struct ParamTraits<LookAndFeelInt>
{
typedef LookAndFeelInt paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.id);
WriteParam(aMsg, aParam.value);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
int32_t id, value;
if (ReadParam(aMsg, aIter, &id) &&
ReadParam(aMsg, aIter, &value)) {
aResult->id = id;
aResult->value = value;
return true;
}
return false;
}
};
} // namespace IPC
#endif // WidgetMessageUtils_h

27
widget/WidgetTraceEvent.h Normal file
View file

@ -0,0 +1,27 @@
/* 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/. */
#ifndef WIDGET_PUBLIC_WIDGETTRACEEVENT_H_
#define WIDGET_PUBLIC_WIDGETTRACEEVENT_H_
namespace mozilla {
// Perform any required initialization in the widget backend for
// event tracing. Return true if initialization was successful.
bool InitWidgetTracing();
// Perform any required cleanup in the widget backend for event tracing.
void CleanUpWidgetTracing();
// Fire a tracer event at the UI-thread event loop, and block until
// the event is processed. This should only be called by
// a thread that's not the UI thread.
bool FireAndWaitForTracerEvent();
// Signal that the event has been received by the event loop.
void SignalTracerThread();
} // namespace mozilla
#endif // WIDGET_PUBLIC_WIDGETTRACEEVENT_H_

141
widget/WidgetUtils.cpp Normal file
View file

@ -0,0 +1,141 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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 "mozilla/WidgetUtils.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/Unused.h"
#include "nsContentUtils.h"
#include "nsIBidiKeyboard.h"
#include "nsTArray.h"
#ifdef XP_WIN
#include "WinUtils.h"
#endif
#if MOZ_WIDGET_GTK == 3
#include "mozilla/WidgetUtilsGtk.h"
#endif
namespace mozilla {
gfx::Matrix
ComputeTransformForRotation(const nsIntRect& aBounds,
ScreenRotation aRotation)
{
gfx::Matrix transform;
static const gfx::Float floatPi = static_cast<gfx::Float>(M_PI);
switch (aRotation) {
case ROTATION_0:
break;
case ROTATION_90:
transform.PreTranslate(aBounds.width, 0);
transform.PreRotate(floatPi / 2);
break;
case ROTATION_180:
transform.PreTranslate(aBounds.width, aBounds.height);
transform.PreRotate(floatPi);
break;
case ROTATION_270:
transform.PreTranslate(0, aBounds.height);
transform.PreRotate(floatPi * 3 / 2);
break;
default:
MOZ_CRASH("Unknown rotation");
}
return transform;
}
gfx::Matrix
ComputeTransformForUnRotation(const nsIntRect& aBounds,
ScreenRotation aRotation)
{
gfx::Matrix transform;
static const gfx::Float floatPi = static_cast<gfx::Float>(M_PI);
switch (aRotation) {
case ROTATION_0:
break;
case ROTATION_90:
transform.PreTranslate(0, aBounds.height);
transform.PreRotate(floatPi * 3 / 2);
break;
case ROTATION_180:
transform.PreTranslate(aBounds.width, aBounds.height);
transform.PreRotate(floatPi);
break;
case ROTATION_270:
transform.PreTranslate(aBounds.width, 0);
transform.PreRotate(floatPi / 2);
break;
default:
MOZ_CRASH("Unknown rotation");
}
return transform;
}
nsIntRect RotateRect(nsIntRect aRect,
const nsIntRect& aBounds,
ScreenRotation aRotation)
{
switch (aRotation) {
case ROTATION_0:
return aRect;
case ROTATION_90:
return nsIntRect(aRect.y,
aBounds.width - aRect.x - aRect.width,
aRect.height, aRect.width);
case ROTATION_180:
return nsIntRect(aBounds.width - aRect.x - aRect.width,
aBounds.height - aRect.y - aRect.height,
aRect.width, aRect.height);
case ROTATION_270:
return nsIntRect(aBounds.height - aRect.y - aRect.height,
aRect.x,
aRect.height, aRect.width);
default:
MOZ_CRASH("Unknown rotation");
}
}
namespace widget {
uint32_t
WidgetUtils::IsTouchDeviceSupportPresent()
{
#ifdef XP_WIN
return WinUtils::IsTouchDeviceSupportPresent();
#elif MOZ_WIDGET_GTK == 3
return WidgetUtilsGTK::IsTouchDeviceSupportPresent();
#else
return 0;
#endif
}
// static
void
WidgetUtils::SendBidiKeyboardInfoToContent()
{
nsCOMPtr<nsIBidiKeyboard> bidiKeyboard = nsContentUtils::GetBidiKeyboard();
if (!bidiKeyboard) {
return;
}
bool rtl;
if (NS_FAILED(bidiKeyboard->IsLangRTL(&rtl))) {
return;
}
bool bidiKeyboards = false;
bidiKeyboard->GetHaveBidiKeyboards(&bidiKeyboards);
nsTArray<dom::ContentParent*> children;
dom::ContentParent::GetAll(children);
for (uint32_t i = 0; i < children.Length(); i++) {
Unused << children[i]->SendBidiKeyboardNotify(rtl, bidiKeyboards);
}
}
} // namespace widget
} // namespace mozilla

99
widget/WidgetUtils.h Normal file
View file

@ -0,0 +1,99 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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/. */
#ifndef mozilla_WidgetUtils_h
#define mozilla_WidgetUtils_h
#include "mozilla/EventForwards.h"
#include "mozilla/gfx/Matrix.h"
#include "nsCOMPtr.h"
#include "nsIWidget.h"
#include "nsRect.h"
class nsPIDOMWindowOuter;
namespace mozilla {
// NB: these must match up with pseudo-enum in nsIScreen.idl.
enum ScreenRotation {
ROTATION_0 = 0,
ROTATION_90,
ROTATION_180,
ROTATION_270,
ROTATION_COUNT
};
gfx::Matrix ComputeTransformForRotation(const nsIntRect& aBounds,
ScreenRotation aRotation);
gfx::Matrix ComputeTransformForUnRotation(const nsIntRect& aBounds,
ScreenRotation aRotation);
nsIntRect RotateRect(nsIntRect aRect,
const nsIntRect& aBounds,
ScreenRotation aRotation);
namespace widget {
class WidgetUtils
{
public:
/**
* Shutdown() is called when "xpcom-will-shutdown" is notified. This is
* useful when you need to observe the notification in XP level code under
* widget.
*/
static void Shutdown();
/**
* Starting at the docshell item for the passed in DOM window this looks up
* the docshell tree until it finds a docshell item that has a widget.
*/
static already_AddRefed<nsIWidget> DOMWindowToWidget(nsPIDOMWindowOuter* aDOMWindow);
/**
* Compute our keyCode value (NS_VK_*) from an ASCII character.
*/
static uint32_t ComputeKeyCodeFromChar(uint32_t aCharCode);
/**
* Get unshifted charCode and shifted charCode for aKeyCode if the keyboad
* layout is a Latin keyboard layout.
*
* @param aKeyCode Our keyCode (NS_VK_*).
* @param aIsCapsLock TRUE if CapsLock is Locked. Otherwise, FALSE.
* This is used only when aKeyCode is NS_VK_[0-9].
* @param aUnshiftedCharCode CharCode for aKeyCode without Shift key.
* This may be zero if aKeyCode key doesn't input
* a Latin character.
* Note that must not be nullptr.
* @param aShiftedCharCode CharCode for aKeyCOde with Shift key.
* This is always 0 when aKeyCode isn't
* NS_VK_[A-Z].
* Note that must not be nullptr.
*/
static void GetLatinCharCodeForKeyCode(uint32_t aKeyCode,
bool aIsCapsLock,
uint32_t* aUnshiftedCharCode,
uint32_t* aShiftedCharCode);
/**
* Does device have touch support
*/
static uint32_t IsTouchDeviceSupportPresent();
/**
* Send bidi keyboard information to content process
*/
static void SendBidiKeyboardInfoToContent();
};
} // namespace widget
} // namespace mozilla
#endif // mozilla_WidgetUtils_h

37
widget/WindowSurface.h Normal file
View file

@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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/. */
#ifndef _MOZILLA_WIDGET_WINDOW_SURFACE_H
#define _MOZILLA_WIDGET_WINDOW_SURFACE_H
#include "mozilla/gfx/2D.h"
#include "Units.h"
namespace mozilla {
namespace widget {
// A class for drawing to double-buffered windows.
class WindowSurface {
public:
virtual ~WindowSurface() {}
// Locks a region of the window for drawing, returning a draw target
// capturing the bounds of the provided region.
// Implementations must permit invocation from any thread.
virtual already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion) = 0;
// Swaps the provided invalid region from the back buffer to the window.
// Implementations must permit invocation from any thread.
virtual void Commit(const LayoutDeviceIntRegion& aInvalidRegion) = 0;
// Whether the window surface represents a fallback method.
virtual bool IsFallback() const { return false; }
};
} // namespace widget
} // namespace mozilla
#endif // _MOZILLA_WIDGET_WINDOW_SURFACE_H

View file

@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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 "WindowSurfaceX11SHM.h"
namespace mozilla {
namespace widget {
WindowSurfaceX11SHM::WindowSurfaceX11SHM(Display* aDisplay, Drawable aWindow,
Visual* aVisual, unsigned int aDepth)
{
mFrontImage = new nsShmImage(aDisplay, aWindow, aVisual, aDepth);
mBackImage = new nsShmImage(aDisplay, aWindow, aVisual, aDepth);
}
already_AddRefed<gfx::DrawTarget>
WindowSurfaceX11SHM::Lock(const LayoutDeviceIntRegion& aRegion)
{
mBackImage.swap(mFrontImage);
return mBackImage->CreateDrawTarget(aRegion);
}
void
WindowSurfaceX11SHM::Commit(const LayoutDeviceIntRegion& aInvalidRegion)
{
mBackImage->Put(aInvalidRegion);
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,35 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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/. */
#ifndef _MOZILLA_WIDGET_WINDOW_SURFACE_X11_SHM_H
#define _MOZILLA_WIDGET_WINDOW_SURFACE_X11_SHM_H
#ifdef MOZ_X11
#include "mozilla/widget/WindowSurface.h"
#include "nsShmImage.h"
namespace mozilla {
namespace widget {
class WindowSurfaceX11SHM : public WindowSurface {
public:
WindowSurfaceX11SHM(Display* aDisplay, Drawable aWindow, Visual* aVisual,
unsigned int aDepth);
already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion) override;
void Commit(const LayoutDeviceIntRegion& aInvalidRegion) override;
private:
RefPtr<nsShmImage> mFrontImage;
RefPtr<nsShmImage> mBackImage;
};
} // namespace widget
} // namespace mozilla
#endif // MOZ_X11
#endif // _MOZILLA_WIDGET_WINDOW_SURFACE_X11_SHM_H

View file

@ -0,0 +1,89 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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 "ANRReporter.h"
#include "GeckoProfiler.h"
#include <unistd.h>
namespace mozilla {
bool
ANRReporter::RequestNativeStack(bool aUnwind)
{
if (profiler_is_active()) {
// Don't proceed if profiler is already running
return false;
}
// WARNING: we are on the ANR reporter thread at this point and it is
// generally unsafe to use the profiler from off the main thread. However,
// the risk here is limited because for most users, the profiler is not run
// elsewhere. See the discussion in Bug 863777, comment 13
const char *NATIVE_STACK_FEATURES[] =
{"leaf", "threads", "privacy"};
const char *NATIVE_STACK_UNWIND_FEATURES[] =
{"leaf", "threads", "privacy", "stackwalk"};
const char **features = NATIVE_STACK_FEATURES;
size_t features_size = sizeof(NATIVE_STACK_FEATURES);
if (aUnwind) {
features = NATIVE_STACK_UNWIND_FEATURES;
features_size = sizeof(NATIVE_STACK_UNWIND_FEATURES);
// We want the new unwinder if the unwind mode has not been set yet
putenv("MOZ_PROFILER_NEW=1");
}
const char *NATIVE_STACK_THREADS[] =
{"GeckoMain", "Compositor"};
// Buffer one sample and let the profiler wait a long time
profiler_start(100, 10000, features, features_size / sizeof(char*),
NATIVE_STACK_THREADS, sizeof(NATIVE_STACK_THREADS) / sizeof(char*));
return true;
}
jni::String::LocalRef
ANRReporter::GetNativeStack()
{
if (!profiler_is_active()) {
// Maybe profiler support is disabled?
return nullptr;
}
// Timeout if we don't get a profiler sample after 5 seconds.
const PRIntervalTime timeout = PR_SecondsToInterval(5);
const PRIntervalTime startTime = PR_IntervalNow();
// Pointer to a profile JSON string
typedef mozilla::UniquePtr<char[]> ProfilePtr;
ProfilePtr profile(profiler_get_profile());
while (profile && !strstr(profile.get(), "\"samples\":[{")) {
// no sample yet?
if (PR_IntervalNow() - startTime >= timeout) {
return nullptr;
}
usleep(100000ul); // Sleep for 100ms
profile = ProfilePtr(profiler_get_profile());
}
if (profile) {
return jni::String::Param(profile.get());
}
return nullptr;
}
void
ANRReporter::ReleaseNativeStack()
{
if (!profiler_is_active()) {
// Maybe profiler support is disabled?
return;
}
profiler_stop();
}
} // namespace

View file

@ -0,0 +1,26 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
#ifndef ANRReporter_h__
#define ANRReporter_h__
#include "FennecJNINatives.h"
namespace mozilla {
class ANRReporter : public java::ANRReporter::Natives<ANRReporter>
{
private:
ANRReporter();
public:
static bool RequestNativeStack(bool aUnwind);
static jni::String::LocalRef GetNativeStack();
static void ReleaseNativeStack();
};
} // namespace
#endif // ANRReporter_h__

View file

@ -0,0 +1,126 @@
/* -*- Mode: c++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4; -*- */
/* 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 "AndroidAlerts.h"
#include "GeneratedJNIWrappers.h"
#include "nsAlertsUtils.h"
namespace mozilla {
namespace widget {
NS_IMPL_ISUPPORTS(AndroidAlerts, nsIAlertsService)
StaticAutoPtr<AndroidAlerts::ListenerMap> AndroidAlerts::sListenerMap;
NS_IMETHODIMP
AndroidAlerts::ShowAlertNotification(const nsAString & aImageUrl,
const nsAString & aAlertTitle,
const nsAString & aAlertText,
bool aAlertTextClickable,
const nsAString & aAlertCookie,
nsIObserver * aAlertListener,
const nsAString & aAlertName,
const nsAString & aBidi,
const nsAString & aLang,
const nsAString & aData,
nsIPrincipal * aPrincipal,
bool aInPrivateBrowsing,
bool aRequireInteraction)
{
MOZ_ASSERT_UNREACHABLE("Should be implemented by nsAlertsService.");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
AndroidAlerts::ShowAlert(nsIAlertNotification* aAlert,
nsIObserver* aAlertListener)
{
return ShowPersistentNotification(EmptyString(), aAlert, aAlertListener);
}
NS_IMETHODIMP
AndroidAlerts::ShowPersistentNotification(const nsAString& aPersistentData,
nsIAlertNotification* aAlert,
nsIObserver* aAlertListener)
{
// nsAlertsService disables our alerts backend if we ever return failure
// here. To keep the backend enabled, we always return NS_OK even if we
// encounter an error here.
nsresult rv;
nsAutoString imageUrl;
rv = aAlert->GetImageURL(imageUrl);
NS_ENSURE_SUCCESS(rv, NS_OK);
nsAutoString title;
rv = aAlert->GetTitle(title);
NS_ENSURE_SUCCESS(rv, NS_OK);
nsAutoString text;
rv = aAlert->GetText(text);
NS_ENSURE_SUCCESS(rv, NS_OK);
nsAutoString cookie;
rv = aAlert->GetCookie(cookie);
NS_ENSURE_SUCCESS(rv, NS_OK);
nsAutoString name;
rv = aAlert->GetName(name);
NS_ENSURE_SUCCESS(rv, NS_OK);
nsCOMPtr<nsIPrincipal> principal;
rv = aAlert->GetPrincipal(getter_AddRefs(principal));
NS_ENSURE_SUCCESS(rv, NS_OK);
nsAutoString host;
nsAlertsUtils::GetSourceHostPort(principal, host);
if (aPersistentData.IsEmpty() && aAlertListener) {
if (!sListenerMap) {
sListenerMap = new ListenerMap();
}
// This will remove any observers already registered for this name.
sListenerMap->Put(name, aAlertListener);
}
java::GeckoAppShell::ShowNotification(
name, cookie, title, text, host, imageUrl,
!aPersistentData.IsEmpty() ? jni::StringParam(aPersistentData)
: jni::StringParam(nullptr));
return NS_OK;
}
NS_IMETHODIMP
AndroidAlerts::CloseAlert(const nsAString& aAlertName,
nsIPrincipal* aPrincipal)
{
// We delete the entry in sListenerMap later, when CloseNotification calls
// NotifyListener.
java::GeckoAppShell::CloseNotification(aAlertName);
return NS_OK;
}
void
AndroidAlerts::NotifyListener(const nsAString& aName, const char* aTopic,
const char16_t* aCookie)
{
if (!sListenerMap) {
return;
}
nsCOMPtr<nsIObserver> listener = sListenerMap->Get(aName);
if (!listener) {
return;
}
listener->Observe(nullptr, aTopic, aCookie);
if (NS_LITERAL_CSTRING("alertfinished").Equals(aTopic)) {
sListenerMap->Remove(aName);
}
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,44 @@
/* -*- Mode: c++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4; -*- */
/* 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/. */
#ifndef mozilla_widget_AndroidAlerts_h__
#define mozilla_widget_AndroidAlerts_h__
#include "nsInterfaceHashtable.h"
#include "nsCOMPtr.h"
#include "nsHashKeys.h"
#include "nsIAlertsService.h"
#include "nsIObserver.h"
#include "mozilla/StaticPtr.h"
namespace mozilla {
namespace widget {
class AndroidAlerts : public nsIAlertsService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIALERTSSERVICE
AndroidAlerts() {}
static void NotifyListener(const nsAString& aName, const char* aTopic,
const char16_t* aCookie);
protected:
virtual ~AndroidAlerts()
{
sListenerMap = nullptr;
}
using ListenerMap = nsInterfaceHashtable<nsStringHashKey, nsIObserver>;
static StaticAutoPtr<ListenerMap> sListenerMap;
};
} // namespace widget
} // namespace mozilla
#endif // nsAndroidAlerts_h__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,419 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
#ifndef AndroidBridge_h__
#define AndroidBridge_h__
#include <jni.h>
#include <android/log.h>
#include <cstdlib>
#include <pthread.h>
#include "APKOpen.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "GeneratedJNIWrappers.h"
#include "nsIMutableArray.h"
#include "nsIMIMEInfo.h"
#include "nsColor.h"
#include "gfxRect.h"
#include "nsIAndroidBridge.h"
#include "nsIDOMDOMCursor.h"
#include "mozilla/Likely.h"
#include "mozilla/Mutex.h"
#include "mozilla/Types.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/jni/Utils.h"
#include "nsIObserver.h"
#include "nsDataHashtable.h"
#include "Units.h"
// Some debug #defines
// #define DEBUG_ANDROID_EVENTS
// #define DEBUG_ANDROID_WIDGET
class nsPIDOMWindowOuter;
namespace base {
class Thread;
} // end namespace base
typedef void* EGLSurface;
namespace mozilla {
class AutoLocalJNIFrame;
class Runnable;
namespace hal {
class BatteryInformation;
class NetworkInformation;
} // namespace hal
// The order and number of the members in this structure must correspond
// to the attrsAppearance array in GeckoAppShell.getSystemColors()
typedef struct AndroidSystemColors {
nscolor textColorPrimary;
nscolor textColorPrimaryInverse;
nscolor textColorSecondary;
nscolor textColorSecondaryInverse;
nscolor textColorTertiary;
nscolor textColorTertiaryInverse;
nscolor textColorHighlight;
nscolor colorForeground;
nscolor colorBackground;
nscolor panelColorForeground;
nscolor panelColorBackground;
} AndroidSystemColors;
class MessageCursorContinueCallback : public nsICursorContinueCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICURSORCONTINUECALLBACK
MessageCursorContinueCallback(int aRequestId)
: mRequestId(aRequestId)
{
}
private:
virtual ~MessageCursorContinueCallback()
{
}
int mRequestId;
};
class AndroidBridge final
{
public:
enum {
// Values for NotifyIME, in addition to values from the Gecko
// IMEMessage enum; use negative values here to prevent conflict
NOTIFY_IME_OPEN_VKB = -2,
NOTIFY_IME_REPLY_EVENT = -1,
};
enum {
LAYER_CLIENT_TYPE_NONE = 0,
LAYER_CLIENT_TYPE_GL = 2 // AndroidGeckoGLLayerClient
};
static bool IsJavaUiThread() {
return pthread_equal(pthread_self(), ::getJavaUiThread());
}
static void ConstructBridge();
static void DeconstructBridge();
static AndroidBridge *Bridge() {
return sBridge;
}
void ContentDocumentChanged(mozIDOMWindowProxy* aDOMWindow);
bool IsContentDocumentDisplayed(mozIDOMWindowProxy* aDOMWindow);
bool GetHandlersForURL(const nsAString& aURL,
nsIMutableArray* handlersArray = nullptr,
nsIHandlerApp **aDefaultApp = nullptr,
const nsAString& aAction = EmptyString());
bool GetHandlersForMimeType(const nsAString& aMimeType,
nsIMutableArray* handlersArray = nullptr,
nsIHandlerApp **aDefaultApp = nullptr,
const nsAString& aAction = EmptyString());
bool GetHWEncoderCapability();
bool GetHWDecoderCapability();
void GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType);
void GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt);
bool GetClipboardText(nsAString& aText);
int GetDPI();
int GetScreenDepth();
void Vibrate(const nsTArray<uint32_t>& aPattern);
void GetSystemColors(AndroidSystemColors *aColors);
void GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize, uint8_t * const aBuf);
bool GetStaticStringField(const char *classID, const char *field, nsAString &result, JNIEnv* env = nullptr);
bool GetStaticIntField(const char *className, const char *fieldName, int32_t* aInt, JNIEnv* env = nullptr);
// Returns a global reference to the Context for Fennec's Activity. The
// caller is responsible for ensuring this doesn't leak by calling
// DeleteGlobalRef() when the context is no longer needed.
jobject GetGlobalContextRef(void);
void HandleGeckoMessage(JSContext* cx, JS::HandleObject message);
void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
// These methods don't use a ScreenOrientation because it's an
// enum and that would require including the header which requires
// include IPC headers which requires including basictypes.h which
// requires a lot of changes...
uint32_t GetScreenOrientation();
uint16_t GetScreenAngle();
int GetAPIVersion() { return mAPIVersion; }
nsresult GetProxyForURI(const nsACString & aSpec,
const nsACString & aScheme,
const nsACString & aHost,
const int32_t aPort,
nsACString & aResult);
bool PumpMessageLoop();
// Utility methods.
static jstring NewJavaString(JNIEnv* env, const char16_t* string, uint32_t len);
static jstring NewJavaString(JNIEnv* env, const nsAString& string);
static jstring NewJavaString(JNIEnv* env, const char* string);
static jstring NewJavaString(JNIEnv* env, const nsACString& string);
static jstring NewJavaString(AutoLocalJNIFrame* frame, const char16_t* string, uint32_t len);
static jstring NewJavaString(AutoLocalJNIFrame* frame, const nsAString& string);
static jstring NewJavaString(AutoLocalJNIFrame* frame, const char* string);
static jstring NewJavaString(AutoLocalJNIFrame* frame, const nsACString& string);
static jfieldID GetFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType);
static jfieldID GetStaticFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType);
static jmethodID GetMethodID(JNIEnv* env, jclass jClass, const char* methodName, const char* methodType);
static jmethodID GetStaticMethodID(JNIEnv* env, jclass jClass, const char* methodName, const char* methodType);
static jni::Object::LocalRef ChannelCreate(jni::Object::Param);
static void InputStreamClose(jni::Object::Param obj);
static uint32_t InputStreamAvailable(jni::Object::Param obj);
static nsresult InputStreamRead(jni::Object::Param obj, char *aBuf, uint32_t aCount, uint32_t *aRead);
protected:
static nsDataHashtable<nsStringHashKey, nsString> sStoragePaths;
static AndroidBridge* sBridge;
AndroidBridge();
~AndroidBridge();
int mAPIVersion;
// intput stream
jclass jReadableByteChannel;
jclass jChannels;
jmethodID jChannelCreate;
jmethodID jByteBufferRead;
jclass jInputStream;
jmethodID jClose;
jmethodID jAvailable;
jmethodID jCalculateLength;
// some convinient types to have around
jclass jStringClass;
jni::Object::GlobalRef mMessageQueue;
jfieldID mMessageQueueMessages;
jmethodID mMessageQueueNext;
private:
class DelayedTask;
nsTArray<DelayedTask> mUiTaskQueue;
mozilla::Mutex mUiTaskQueueLock;
public:
void PostTaskToUiThread(already_AddRefed<Runnable> aTask, int aDelayMs);
int64_t RunDelayedUiThreadTasks();
};
class AutoJNIClass {
private:
JNIEnv* const mEnv;
const jclass mClass;
public:
AutoJNIClass(JNIEnv* jEnv, const char* name)
: mEnv(jEnv)
, mClass(jni::GetClassRef(jEnv, name))
{}
~AutoJNIClass() {
mEnv->DeleteLocalRef(mClass);
}
jclass getRawRef() const {
return mClass;
}
jclass getGlobalRef() const {
return static_cast<jclass>(mEnv->NewGlobalRef(mClass));
}
jfieldID getField(const char* name, const char* type) const {
return AndroidBridge::GetFieldID(mEnv, mClass, name, type);
}
jfieldID getStaticField(const char* name, const char* type) const {
return AndroidBridge::GetStaticFieldID(mEnv, mClass, name, type);
}
jmethodID getMethod(const char* name, const char* type) const {
return AndroidBridge::GetMethodID(mEnv, mClass, name, type);
}
jmethodID getStaticMethod(const char* name, const char* type) const {
return AndroidBridge::GetStaticMethodID(mEnv, mClass, name, type);
}
};
class AutoJObject {
public:
AutoJObject(JNIEnv* aJNIEnv = nullptr) : mObject(nullptr)
{
mJNIEnv = aJNIEnv ? aJNIEnv : jni::GetGeckoThreadEnv();
}
AutoJObject(JNIEnv* aJNIEnv, jobject aObject)
{
mJNIEnv = aJNIEnv ? aJNIEnv : jni::GetGeckoThreadEnv();
mObject = aObject;
}
~AutoJObject() {
if (mObject)
mJNIEnv->DeleteLocalRef(mObject);
}
jobject operator=(jobject aObject)
{
if (mObject) {
mJNIEnv->DeleteLocalRef(mObject);
}
return mObject = aObject;
}
operator jobject() {
return mObject;
}
private:
JNIEnv* mJNIEnv;
jobject mObject;
};
class AutoLocalJNIFrame {
public:
AutoLocalJNIFrame(int nEntries = 15)
: mEntries(nEntries)
, mJNIEnv(jni::GetGeckoThreadEnv())
, mHasFrameBeenPushed(false)
{
MOZ_ASSERT(mJNIEnv);
Push();
}
AutoLocalJNIFrame(JNIEnv* aJNIEnv, int nEntries = 15)
: mEntries(nEntries)
, mJNIEnv(aJNIEnv ? aJNIEnv : jni::GetGeckoThreadEnv())
, mHasFrameBeenPushed(false)
{
MOZ_ASSERT(mJNIEnv);
Push();
}
~AutoLocalJNIFrame() {
if (mHasFrameBeenPushed) {
Pop();
}
}
JNIEnv* GetEnv() {
return mJNIEnv;
}
bool CheckForException() {
if (mJNIEnv->ExceptionCheck()) {
MOZ_CATCH_JNI_EXCEPTION(mJNIEnv);
return true;
}
return false;
}
// Note! Calling Purge makes all previous local refs created in
// the AutoLocalJNIFrame's scope INVALID; be sure that you locked down
// any local refs that you need to keep around in global refs!
void Purge() {
Pop();
Push();
}
template <typename ReturnType = jobject>
ReturnType Pop(ReturnType aResult = nullptr) {
MOZ_ASSERT(mHasFrameBeenPushed);
mHasFrameBeenPushed = false;
return static_cast<ReturnType>(
mJNIEnv->PopLocalFrame(static_cast<jobject>(aResult)));
}
private:
void Push() {
MOZ_ASSERT(!mHasFrameBeenPushed);
// Make sure there is enough space to store a local ref to the
// exception. I am not completely sure this is needed, but does
// not hurt.
if (mJNIEnv->PushLocalFrame(mEntries + 1) != 0) {
CheckForException();
return;
}
mHasFrameBeenPushed = true;
}
const int mEntries;
JNIEnv* const mJNIEnv;
bool mHasFrameBeenPushed;
};
}
#define NS_ANDROIDBRIDGE_CID \
{ 0x0FE2321D, 0xEBD9, 0x467D, \
{ 0xA7, 0x43, 0x03, 0xA6, 0x8D, 0x40, 0x59, 0x9E } }
class nsAndroidBridge final : public nsIAndroidBridge,
public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIANDROIDBRIDGE
NS_DECL_NSIOBSERVER
nsAndroidBridge();
private:
~nsAndroidBridge();
void AddObservers();
void RemoveObservers();
void UpdateAudioPlayingWindows(uint64_t aWindowId, bool aPlaying);
nsTArray<uint64_t> mAudioPlayingWindows;
protected:
};
#endif /* AndroidBridge_h__ */

View file

@ -0,0 +1,13 @@
#ifndef ALOG
#if defined(DEBUG) || defined(FORCE_ALOG)
#define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
#else
#define ALOG(args...) ((void)0)
#endif
#endif
#ifdef DEBUG
#define ALOG_BRIDGE(args...) ALOG(args)
#else
#define ALOG_BRIDGE(args...) ((void)0)
#endif

View file

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=2 et tw=80 : */
/* 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 "AndroidCompositorWidget.h"
#include "nsWindow.h"
namespace mozilla {
namespace widget {
void
AndroidCompositorWidget::SetFirstPaintViewport(const LayerIntPoint& aOffset,
const CSSToLayerScale& aZoom,
const CSSRect& aCssPageRect)
{
auto layerClient = static_cast<nsWindow*>(RealWidget())->GetLayerClient();
if (!layerClient) {
return;
}
layerClient->SetFirstPaintViewport(
float(aOffset.x), float(aOffset.y), aZoom.scale, aCssPageRect.x,
aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
}
void
AndroidCompositorWidget::SyncFrameMetrics(const ParentLayerPoint& aScrollOffset,
const CSSToParentLayerScale& aZoom,
const CSSRect& aCssPageRect,
const CSSRect& aDisplayPort,
const CSSToLayerScale& aPaintedResolution,
bool aLayersUpdated,
int32_t aPaintSyncId,
ScreenMargin& aFixedLayerMargins)
{
auto layerClient = static_cast<nsWindow*>(RealWidget())->GetLayerClient();
if (!layerClient) {
return;
}
// convert the displayport rect from document-relative CSS pixels to
// document-relative device pixels
LayerIntRect dp = gfx::RoundedToInt(aDisplayPort * aPaintedResolution);
java::ViewTransform::LocalRef viewTransform = layerClient->SyncFrameMetrics(
aScrollOffset.x, aScrollOffset.y, aZoom.scale,
aCssPageRect.x, aCssPageRect.y,
aCssPageRect.XMost(), aCssPageRect.YMost(),
dp.x, dp.y, dp.width, dp.height,
aPaintedResolution.scale, aLayersUpdated, aPaintSyncId);
MOZ_ASSERT(viewTransform, "No view transform object!");
aFixedLayerMargins.top = viewTransform->FixedLayerMarginTop();
aFixedLayerMargins.right = viewTransform->FixedLayerMarginRight();
aFixedLayerMargins.bottom = viewTransform->FixedLayerMarginBottom();
aFixedLayerMargins.left = viewTransform->FixedLayerMarginLeft();
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,44 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
#ifndef mozilla_widget_AndroidCompositorWidget_h
#define mozilla_widget_AndroidCompositorWidget_h
#include "mozilla/widget/InProcessCompositorWidget.h"
namespace mozilla {
namespace widget {
/**
* AndroidCompositorWidget inherits from InProcessCompositorWidget because
* Android does not support OOP compositing yet. Once it does,
* AndroidCompositorWidget will be made to inherit from CompositorWidget
* instead.
*/
class AndroidCompositorWidget final : public InProcessCompositorWidget
{
public:
using InProcessCompositorWidget::InProcessCompositorWidget;
AndroidCompositorWidget* AsAndroid() override { return this; }
void SetFirstPaintViewport(const LayerIntPoint& aOffset,
const CSSToLayerScale& aZoom,
const CSSRect& aCssPageRect);
void SyncFrameMetrics(const ParentLayerPoint& aScrollOffset,
const CSSToParentLayerScale& aZoom,
const CSSRect& aCssPageRect,
const CSSRect& aDisplayPort,
const CSSToLayerScale& aPaintedResolution,
bool aLayersUpdated,
int32_t aPaintSyncId,
ScreenMargin& aFixedLayerMargins);
};
} // namespace widget
} // namespace mozilla
#endif // mozilla_widget_AndroidCompositorWidget_h

View file

@ -0,0 +1,157 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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 "AndroidContentController.h"
#include "AndroidBridge.h"
#include "base/message_loop.h"
#include "mozilla/layers/APZCCallbackHelper.h"
#include "mozilla/layers/IAPZCTreeManager.h"
#include "nsIObserverService.h"
#include "nsLayoutUtils.h"
#include "nsWindow.h"
using mozilla::layers::IAPZCTreeManager;
namespace mozilla {
namespace widget {
void
AndroidContentController::Destroy()
{
mAndroidWindow = nullptr;
ChromeProcessController::Destroy();
}
void
AndroidContentController::NotifyDefaultPrevented(IAPZCTreeManager* aManager,
uint64_t aInputBlockId,
bool aDefaultPrevented)
{
if (!AndroidBridge::IsJavaUiThread()) {
// The notification must reach the APZ on the Java UI thread (aka the
// APZ "controller" thread) but we get it from the Gecko thread, so we
// have to throw it onto the other thread.
AndroidBridge::Bridge()->PostTaskToUiThread(NewRunnableMethod<uint64_t, bool>(
aManager, &IAPZCTreeManager::ContentReceivedInputBlock,
aInputBlockId, aDefaultPrevented), 0);
return;
}
aManager->ContentReceivedInputBlock(aInputBlockId, aDefaultPrevented);
}
void
AndroidContentController::DispatchSingleTapToObservers(const LayoutDevicePoint& aPoint,
const ScrollableLayerGuid& aGuid) const
{
nsIContent* content = nsLayoutUtils::FindContentFor(aGuid.mScrollId);
nsPresContext* context = content
? mozilla::layers::APZCCallbackHelper::GetPresContextForContent(content)
: nullptr;
if (!context) {
return;
}
CSSPoint point = mozilla::layers::APZCCallbackHelper::ApplyCallbackTransform(
aPoint / context->CSSToDevPixelScale(), aGuid);
nsPresContext* rcdContext = context->GetToplevelContentDocumentPresContext();
if (rcdContext && rcdContext->PresShell()->ScaleToResolution()) {
// We need to convert from the root document to the root content document,
// by unapplying the resolution that's on the content document.
const float resolution = rcdContext->PresShell()->GetResolution();
point.x /= resolution;
point.y /= resolution;
}
CSSIntPoint rounded = RoundedToInt(point);
nsAppShell::PostEvent([rounded] {
nsCOMPtr<nsIObserverService> obsServ =
mozilla::services::GetObserverService();
if (!obsServ) {
return;
}
nsPrintfCString data("{\"x\":%d,\"y\":%d}", rounded.x, rounded.y);
obsServ->NotifyObservers(nullptr, "Gesture:SingleTap",
NS_ConvertASCIItoUTF16(data).get());
});
}
void
AndroidContentController::HandleTap(TapType aType, const LayoutDevicePoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId)
{
// This function will get invoked first on the Java UI thread, and then
// again on the main thread (because of the code in ChromeProcessController::
// HandleTap). We want to post the SingleTap message once; it can be
// done from either thread but we need access to the callback transform
// so we do it from the main thread.
if (NS_IsMainThread() &&
(aType == TapType::eSingleTap || aType == TapType::eSecondTap)) {
DispatchSingleTapToObservers(aPoint, aGuid);
}
ChromeProcessController::HandleTap(aType, aPoint, aModifiers, aGuid, aInputBlockId);
}
void
AndroidContentController::PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs)
{
AndroidBridge::Bridge()->PostTaskToUiThread(Move(aTask), aDelayMs);
}
void
AndroidContentController::UpdateOverscrollVelocity(const float aX, const float aY, const bool aIsRootContent)
{
if (aIsRootContent && mAndroidWindow) {
mAndroidWindow->UpdateOverscrollVelocity(aX, aY);
}
}
void
AndroidContentController::UpdateOverscrollOffset(const float aX, const float aY, const bool aIsRootContent)
{
if (aIsRootContent && mAndroidWindow) {
mAndroidWindow->UpdateOverscrollOffset(aX, aY);
}
}
void
AndroidContentController::SetScrollingRootContent(const bool isRootContent)
{
if (mAndroidWindow) {
mAndroidWindow->SetScrollingRootContent(isRootContent);
}
}
void
AndroidContentController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
APZStateChange aChange,
int aArg)
{
// This function may get invoked twice, if the first invocation is not on
// the main thread then the ChromeProcessController version of this function
// will redispatch to the main thread. We want to make sure that our handling
// only happens on the main thread.
ChromeProcessController::NotifyAPZStateChange(aGuid, aChange, aArg);
if (NS_IsMainThread()) {
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
if (aChange == layers::GeckoContentController::APZStateChange::eTransformEnd) {
// This is used by tests to determine when the APZ is done doing whatever
// it's doing. XXX generify this as needed when writing additional tests.
observerService->NotifyObservers(nullptr, "APZ:TransformEnd", nullptr);
observerService->NotifyObservers(nullptr, "PanZoom:StateChange", u"NOTHING");
} else if (aChange == layers::GeckoContentController::APZStateChange::eTransformBegin) {
observerService->NotifyObservers(nullptr, "PanZoom:StateChange", u"PANNING");
}
}
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,59 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
#ifndef AndroidContentController_h__
#define AndroidContentController_h__
#include "mozilla/layers/ChromeProcessController.h"
#include "mozilla/EventForwards.h" // for Modifiers
#include "mozilla/StaticPtr.h"
#include "mozilla/TimeStamp.h"
#include "nsIDOMWindowUtils.h"
#include "nsTArray.h"
#include "nsWindow.h"
namespace mozilla {
namespace layers {
class APZEventState;
class IAPZCTreeManager;
}
namespace widget {
class AndroidContentController final
: public mozilla::layers::ChromeProcessController
{
public:
AndroidContentController(nsWindow* aWindow,
mozilla::layers::APZEventState* aAPZEventState,
mozilla::layers::IAPZCTreeManager* aAPZCTreeManager)
: mozilla::layers::ChromeProcessController(aWindow, aAPZEventState, aAPZCTreeManager)
, mAndroidWindow(aWindow)
{}
// ChromeProcessController methods
virtual void Destroy() override;
void HandleTap(TapType aType, const LayoutDevicePoint& aPoint, Modifiers aModifiers,
const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId) override;
void PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs) override;
void UpdateOverscrollVelocity(const float aX, const float aY, const bool aIsRootContent) override;
void UpdateOverscrollOffset(const float aX, const float aY, const bool aIsRootContent) override;
void SetScrollingRootContent(const bool isRootContent) override;
void NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
APZStateChange aChange,
int aArg) override;
static void NotifyDefaultPrevented(mozilla::layers::IAPZCTreeManager* aManager,
uint64_t aInputBlockId, bool aDefaultPrevented);
private:
nsWindow* mAndroidWindow;
void DispatchSingleTapToObservers(const LayoutDevicePoint& aPoint,
const ScrollableLayerGuid& aGuid) const;
};
} // namespace widget
} // namespace mozilla
#endif

View file

@ -0,0 +1,58 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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/. */
#ifndef AndroidDirectTexture_h_
#define AndroidDirectTexture_h_
#include "gfxTypes.h"
#include "mozilla/Mutex.h"
#include "AndroidGraphicBuffer.h"
#include "nsRect.h"
namespace mozilla {
/**
* This is a thread safe wrapper around AndroidGraphicBuffer that handles
* double buffering. Each call to Bind() flips the buffer when necessary.
*
* You need to be careful when destroying an instance of this class. If either
* buffer is locked by the application of the driver/hardware, bad things will
* happen. Be sure that the OpenGL texture is no longer on the screen.
*/
class AndroidDirectTexture
{
public:
AndroidDirectTexture(uint32_t width, uint32_t height, uint32_t usage, gfxImageFormat format);
virtual ~AndroidDirectTexture();
bool Lock(uint32_t usage, unsigned char **bits);
bool Lock(uint32_t usage, const nsIntRect& rect, unsigned char **bits);
bool Unlock(bool aFlip = true);
bool Reallocate(uint32_t aWidth, uint32_t aHeight);
bool Reallocate(uint32_t aWidth, uint32_t aHeight, gfxImageFormat aFormat);
uint32_t Width() { return mWidth; }
uint32_t Height() { return mHeight; }
bool Bind();
private:
mozilla::Mutex mLock;
bool mNeedFlip;
uint32_t mWidth;
uint32_t mHeight;
gfxImageFormat mFormat;
AndroidGraphicBuffer* mFrontBuffer;
AndroidGraphicBuffer* mBackBuffer;
AndroidGraphicBuffer* mPendingReallocBuffer;
void ReallocPendingBuffer();
};
} /* mozilla */
#endif /* AndroidDirectTexture_h_ */

View file

@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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/. */
#ifndef AndroidGraphicBuffer_h_
#define AndroidGraphicBuffer_h_
#include "gfxTypes.h"
#include "nsRect.h"
typedef void* EGLImageKHR;
typedef void* EGLClientBuffer;
namespace mozilla {
/**
* This class allows access to Android's direct texturing mechanism. Locking
* the buffer gives you a pointer you can read/write to directly. It is fully
* threadsafe, but you probably really want to use the AndroidDirectTexture
* class which will handle double buffering.
*
* In order to use the buffer in OpenGL, just call Bind() and it will attach
* to whatever texture is bound to GL_TEXTURE_2D.
*/
class AndroidGraphicBuffer
{
public:
enum {
UsageSoftwareRead = 1,
UsageSoftwareWrite = 1 << 1,
UsageTexture = 1 << 2,
UsageTarget = 1 << 3,
Usage2D = 1 << 4
};
AndroidGraphicBuffer(uint32_t width, uint32_t height, uint32_t usage, gfxImageFormat format);
virtual ~AndroidGraphicBuffer();
int Lock(uint32_t usage, unsigned char **bits);
int Lock(uint32_t usage, const nsIntRect& rect, unsigned char **bits);
int Unlock();
bool Reallocate(uint32_t aWidth, uint32_t aHeight, gfxImageFormat aFormat);
uint32_t Width() { return mWidth; }
uint32_t Height() { return mHeight; }
bool Bind();
static bool IsBlacklisted();
private:
uint32_t mWidth;
uint32_t mHeight;
uint32_t mUsage;
gfxImageFormat mFormat;
bool EnsureInitialized();
bool EnsureEGLImage();
void DestroyBuffer();
bool EnsureBufferCreated();
uint32_t GetAndroidUsage(uint32_t aUsage);
uint32_t GetAndroidFormat(gfxImageFormat aFormat);
void *mHandle;
void *mEGLImage;
};
} /* mozilla */
#endif /* AndroidGraphicBuffer_h_ */

View file

@ -0,0 +1,47 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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 "mozilla/Hal.h"
#include "nsIFile.h"
#include "nsString.h"
#include "AndroidBridge.h"
#include "AndroidContentController.h"
#include "AndroidGraphicBuffer.h"
#include <jni.h>
#include <pthread.h>
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>
#include "nsAppShell.h"
#include "nsWindow.h"
#include <android/log.h>
#include "nsIObserverService.h"
#include "mozilla/Services.h"
#include "nsThreadUtils.h"
#include "mozilla/Unused.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "nsPluginInstanceOwner.h"
#include "AndroidSurfaceTexture.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::layers;
using namespace mozilla::widget;
/* Forward declare all the JNI methods as extern "C" */
extern "C" {
/*
* Incoming JNI methods
*/
}

View file

@ -0,0 +1,140 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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 <android/log.h>
#include <dlfcn.h>
#include <prthread.h>
#include "mozilla/DebugOnly.h"
#include "mozilla/Assertions.h"
#include "mozilla/SyncRunnable.h"
#include "nsThreadUtils.h"
#include "AndroidBridge.h"
extern "C" {
jclass __jsjni_GetGlobalClassRef(const char *className);
}
class GetGlobalClassRefRunnable : public mozilla::Runnable {
public:
GetGlobalClassRefRunnable(const char *className, jclass *foundClass) :
mClassName(className), mResult(foundClass) {}
NS_IMETHOD Run() override {
*mResult = __jsjni_GetGlobalClassRef(mClassName);
return NS_OK;
}
private:
const char *mClassName;
jclass *mResult;
};
extern "C" {
__attribute__ ((visibility("default")))
jclass
jsjni_FindClass(const char *className) {
// FindClass outside the main thread will run into problems due
// to missing the classpath
MOZ_ASSERT(NS_IsMainThread());
JNIEnv *env = mozilla::jni::GetGeckoThreadEnv();
return env->FindClass(className);
}
jclass
__jsjni_GetGlobalClassRef(const char *className) {
// root class globally
JNIEnv *env = mozilla::jni::GetGeckoThreadEnv();
jclass globalRef = static_cast<jclass>(env->NewGlobalRef(env->FindClass(className)));
if (!globalRef)
return nullptr;
// return the newly create global reference
return globalRef;
}
__attribute__ ((visibility("default")))
jclass
jsjni_GetGlobalClassRef(const char *className) {
if (NS_IsMainThread()) {
return __jsjni_GetGlobalClassRef(className);
}
nsCOMPtr<nsIThread> mainThread;
mozilla::DebugOnly<nsresult> rv = NS_GetMainThread(getter_AddRefs(mainThread));
MOZ_ASSERT(NS_SUCCEEDED(rv));
jclass foundClass;
nsCOMPtr<nsIRunnable> runnable_ref(new GetGlobalClassRefRunnable(className,
&foundClass));
RefPtr<mozilla::SyncRunnable> sr = new mozilla::SyncRunnable(runnable_ref);
sr->DispatchToThread(mainThread);
if (!foundClass)
return nullptr;
return foundClass;
}
__attribute__ ((visibility("default")))
jmethodID
jsjni_GetStaticMethodID(jclass methodClass,
const char *methodName,
const char *signature) {
JNIEnv *env = mozilla::jni::GetGeckoThreadEnv();
return env->GetStaticMethodID(methodClass, methodName, signature);
}
__attribute__ ((visibility("default")))
bool
jsjni_ExceptionCheck() {
JNIEnv *env = mozilla::jni::GetGeckoThreadEnv();
return env->ExceptionCheck();
}
__attribute__ ((visibility("default")))
void
jsjni_CallStaticVoidMethodA(jclass cls,
jmethodID method,
jvalue *values) {
JNIEnv *env = mozilla::jni::GetGeckoThreadEnv();
mozilla::AutoLocalJNIFrame jniFrame(env);
env->CallStaticVoidMethodA(cls, method, values);
}
__attribute__ ((visibility("default")))
int
jsjni_CallStaticIntMethodA(jclass cls,
jmethodID method,
jvalue *values) {
JNIEnv *env = mozilla::jni::GetGeckoThreadEnv();
mozilla::AutoLocalJNIFrame jniFrame(env);
return env->CallStaticIntMethodA(cls, method, values);
}
__attribute__ ((visibility("default")))
jobject jsjni_GetGlobalContextRef() {
return mozilla::AndroidBridge::Bridge()->GetGlobalContextRef();
}
__attribute__ ((visibility("default")))
JavaVM* jsjni_GetVM() {
JavaVM* jvm;
JNIEnv* const env = mozilla::jni::GetGeckoThreadEnv();
MOZ_ALWAYS_TRUE(!env->GetJavaVM(&jvm));
return jvm;
}
__attribute__ ((visibility("default")))
JNIEnv* jsjni_GetJNIForThread() {
return mozilla::jni::GetEnvForThread();
}
// For compatibility with JNI.jsm; some addons bundle their own JNI.jsm,
// so we cannot just change the function name used in JNI.jsm.
__attribute__ ((visibility("default")))
JNIEnv* GetJNIForThread() {
return mozilla::jni::GetEnvForThread();
}
}

View file

@ -0,0 +1,34 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
#ifndef AndroidJNIWrapper_h__
#define AndroidJNIWrapper_h__
#include "mozilla/Types.h"
#include <jni.h>
#include <android/log.h>
extern "C" MOZ_EXPORT jclass jsjni_FindClass(const char *className);
/**
* JNIEnv::FindClass alternative.
* Callable from any thread, including code
* invoked via the JNI that doesn't have MOZILLA_INTERNAL_API defined.
* The caller is responsible for ensuring that the class is not leaked by
* calling DeleteGlobalRef at an appropriate time.
*/
extern "C" MOZ_EXPORT jclass jsjni_GetGlobalClassRef(const char *className);
extern "C" MOZ_EXPORT jmethodID jsjni_GetStaticMethodID(jclass methodClass,
const char *methodName,
const char *signature);
extern "C" MOZ_EXPORT bool jsjni_ExceptionCheck();
extern "C" MOZ_EXPORT void jsjni_CallStaticVoidMethodA(jclass cls, jmethodID method, jvalue *values);
extern "C" MOZ_EXPORT int jsjni_CallStaticIntMethodA(jclass cls, jmethodID method, jvalue *values);
extern "C" MOZ_EXPORT jobject jsjni_GetGlobalContextRef();
extern "C" MOZ_EXPORT JavaVM* jsjni_GetVM();
extern "C" MOZ_EXPORT JNIEnv* jsjni_GetJNIForThread();
#endif /* AndroidJNIWrapper_h__ */

View file

@ -0,0 +1,62 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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 "AndroidJavaWrappers.h"
using namespace mozilla;
nsJNIString::nsJNIString(jstring jstr, JNIEnv *jenv)
{
if (!jstr) {
SetIsVoid(true);
return;
}
JNIEnv *jni = jenv;
if (!jni) {
jni = jni::GetGeckoThreadEnv();
}
const jchar* jCharPtr = jni->GetStringChars(jstr, nullptr);
if (!jCharPtr) {
SetIsVoid(true);
return;
}
jsize len = jni->GetStringLength(jstr);
if (len <= 0) {
SetIsVoid(true);
} else {
Assign(reinterpret_cast<const char16_t*>(jCharPtr), len);
}
jni->ReleaseStringChars(jstr, jCharPtr);
}
nsJNICString::nsJNICString(jstring jstr, JNIEnv *jenv)
{
if (!jstr) {
SetIsVoid(true);
return;
}
JNIEnv *jni = jenv;
if (!jni) {
jni = jni::GetGeckoThreadEnv();
}
const char* jCharPtr = jni->GetStringUTFChars(jstr, nullptr);
if (!jCharPtr) {
SetIsVoid(true);
return;
}
jsize len = jni->GetStringUTFLength(jstr);
if (len <= 0) {
SetIsVoid(true);
} else {
Assign(jCharPtr, len);
}
jni->ReleaseStringUTFChars(jstr, jCharPtr);
}

View file

@ -0,0 +1,218 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
#ifndef AndroidJavaWrappers_h__
#define AndroidJavaWrappers_h__
#include <jni.h>
#include <android/input.h>
#include <android/log.h>
#include <android/api-level.h>
#include "nsRect.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsIAndroidBridge.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/dom/Touch.h"
#include "mozilla/EventForwards.h"
#include "InputData.h"
#include "Units.h"
#include "FrameMetrics.h"
//#define FORCE_ALOG 1
class nsIAndroidDisplayport;
class nsIWidget;
namespace mozilla {
enum {
// These keycode masks are not defined in android/keycodes.h:
#if __ANDROID_API__ < 13
AKEYCODE_ESCAPE = 111,
AKEYCODE_FORWARD_DEL = 112,
AKEYCODE_CTRL_LEFT = 113,
AKEYCODE_CTRL_RIGHT = 114,
AKEYCODE_CAPS_LOCK = 115,
AKEYCODE_SCROLL_LOCK = 116,
AKEYCODE_META_LEFT = 117,
AKEYCODE_META_RIGHT = 118,
AKEYCODE_FUNCTION = 119,
AKEYCODE_SYSRQ = 120,
AKEYCODE_BREAK = 121,
AKEYCODE_MOVE_HOME = 122,
AKEYCODE_MOVE_END = 123,
AKEYCODE_INSERT = 124,
AKEYCODE_FORWARD = 125,
AKEYCODE_MEDIA_PLAY = 126,
AKEYCODE_MEDIA_PAUSE = 127,
AKEYCODE_MEDIA_CLOSE = 128,
AKEYCODE_MEDIA_EJECT = 129,
AKEYCODE_MEDIA_RECORD = 130,
AKEYCODE_F1 = 131,
AKEYCODE_F2 = 132,
AKEYCODE_F3 = 133,
AKEYCODE_F4 = 134,
AKEYCODE_F5 = 135,
AKEYCODE_F6 = 136,
AKEYCODE_F7 = 137,
AKEYCODE_F8 = 138,
AKEYCODE_F9 = 139,
AKEYCODE_F10 = 140,
AKEYCODE_F11 = 141,
AKEYCODE_F12 = 142,
AKEYCODE_NUM_LOCK = 143,
AKEYCODE_NUMPAD_0 = 144,
AKEYCODE_NUMPAD_1 = 145,
AKEYCODE_NUMPAD_2 = 146,
AKEYCODE_NUMPAD_3 = 147,
AKEYCODE_NUMPAD_4 = 148,
AKEYCODE_NUMPAD_5 = 149,
AKEYCODE_NUMPAD_6 = 150,
AKEYCODE_NUMPAD_7 = 151,
AKEYCODE_NUMPAD_8 = 152,
AKEYCODE_NUMPAD_9 = 153,
AKEYCODE_NUMPAD_DIVIDE = 154,
AKEYCODE_NUMPAD_MULTIPLY = 155,
AKEYCODE_NUMPAD_SUBTRACT = 156,
AKEYCODE_NUMPAD_ADD = 157,
AKEYCODE_NUMPAD_DOT = 158,
AKEYCODE_NUMPAD_COMMA = 159,
AKEYCODE_NUMPAD_ENTER = 160,
AKEYCODE_NUMPAD_EQUALS = 161,
AKEYCODE_NUMPAD_LEFT_PAREN = 162,
AKEYCODE_NUMPAD_RIGHT_PAREN = 163,
AKEYCODE_VOLUME_MUTE = 164,
AKEYCODE_INFO = 165,
AKEYCODE_CHANNEL_UP = 166,
AKEYCODE_CHANNEL_DOWN = 167,
AKEYCODE_ZOOM_IN = 168,
AKEYCODE_ZOOM_OUT = 169,
AKEYCODE_TV = 170,
AKEYCODE_WINDOW = 171,
AKEYCODE_GUIDE = 172,
AKEYCODE_DVR = 173,
AKEYCODE_BOOKMARK = 174,
AKEYCODE_CAPTIONS = 175,
AKEYCODE_SETTINGS = 176,
AKEYCODE_TV_POWER = 177,
AKEYCODE_TV_INPUT = 178,
AKEYCODE_STB_POWER = 179,
AKEYCODE_STB_INPUT = 180,
AKEYCODE_AVR_POWER = 181,
AKEYCODE_AVR_INPUT = 182,
AKEYCODE_PROG_RED = 183,
AKEYCODE_PROG_GREEN = 184,
AKEYCODE_PROG_YELLOW = 185,
AKEYCODE_PROG_BLUE = 186,
AKEYCODE_APP_SWITCH = 187,
AKEYCODE_BUTTON_1 = 188,
AKEYCODE_BUTTON_2 = 189,
AKEYCODE_BUTTON_3 = 190,
AKEYCODE_BUTTON_4 = 191,
AKEYCODE_BUTTON_5 = 192,
AKEYCODE_BUTTON_6 = 193,
AKEYCODE_BUTTON_7 = 194,
AKEYCODE_BUTTON_8 = 195,
AKEYCODE_BUTTON_9 = 196,
AKEYCODE_BUTTON_10 = 197,
AKEYCODE_BUTTON_11 = 198,
AKEYCODE_BUTTON_12 = 199,
AKEYCODE_BUTTON_13 = 200,
AKEYCODE_BUTTON_14 = 201,
AKEYCODE_BUTTON_15 = 202,
AKEYCODE_BUTTON_16 = 203,
#endif
#if __ANDROID_API__ < 14
AKEYCODE_LANGUAGE_SWITCH = 204,
AKEYCODE_MANNER_MODE = 205,
AKEYCODE_3D_MODE = 206,
#endif
#if __ANDROID_API__ < 15
AKEYCODE_CONTACTS = 207,
AKEYCODE_CALENDAR = 208,
AKEYCODE_MUSIC = 209,
AKEYCODE_CALCULATOR = 210,
#endif
#if __ANDROID_API__ < 16
AKEYCODE_ZENKAKU_HANKAKU = 211,
AKEYCODE_EISU = 212,
AKEYCODE_MUHENKAN = 213,
AKEYCODE_HENKAN = 214,
AKEYCODE_KATAKANA_HIRAGANA = 215,
AKEYCODE_YEN = 216,
AKEYCODE_RO = 217,
AKEYCODE_KANA = 218,
AKEYCODE_ASSIST = 219,
#endif
AMETA_FUNCTION_ON = 0x00000008,
AMETA_CTRL_ON = 0x00001000,
AMETA_CTRL_LEFT_ON = 0x00002000,
AMETA_CTRL_RIGHT_ON = 0x00004000,
AMETA_META_ON = 0x00010000,
AMETA_META_LEFT_ON = 0x00020000,
AMETA_META_RIGHT_ON = 0x00040000,
AMETA_CAPS_LOCK_ON = 0x00100000,
AMETA_NUM_LOCK_ON = 0x00200000,
AMETA_SCROLL_LOCK_ON = 0x00400000,
AMETA_ALT_MASK = AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON | AMETA_ALT_ON,
AMETA_CTRL_MASK = AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON | AMETA_CTRL_ON,
AMETA_META_MASK = AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON | AMETA_META_ON,
AMETA_SHIFT_MASK = AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON | AMETA_SHIFT_ON,
};
class AndroidMotionEvent
{
public:
enum {
ACTION_DOWN = 0,
ACTION_UP = 1,
ACTION_MOVE = 2,
ACTION_CANCEL = 3,
ACTION_OUTSIDE = 4,
ACTION_POINTER_DOWN = 5,
ACTION_POINTER_UP = 6,
ACTION_HOVER_MOVE = 7,
ACTION_HOVER_ENTER = 9,
ACTION_HOVER_EXIT = 10,
ACTION_MAGNIFY_START = 11,
ACTION_MAGNIFY = 12,
ACTION_MAGNIFY_END = 13,
EDGE_TOP = 0x00000001,
EDGE_BOTTOM = 0x00000002,
EDGE_LEFT = 0x00000004,
EDGE_RIGHT = 0x00000008,
SAMPLE_X = 0,
SAMPLE_Y = 1,
SAMPLE_PRESSURE = 2,
SAMPLE_SIZE = 3,
NUM_SAMPLE_DATA = 4,
TOOL_TYPE_UNKNOWN = 0,
TOOL_TYPE_FINGER = 1,
TOOL_TYPE_STYLUS = 2,
TOOL_TYPE_MOUSE = 3,
TOOL_TYPE_ERASER = 4,
dummy_java_enum_list_end
};
};
class nsJNIString : public nsString
{
public:
nsJNIString(jstring jstr, JNIEnv *jenv);
};
class nsJNICString : public nsCString
{
public:
nsJNICString(jstring jstr, JNIEnv *jenv);
};
}
#endif

View file

@ -0,0 +1,30 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
#ifndef GeckoBatteryManager_h
#define GeckoBatteryManager_h
#include "GeneratedJNINatives.h"
#include "nsAppShell.h"
#include "mozilla/Hal.h"
namespace mozilla {
class GeckoBatteryManager final
: public java::GeckoBatteryManager::Natives<GeckoBatteryManager>
{
public:
static void
OnBatteryChange(double aLevel, bool aCharging, double aRemainingTime)
{
hal::NotifyBatteryChange(
hal::BatteryInformation(aLevel, aCharging, aRemainingTime));
}
};
} // namespace mozilla
#endif // GeckoBatteryManager_h

View file

@ -0,0 +1,53 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
#ifndef GeckoNetworkManager_h
#define GeckoNetworkManager_h
#include "GeneratedJNINatives.h"
#include "nsAppShell.h"
#include "nsCOMPtr.h"
#include "nsINetworkLinkService.h"
#include "mozilla/Services.h"
namespace mozilla {
class GeckoNetworkManager final
: public java::GeckoNetworkManager::Natives<GeckoNetworkManager>
{
GeckoNetworkManager() = delete;
public:
static void
OnConnectionChanged(int32_t aType, jni::String::Param aSubType,
bool aIsWifi, int32_t aGateway)
{
hal::NotifyNetworkChange(hal::NetworkInformation(
aType, aIsWifi, aGateway));
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->NotifyObservers(nullptr,
NS_NETWORK_LINK_TYPE_TOPIC,
aSubType->ToString().get());
}
}
static void
OnStatusChanged(jni::String::Param aStatus)
{
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
os->NotifyObservers(nullptr,
NS_NETWORK_LINK_TOPIC,
aStatus->ToString().get());
}
}
};
} // namespace mozilla
#endif // GeckoNetworkManager_h

View file

@ -0,0 +1,55 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
#ifndef GeckoScreenOrientation_h
#define GeckoScreenOrientation_h
#include "GeneratedJNINatives.h"
#include "nsAppShell.h"
#include "nsCOMPtr.h"
#include "nsIScreenManager.h"
#include "mozilla/Hal.h"
#include "mozilla/dom/ScreenOrientation.h"
namespace mozilla {
class GeckoScreenOrientation final
: public java::GeckoScreenOrientation::Natives<GeckoScreenOrientation>
{
GeckoScreenOrientation() = delete;
public:
static void
OnOrientationChange(int16_t aOrientation, int16_t aAngle)
{
nsCOMPtr<nsIScreenManager> screenMgr =
do_GetService("@mozilla.org/gfx/screenmanager;1");
nsCOMPtr<nsIScreen> screen;
if (!screenMgr || NS_FAILED(screenMgr->GetPrimaryScreen(
getter_AddRefs(screen))) || !screen) {
return;
}
nsIntRect rect;
int32_t colorDepth, pixelDepth;
if (NS_FAILED(screen->GetRect(&rect.x, &rect.y,
&rect.width, &rect.height)) ||
NS_FAILED(screen->GetColorDepth(&colorDepth)) ||
NS_FAILED(screen->GetPixelDepth(&pixelDepth))) {
return;
}
hal::NotifyScreenConfigurationChange(hal::ScreenConfiguration(
rect, static_cast<dom::ScreenOrientationInternal>(aOrientation),
aAngle, colorDepth, pixelDepth));
}
};
} // namespace mozilla
#endif // GeckoScreenOrientation_h

View file

@ -0,0 +1,526 @@
// GENERATED CODE
// Generated by the Java program at /build/annotationProcessors at compile time
// from annotations on Java methods. To update, change the annotations on the
// corresponding Java methods and rerun the build. Manually updating this file
// will cause your build to fail.
#ifndef GeneratedJNINatives_h
#define GeneratedJNINatives_h
#include "GeneratedJNIWrappers.h"
#include "mozilla/jni/Natives.h"
namespace mozilla {
namespace java {
template<class Impl>
class AlarmReceiver::Natives : public mozilla::jni::NativeImpl<AlarmReceiver, Impl>
{
public:
static const JNINativeMethod methods[1];
};
template<class Impl>
const JNINativeMethod AlarmReceiver::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<AlarmReceiver::NotifyAlarmFired_t>(
mozilla::jni::NativeStub<AlarmReceiver::NotifyAlarmFired_t, Impl>
::template Wrap<&Impl::NotifyAlarmFired>)
};
template<class Impl>
class AndroidGamepadManager::Natives : public mozilla::jni::NativeImpl<AndroidGamepadManager, Impl>
{
public:
static const JNINativeMethod methods[3];
};
template<class Impl>
const JNINativeMethod AndroidGamepadManager::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<AndroidGamepadManager::OnAxisChange_t>(
mozilla::jni::NativeStub<AndroidGamepadManager::OnAxisChange_t, Impl>
::template Wrap<&Impl::OnAxisChange>),
mozilla::jni::MakeNativeMethod<AndroidGamepadManager::OnButtonChange_t>(
mozilla::jni::NativeStub<AndroidGamepadManager::OnButtonChange_t, Impl>
::template Wrap<&Impl::OnButtonChange>),
mozilla::jni::MakeNativeMethod<AndroidGamepadManager::OnGamepadChange_t>(
mozilla::jni::NativeStub<AndroidGamepadManager::OnGamepadChange_t, Impl>
::template Wrap<&Impl::OnGamepadChange>)
};
template<class Impl>
class GeckoAppShell::Natives : public mozilla::jni::NativeImpl<GeckoAppShell, Impl>
{
public:
static const JNINativeMethod methods[8];
};
template<class Impl>
const JNINativeMethod GeckoAppShell::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<GeckoAppShell::NotifyObservers_t>(
mozilla::jni::NativeStub<GeckoAppShell::NotifyObservers_t, Impl>
::template Wrap<&Impl::NotifyObservers>),
mozilla::jni::MakeNativeMethod<GeckoAppShell::NotifyAlertListener_t>(
mozilla::jni::NativeStub<GeckoAppShell::NotifyAlertListener_t, Impl>
::template Wrap<&Impl::NotifyAlertListener>),
mozilla::jni::MakeNativeMethod<GeckoAppShell::NotifyUriVisited_t>(
mozilla::jni::NativeStub<GeckoAppShell::NotifyUriVisited_t, Impl>
::template Wrap<&Impl::NotifyUriVisited>),
mozilla::jni::MakeNativeMethod<GeckoAppShell::OnFullScreenPluginHidden_t>(
mozilla::jni::NativeStub<GeckoAppShell::OnFullScreenPluginHidden_t, Impl>
::template Wrap<&Impl::OnFullScreenPluginHidden>),
mozilla::jni::MakeNativeMethod<GeckoAppShell::OnLocationChanged_t>(
mozilla::jni::NativeStub<GeckoAppShell::OnLocationChanged_t, Impl>
::template Wrap<&Impl::OnLocationChanged>),
mozilla::jni::MakeNativeMethod<GeckoAppShell::OnSensorChanged_t>(
mozilla::jni::NativeStub<GeckoAppShell::OnSensorChanged_t, Impl>
::template Wrap<&Impl::OnSensorChanged>),
mozilla::jni::MakeNativeMethod<GeckoAppShell::ReportJavaCrash_t>(
mozilla::jni::NativeStub<GeckoAppShell::ReportJavaCrash_t, Impl>
::template Wrap<&Impl::ReportJavaCrash>),
mozilla::jni::MakeNativeMethod<GeckoAppShell::SyncNotifyObservers_t>(
mozilla::jni::NativeStub<GeckoAppShell::SyncNotifyObservers_t, Impl>
::template Wrap<&Impl::SyncNotifyObservers>)
};
template<class Impl>
class GeckoAppShell::CameraCallback::Natives : public mozilla::jni::NativeImpl<CameraCallback, Impl>
{
public:
static const JNINativeMethod methods[1];
};
template<class Impl>
const JNINativeMethod GeckoAppShell::CameraCallback::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<GeckoAppShell::CameraCallback::OnFrameData_t>(
mozilla::jni::NativeStub<GeckoAppShell::CameraCallback::OnFrameData_t, Impl>
::template Wrap<&Impl::OnFrameData>)
};
template<class Impl>
class GeckoBatteryManager::Natives : public mozilla::jni::NativeImpl<GeckoBatteryManager, Impl>
{
public:
static const JNINativeMethod methods[1];
};
template<class Impl>
const JNINativeMethod GeckoBatteryManager::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<GeckoBatteryManager::OnBatteryChange_t>(
mozilla::jni::NativeStub<GeckoBatteryManager::OnBatteryChange_t, Impl>
::template Wrap<&Impl::OnBatteryChange>)
};
template<class Impl>
class GeckoEditable::Natives : public mozilla::jni::NativeImpl<GeckoEditable, Impl>
{
public:
static const JNINativeMethod methods[7];
};
template<class Impl>
const JNINativeMethod GeckoEditable::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<GeckoEditable::DisposeNative_t>(
mozilla::jni::NativeStub<GeckoEditable::DisposeNative_t, Impl>
::template Wrap<&Impl::DisposeNative>),
mozilla::jni::MakeNativeMethod<GeckoEditable::OnImeAddCompositionRange_t>(
mozilla::jni::NativeStub<GeckoEditable::OnImeAddCompositionRange_t, Impl>
::template Wrap<&Impl::OnImeAddCompositionRange>),
mozilla::jni::MakeNativeMethod<GeckoEditable::OnImeReplaceText_t>(
mozilla::jni::NativeStub<GeckoEditable::OnImeReplaceText_t, Impl>
::template Wrap<&Impl::OnImeReplaceText>),
mozilla::jni::MakeNativeMethod<GeckoEditable::OnImeRequestCursorUpdates_t>(
mozilla::jni::NativeStub<GeckoEditable::OnImeRequestCursorUpdates_t, Impl>
::template Wrap<&Impl::OnImeRequestCursorUpdates>),
mozilla::jni::MakeNativeMethod<GeckoEditable::OnImeSynchronize_t>(
mozilla::jni::NativeStub<GeckoEditable::OnImeSynchronize_t, Impl>
::template Wrap<&Impl::OnImeSynchronize>),
mozilla::jni::MakeNativeMethod<GeckoEditable::OnImeUpdateComposition_t>(
mozilla::jni::NativeStub<GeckoEditable::OnImeUpdateComposition_t, Impl>
::template Wrap<&Impl::OnImeUpdateComposition>),
mozilla::jni::MakeNativeMethod<GeckoEditable::OnKeyEvent_t>(
mozilla::jni::NativeStub<GeckoEditable::OnKeyEvent_t, Impl>
::template Wrap<&Impl::OnKeyEvent>)
};
template<class Impl>
class GeckoNetworkManager::Natives : public mozilla::jni::NativeImpl<GeckoNetworkManager, Impl>
{
public:
static const JNINativeMethod methods[2];
};
template<class Impl>
const JNINativeMethod GeckoNetworkManager::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<GeckoNetworkManager::OnConnectionChanged_t>(
mozilla::jni::NativeStub<GeckoNetworkManager::OnConnectionChanged_t, Impl>
::template Wrap<&Impl::OnConnectionChanged>),
mozilla::jni::MakeNativeMethod<GeckoNetworkManager::OnStatusChanged_t>(
mozilla::jni::NativeStub<GeckoNetworkManager::OnStatusChanged_t, Impl>
::template Wrap<&Impl::OnStatusChanged>)
};
template<class Impl>
class GeckoScreenOrientation::Natives : public mozilla::jni::NativeImpl<GeckoScreenOrientation, Impl>
{
public:
static const JNINativeMethod methods[1];
};
template<class Impl>
const JNINativeMethod GeckoScreenOrientation::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<GeckoScreenOrientation::OnOrientationChange_t>(
mozilla::jni::NativeStub<GeckoScreenOrientation::OnOrientationChange_t, Impl>
::template Wrap<&Impl::OnOrientationChange>)
};
template<class Impl>
class GeckoThread::Natives : public mozilla::jni::NativeImpl<GeckoThread, Impl>
{
public:
static const JNINativeMethod methods[6];
};
template<class Impl>
const JNINativeMethod GeckoThread::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<GeckoThread::CreateServices_t>(
mozilla::jni::NativeStub<GeckoThread::CreateServices_t, Impl>
::template Wrap<&Impl::CreateServices>),
mozilla::jni::MakeNativeMethod<GeckoThread::OnPause_t>(
mozilla::jni::NativeStub<GeckoThread::OnPause_t, Impl>
::template Wrap<&Impl::OnPause>),
mozilla::jni::MakeNativeMethod<GeckoThread::OnResume_t>(
mozilla::jni::NativeStub<GeckoThread::OnResume_t, Impl>
::template Wrap<&Impl::OnResume>),
mozilla::jni::MakeNativeMethod<GeckoThread::RunUiThreadCallback_t>(
mozilla::jni::NativeStub<GeckoThread::RunUiThreadCallback_t, Impl>
::template Wrap<&Impl::RunUiThreadCallback>),
mozilla::jni::MakeNativeMethod<GeckoThread::SpeculativeConnect_t>(
mozilla::jni::NativeStub<GeckoThread::SpeculativeConnect_t, Impl>
::template Wrap<&Impl::SpeculativeConnect>),
mozilla::jni::MakeNativeMethod<GeckoThread::WaitOnGecko_t>(
mozilla::jni::NativeStub<GeckoThread::WaitOnGecko_t, Impl>
::template Wrap<&Impl::WaitOnGecko>)
};
template<class Impl>
class GeckoView::Window::Natives : public mozilla::jni::NativeImpl<Window, Impl>
{
public:
static const JNINativeMethod methods[5];
};
template<class Impl>
const JNINativeMethod GeckoView::Window::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<GeckoView::Window::Close_t>(
mozilla::jni::NativeStub<GeckoView::Window::Close_t, Impl>
::template Wrap<&Impl::Close>),
mozilla::jni::MakeNativeMethod<GeckoView::Window::DisposeNative_t>(
mozilla::jni::NativeStub<GeckoView::Window::DisposeNative_t, Impl>
::template Wrap<&Impl::DisposeNative>),
mozilla::jni::MakeNativeMethod<GeckoView::Window::LoadUri_t>(
mozilla::jni::NativeStub<GeckoView::Window::LoadUri_t, Impl>
::template Wrap<&Impl::LoadUri>),
mozilla::jni::MakeNativeMethod<GeckoView::Window::Open_t>(
mozilla::jni::NativeStub<GeckoView::Window::Open_t, Impl>
::template Wrap<&Impl::Open>),
mozilla::jni::MakeNativeMethod<GeckoView::Window::Reattach_t>(
mozilla::jni::NativeStub<GeckoView::Window::Reattach_t, Impl>
::template Wrap<&Impl::Reattach>)
};
template<class Impl>
class PrefsHelper::Natives : public mozilla::jni::NativeImpl<PrefsHelper, Impl>
{
public:
static const JNINativeMethod methods[4];
};
template<class Impl>
const JNINativeMethod PrefsHelper::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<PrefsHelper::AddObserver_t>(
mozilla::jni::NativeStub<PrefsHelper::AddObserver_t, Impl>
::template Wrap<&Impl::AddObserver>),
mozilla::jni::MakeNativeMethod<PrefsHelper::GetPrefs_t>(
mozilla::jni::NativeStub<PrefsHelper::GetPrefs_t, Impl>
::template Wrap<&Impl::GetPrefs>),
mozilla::jni::MakeNativeMethod<PrefsHelper::RemoveObserver_t>(
mozilla::jni::NativeStub<PrefsHelper::RemoveObserver_t, Impl>
::template Wrap<&Impl::RemoveObserver>),
mozilla::jni::MakeNativeMethod<PrefsHelper::SetPref_t>(
mozilla::jni::NativeStub<PrefsHelper::SetPref_t, Impl>
::template Wrap<&Impl::SetPref>)
};
template<class Impl>
class SurfaceTextureListener::Natives : public mozilla::jni::NativeImpl<SurfaceTextureListener, Impl>
{
public:
static const JNINativeMethod methods[1];
};
template<class Impl>
const JNINativeMethod SurfaceTextureListener::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<SurfaceTextureListener::OnFrameAvailable_t>(
mozilla::jni::NativeStub<SurfaceTextureListener::OnFrameAvailable_t, Impl>
::template Wrap<&Impl::OnFrameAvailable>)
};
template<class Impl>
class LayerView::Compositor::Natives : public mozilla::jni::NativeImpl<Compositor, Impl>
{
public:
static const JNINativeMethod methods[7];
};
template<class Impl>
const JNINativeMethod LayerView::Compositor::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<LayerView::Compositor::AttachToJava_t>(
mozilla::jni::NativeStub<LayerView::Compositor::AttachToJava_t, Impl>
::template Wrap<&Impl::AttachToJava>),
mozilla::jni::MakeNativeMethod<LayerView::Compositor::CreateCompositor_t>(
mozilla::jni::NativeStub<LayerView::Compositor::CreateCompositor_t, Impl>
::template Wrap<&Impl::CreateCompositor>),
mozilla::jni::MakeNativeMethod<LayerView::Compositor::DisposeNative_t>(
mozilla::jni::NativeStub<LayerView::Compositor::DisposeNative_t, Impl>
::template Wrap<&Impl::DisposeNative>),
mozilla::jni::MakeNativeMethod<LayerView::Compositor::OnSizeChanged_t>(
mozilla::jni::NativeStub<LayerView::Compositor::OnSizeChanged_t, Impl>
::template Wrap<&Impl::OnSizeChanged>),
mozilla::jni::MakeNativeMethod<LayerView::Compositor::SyncInvalidateAndScheduleComposite_t>(
mozilla::jni::NativeStub<LayerView::Compositor::SyncInvalidateAndScheduleComposite_t, Impl>
::template Wrap<&Impl::SyncInvalidateAndScheduleComposite>),
mozilla::jni::MakeNativeMethod<LayerView::Compositor::SyncPauseCompositor_t>(
mozilla::jni::NativeStub<LayerView::Compositor::SyncPauseCompositor_t, Impl>
::template Wrap<&Impl::SyncPauseCompositor>),
mozilla::jni::MakeNativeMethod<LayerView::Compositor::SyncResumeResizeCompositor_t>(
mozilla::jni::NativeStub<LayerView::Compositor::SyncResumeResizeCompositor_t, Impl>
::template Wrap<&Impl::SyncResumeResizeCompositor>)
};
template<class Impl>
class NativePanZoomController::Natives : public mozilla::jni::NativeImpl<NativePanZoomController, Impl>
{
public:
static const JNINativeMethod methods[7];
};
template<class Impl>
const JNINativeMethod NativePanZoomController::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<NativePanZoomController::AdjustScrollForSurfaceShift_t>(
mozilla::jni::NativeStub<NativePanZoomController::AdjustScrollForSurfaceShift_t, Impl>
::template Wrap<&Impl::AdjustScrollForSurfaceShift>),
mozilla::jni::MakeNativeMethod<NativePanZoomController::DisposeNative_t>(
mozilla::jni::NativeStub<NativePanZoomController::DisposeNative_t, Impl>
::template Wrap<&Impl::DisposeNative>),
mozilla::jni::MakeNativeMethod<NativePanZoomController::HandleMotionEvent_t>(
mozilla::jni::NativeStub<NativePanZoomController::HandleMotionEvent_t, Impl>
::template Wrap<&Impl::HandleMotionEvent>),
mozilla::jni::MakeNativeMethod<NativePanZoomController::HandleMotionEventVelocity_t>(
mozilla::jni::NativeStub<NativePanZoomController::HandleMotionEventVelocity_t, Impl>
::template Wrap<&Impl::HandleMotionEventVelocity>),
mozilla::jni::MakeNativeMethod<NativePanZoomController::HandleMouseEvent_t>(
mozilla::jni::NativeStub<NativePanZoomController::HandleMouseEvent_t, Impl>
::template Wrap<&Impl::HandleMouseEvent>),
mozilla::jni::MakeNativeMethod<NativePanZoomController::HandleScrollEvent_t>(
mozilla::jni::NativeStub<NativePanZoomController::HandleScrollEvent_t, Impl>
::template Wrap<&Impl::HandleScrollEvent>),
mozilla::jni::MakeNativeMethod<NativePanZoomController::SetIsLongpressEnabled_t>(
mozilla::jni::NativeStub<NativePanZoomController::SetIsLongpressEnabled_t, Impl>
::template Wrap<&Impl::SetIsLongpressEnabled>)
};
template<class Impl>
class NativeJSContainer::Natives : public mozilla::jni::NativeImpl<NativeJSContainer, Impl>
{
public:
static const JNINativeMethod methods[2];
};
template<class Impl>
const JNINativeMethod NativeJSContainer::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<NativeJSContainer::Clone2_t>(
mozilla::jni::NativeStub<NativeJSContainer::Clone2_t, Impl>
::template Wrap<&Impl::Clone>),
mozilla::jni::MakeNativeMethod<NativeJSContainer::DisposeNative_t>(
mozilla::jni::NativeStub<NativeJSContainer::DisposeNative_t, Impl>
::template Wrap<&Impl::DisposeNative>)
};
template<class Impl>
class NativeJSObject::Natives : public mozilla::jni::NativeImpl<NativeJSObject, Impl>
{
public:
static const JNINativeMethod methods[27];
};
template<class Impl>
const JNINativeMethod NativeJSObject::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<NativeJSObject::GetBoolean_t>(
mozilla::jni::NativeStub<NativeJSObject::GetBoolean_t, Impl>
::template Wrap<&Impl::GetBoolean>),
mozilla::jni::MakeNativeMethod<NativeJSObject::GetBooleanArray_t>(
mozilla::jni::NativeStub<NativeJSObject::GetBooleanArray_t, Impl>
::template Wrap<&Impl::GetBooleanArray>),
mozilla::jni::MakeNativeMethod<NativeJSObject::GetBundle_t>(
mozilla::jni::NativeStub<NativeJSObject::GetBundle_t, Impl>
::template Wrap<&Impl::GetBundle>),
mozilla::jni::MakeNativeMethod<NativeJSObject::GetBundleArray_t>(
mozilla::jni::NativeStub<NativeJSObject::GetBundleArray_t, Impl>
::template Wrap<&Impl::GetBundleArray>),
mozilla::jni::MakeNativeMethod<NativeJSObject::GetDouble_t>(
mozilla::jni::NativeStub<NativeJSObject::GetDouble_t, Impl>
::template Wrap<&Impl::GetDouble>),
mozilla::jni::MakeNativeMethod<NativeJSObject::GetDoubleArray_t>(
mozilla::jni::NativeStub<NativeJSObject::GetDoubleArray_t, Impl>
::template Wrap<&Impl::GetDoubleArray>),
mozilla::jni::MakeNativeMethod<NativeJSObject::GetInt_t>(
mozilla::jni::NativeStub<NativeJSObject::GetInt_t, Impl>
::template Wrap<&Impl::GetInt>),
mozilla::jni::MakeNativeMethod<NativeJSObject::GetIntArray_t>(
mozilla::jni::NativeStub<NativeJSObject::GetIntArray_t, Impl>
::template Wrap<&Impl::GetIntArray>),
mozilla::jni::MakeNativeMethod<NativeJSObject::GetObject_t>(
mozilla::jni::NativeStub<NativeJSObject::GetObject_t, Impl>
::template Wrap<&Impl::GetObject>),
mozilla::jni::MakeNativeMethod<NativeJSObject::GetObjectArray_t>(
mozilla::jni::NativeStub<NativeJSObject::GetObjectArray_t, Impl>
::template Wrap<&Impl::GetObjectArray>),
mozilla::jni::MakeNativeMethod<NativeJSObject::GetString_t>(
mozilla::jni::NativeStub<NativeJSObject::GetString_t, Impl>
::template Wrap<&Impl::GetString>),
mozilla::jni::MakeNativeMethod<NativeJSObject::GetStringArray_t>(
mozilla::jni::NativeStub<NativeJSObject::GetStringArray_t, Impl>
::template Wrap<&Impl::GetStringArray>),
mozilla::jni::MakeNativeMethod<NativeJSObject::Has_t>(
mozilla::jni::NativeStub<NativeJSObject::Has_t, Impl>
::template Wrap<&Impl::Has>),
mozilla::jni::MakeNativeMethod<NativeJSObject::OptBoolean_t>(
mozilla::jni::NativeStub<NativeJSObject::OptBoolean_t, Impl>
::template Wrap<&Impl::OptBoolean>),
mozilla::jni::MakeNativeMethod<NativeJSObject::OptBooleanArray_t>(
mozilla::jni::NativeStub<NativeJSObject::OptBooleanArray_t, Impl>
::template Wrap<&Impl::OptBooleanArray>),
mozilla::jni::MakeNativeMethod<NativeJSObject::OptBundle_t>(
mozilla::jni::NativeStub<NativeJSObject::OptBundle_t, Impl>
::template Wrap<&Impl::OptBundle>),
mozilla::jni::MakeNativeMethod<NativeJSObject::OptBundleArray_t>(
mozilla::jni::NativeStub<NativeJSObject::OptBundleArray_t, Impl>
::template Wrap<&Impl::OptBundleArray>),
mozilla::jni::MakeNativeMethod<NativeJSObject::OptDouble_t>(
mozilla::jni::NativeStub<NativeJSObject::OptDouble_t, Impl>
::template Wrap<&Impl::OptDouble>),
mozilla::jni::MakeNativeMethod<NativeJSObject::OptDoubleArray_t>(
mozilla::jni::NativeStub<NativeJSObject::OptDoubleArray_t, Impl>
::template Wrap<&Impl::OptDoubleArray>),
mozilla::jni::MakeNativeMethod<NativeJSObject::OptInt_t>(
mozilla::jni::NativeStub<NativeJSObject::OptInt_t, Impl>
::template Wrap<&Impl::OptInt>),
mozilla::jni::MakeNativeMethod<NativeJSObject::OptIntArray_t>(
mozilla::jni::NativeStub<NativeJSObject::OptIntArray_t, Impl>
::template Wrap<&Impl::OptIntArray>),
mozilla::jni::MakeNativeMethod<NativeJSObject::OptObject_t>(
mozilla::jni::NativeStub<NativeJSObject::OptObject_t, Impl>
::template Wrap<&Impl::OptObject>),
mozilla::jni::MakeNativeMethod<NativeJSObject::OptObjectArray_t>(
mozilla::jni::NativeStub<NativeJSObject::OptObjectArray_t, Impl>
::template Wrap<&Impl::OptObjectArray>),
mozilla::jni::MakeNativeMethod<NativeJSObject::OptString_t>(
mozilla::jni::NativeStub<NativeJSObject::OptString_t, Impl>
::template Wrap<&Impl::OptString>),
mozilla::jni::MakeNativeMethod<NativeJSObject::OptStringArray_t>(
mozilla::jni::NativeStub<NativeJSObject::OptStringArray_t, Impl>
::template Wrap<&Impl::OptStringArray>),
mozilla::jni::MakeNativeMethod<NativeJSObject::ToBundle_t>(
mozilla::jni::NativeStub<NativeJSObject::ToBundle_t, Impl>
::template Wrap<&Impl::ToBundle>),
mozilla::jni::MakeNativeMethod<NativeJSObject::ToString_t>(
mozilla::jni::NativeStub<NativeJSObject::ToString_t, Impl>
::template Wrap<&Impl::ToString>)
};
} /* java */
} /* mozilla */
#endif // GeneratedJNINatives_h

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

621
widget/android/GfxInfo.cpp Normal file
View file

@ -0,0 +1,621 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "GfxInfo.h"
#include "GLContext.h"
#include "GLContextProvider.h"
#include "nsUnicharUtils.h"
#include "prenv.h"
#include "prprf.h"
#include "nsHashKeys.h"
#include "nsVersionComparator.h"
#include "AndroidBridge.h"
#include "nsIWindowWatcher.h"
#include "nsServiceManagerUtils.h"
#if defined(MOZ_CRASHREPORTER)
#include "nsExceptionHandler.h"
#include "nsICrashReporter.h"
#define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
#endif
namespace mozilla {
namespace widget {
class GfxInfo::GLStrings
{
nsCString mVendor;
nsCString mRenderer;
nsCString mVersion;
bool mReady;
public:
GLStrings()
: mReady(false)
{}
const nsCString& Vendor() {
EnsureInitialized();
return mVendor;
}
// This spoofed value wins, even if the environment variable
// MOZ_GFX_SPOOF_GL_VENDOR was set.
void SpoofVendor(const nsCString& s) {
mVendor = s;
}
const nsCString& Renderer() {
EnsureInitialized();
return mRenderer;
}
// This spoofed value wins, even if the environment variable
// MOZ_GFX_SPOOF_GL_RENDERER was set.
void SpoofRenderer(const nsCString& s) {
mRenderer = s;
}
const nsCString& Version() {
EnsureInitialized();
return mVersion;
}
// This spoofed value wins, even if the environment variable
// MOZ_GFX_SPOOF_GL_VERSION was set.
void SpoofVersion(const nsCString& s) {
mVersion = s;
}
void EnsureInitialized() {
if (mReady) {
return;
}
RefPtr<gl::GLContext> gl;
nsCString discardFailureId;
gl = gl::GLContextProvider::CreateHeadless(gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE,
&discardFailureId);
if (!gl) {
// Setting mReady to true here means that we won't retry. Everything will
// remain blacklisted forever. Ideally, we would like to update that once
// any GLContext is successfully created, like the compositor's GLContext.
mReady = true;
return;
}
gl->MakeCurrent();
if (mVendor.IsEmpty()) {
const char *spoofedVendor = PR_GetEnv("MOZ_GFX_SPOOF_GL_VENDOR");
if (spoofedVendor) {
mVendor.Assign(spoofedVendor);
} else {
mVendor.Assign((const char*)gl->fGetString(LOCAL_GL_VENDOR));
}
}
if (mRenderer.IsEmpty()) {
const char *spoofedRenderer = PR_GetEnv("MOZ_GFX_SPOOF_GL_RENDERER");
if (spoofedRenderer) {
mRenderer.Assign(spoofedRenderer);
} else {
mRenderer.Assign((const char*)gl->fGetString(LOCAL_GL_RENDERER));
}
}
if (mVersion.IsEmpty()) {
const char *spoofedVersion = PR_GetEnv("MOZ_GFX_SPOOF_GL_VERSION");
if (spoofedVersion) {
mVersion.Assign(spoofedVersion);
} else {
mVersion.Assign((const char*)gl->fGetString(LOCAL_GL_VERSION));
}
}
mReady = true;
}
};
#ifdef DEBUG
NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
#endif
GfxInfo::GfxInfo()
: mInitialized(false)
, mGLStrings(new GLStrings)
, mOSVersionInteger(0)
, mSDKVersion(0)
{
}
GfxInfo::~GfxInfo()
{
}
/* GetD2DEnabled and GetDwriteEnabled shouldn't be called until after gfxPlatform initialization
* has occurred because they depend on it for information. (See bug 591561) */
nsresult
GfxInfo::GetD2DEnabled(bool *aEnabled)
{
return NS_ERROR_FAILURE;
}
nsresult
GfxInfo::GetDWriteEnabled(bool *aEnabled)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetDWriteVersion(nsAString & aDwriteVersion)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetCleartypeParameters(nsAString & aCleartypeParams)
{
return NS_ERROR_FAILURE;
}
void
GfxInfo::EnsureInitialized()
{
if (mInitialized)
return;
if (!mozilla::AndroidBridge::Bridge()) {
gfxWarning() << "AndroidBridge missing during initialization";
return;
}
if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "MODEL", mModel)) {
mAdapterDescription.AppendPrintf("Model: %s", NS_LossyConvertUTF16toASCII(mModel).get());
}
if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "PRODUCT", mProduct)) {
mAdapterDescription.AppendPrintf(", Product: %s", NS_LossyConvertUTF16toASCII(mProduct).get());
}
if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "MANUFACTURER", mManufacturer)) {
mAdapterDescription.AppendPrintf(", Manufacturer: %s", NS_LossyConvertUTF16toASCII(mManufacturer).get());
}
if (mozilla::AndroidBridge::Bridge()->GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &mSDKVersion)) {
// the HARDWARE field isn't available on Android SDK < 8, but we require 9+ anyway.
MOZ_ASSERT(mSDKVersion >= 8);
if (mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "HARDWARE", mHardware)) {
mAdapterDescription.AppendPrintf(", Hardware: %s", NS_LossyConvertUTF16toASCII(mHardware).get());
}
} else {
mSDKVersion = 0;
}
nsString release;
mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build$VERSION", "RELEASE", release);
mOSVersion = NS_LossyConvertUTF16toASCII(release);
mOSVersionInteger = 0;
char a[5], b[5], c[5], d[5];
SplitDriverVersion(mOSVersion.get(), a, b, c, d);
uint8_t na = atoi(a);
uint8_t nb = atoi(b);
uint8_t nc = atoi(c);
uint8_t nd = atoi(d);
mOSVersionInteger = (uint32_t(na) << 24) |
(uint32_t(nb) << 16) |
(uint32_t(nc) << 8) |
uint32_t(nd);
mAdapterDescription.AppendPrintf(", OpenGL: %s -- %s -- %s",
mGLStrings->Vendor().get(),
mGLStrings->Renderer().get(),
mGLStrings->Version().get());
AddCrashReportAnnotations();
mInitialized = true;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription)
{
EnsureInitialized();
aAdapterDescription = NS_ConvertASCIItoUTF16(mAdapterDescription);
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription)
{
EnsureInitialized();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM)
{
EnsureInitialized();
aAdapterRAM.Truncate();
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM)
{
EnsureInitialized();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver)
{
EnsureInitialized();
aAdapterDriver.Truncate();
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver)
{
EnsureInitialized();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion)
{
EnsureInitialized();
aAdapterDriverVersion = NS_ConvertASCIItoUTF16(mGLStrings->Version());
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion)
{
EnsureInitialized();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate)
{
EnsureInitialized();
aAdapterDriverDate.Truncate();
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate)
{
EnsureInitialized();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterVendorID(nsAString & aAdapterVendorID)
{
EnsureInitialized();
aAdapterVendorID = NS_ConvertASCIItoUTF16(mGLStrings->Vendor());
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterVendorID2(nsAString & aAdapterVendorID)
{
EnsureInitialized();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDeviceID(nsAString & aAdapterDeviceID)
{
EnsureInitialized();
aAdapterDeviceID = NS_ConvertASCIItoUTF16(mGLStrings->Renderer());
return NS_OK;
}
NS_IMETHODIMP
GfxInfo::GetAdapterDeviceID2(nsAString & aAdapterDeviceID)
{
EnsureInitialized();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterSubsysID(nsAString & aAdapterSubsysID)
{
EnsureInitialized();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetAdapterSubsysID2(nsAString & aAdapterSubsysID)
{
EnsureInitialized();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active)
{
EnsureInitialized();
return NS_ERROR_FAILURE;
}
void
GfxInfo::AddCrashReportAnnotations()
{
#if defined(MOZ_CRASHREPORTER)
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterVendorID"),
mGLStrings->Vendor());
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDeviceID"),
mGLStrings->Renderer());
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDriverVersion"),
mGLStrings->Version());
/* Add an App Note for now so that we get the data immediately. These
* can go away after we store the above in the socorro db */
nsAutoCString note;
note.AppendPrintf("AdapterDescription: '%s'\n", mAdapterDescription.get());
CrashReporter::AppendAppNotesToCrashReport(note);
#endif
}
const nsTArray<GfxDriverInfo>&
GfxInfo::GetGfxDriverInfo()
{
if (mDriverInfo->IsEmpty()) {
APPEND_TO_DRIVER_BLOCKLIST2(OperatingSystem::Android,
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorAll), GfxDriverInfo::allDevices,
nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_STATUS_OK,
DRIVER_COMPARISON_IGNORED, GfxDriverInfo::allDriverVersions,
"FEATURE_OK_FORCE_OPENGL" );
}
return *mDriverInfo;
}
nsresult
GfxInfo::GetFeatureStatusImpl(int32_t aFeature,
int32_t *aStatus,
nsAString &aSuggestedDriverVersion,
const nsTArray<GfxDriverInfo>& aDriverInfo,
nsACString &aFailureId,
OperatingSystem* aOS /* = nullptr */)
{
NS_ENSURE_ARG_POINTER(aStatus);
aSuggestedDriverVersion.SetIsVoid(true);
*aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
OperatingSystem os = mOS;
if (aOS)
*aOS = os;
// OpenGL layers are never blacklisted on Android.
// This early return is so we avoid potentially slow
// GLStrings initialization on startup when we initialize GL layers.
if (aFeature == nsIGfxInfo::FEATURE_OPENGL_LAYERS) {
*aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
return NS_OK;
}
EnsureInitialized();
if (mGLStrings->Vendor().IsEmpty() || mGLStrings->Renderer().IsEmpty()) {
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
return NS_OK;
}
// Don't evaluate special cases when evaluating the downloaded blocklist.
if (aDriverInfo.IsEmpty()) {
if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
if (mSDKVersion < 11) {
// It's slower than software due to not having a compositing fast path
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
aFailureId = "FEATURE_FAILURE_CANVAS_2D_SDK";
} else if (mGLStrings->Renderer().Find("Vivante GC1000") != -1) {
// Blocklist Vivante GC1000. See bug 1248183.
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
aFailureId = "FEATURE_FAILED_CANVAS_2D_HW";
} else {
*aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
}
return NS_OK;
}
if (aFeature == FEATURE_WEBGL_OPENGL) {
if (mGLStrings->Renderer().Find("Adreno 200") != -1 ||
mGLStrings->Renderer().Find("Adreno 205") != -1)
{
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
aFailureId = "FEATURE_FAILURE_ADRENO_20x";
return NS_OK;
}
if (mHardware.EqualsLiteral("ville")) {
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
aFailureId = "FEATURE_FAILURE_VILLE";
return NS_OK;
}
}
if (aFeature == FEATURE_STAGEFRIGHT) {
NS_LossyConvertUTF16toASCII cManufacturer(mManufacturer);
NS_LossyConvertUTF16toASCII cModel(mModel);
NS_LossyConvertUTF16toASCII cHardware(mHardware);
if (cHardware.EqualsLiteral("antares") ||
cHardware.EqualsLiteral("harmony") ||
cHardware.EqualsLiteral("picasso") ||
cHardware.EqualsLiteral("picasso_e") ||
cHardware.EqualsLiteral("ventana") ||
cHardware.EqualsLiteral("rk30board"))
{
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
aFailureId = "FEATURE_FAILURE_STAGE_HW";
return NS_OK;
}
if (CompareVersions(mOSVersion.get(), "4.1.0") < 0)
{
// Whitelist:
// All Samsung ICS devices, except for:
// Samsung SGH-I717 (Bug 845729)
// Samsung SGH-I727 (Bug 845729)
// Samsung SGH-I757 (Bug 845729)
// All Galaxy nexus ICS devices
// Sony Xperia Ion (LT28) ICS devices
bool isWhitelisted =
cModel.Equals("LT28h", nsCaseInsensitiveCStringComparator()) ||
cManufacturer.Equals("samsung", nsCaseInsensitiveCStringComparator()) ||
cModel.Equals("galaxy nexus", nsCaseInsensitiveCStringComparator()); // some Galaxy Nexus have manufacturer=amazon
if (cModel.Find("SGH-I717", true) != -1 ||
cModel.Find("SGH-I727", true) != -1 ||
cModel.Find("SGH-I757", true) != -1)
{
isWhitelisted = false;
}
if (!isWhitelisted) {
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
aFailureId = "FEATURE_FAILURE_4_1_HW";
return NS_OK;
}
}
else if (CompareVersions(mOSVersion.get(), "4.2.0") < 0)
{
// Whitelist:
// All JB phones except for those in blocklist below
// Blocklist:
// Samsung devices from bug 812881 and 853522.
// Motorola XT890 from bug 882342.
bool isBlocklisted =
cModel.Find("GT-P3100", true) != -1 ||
cModel.Find("GT-P3110", true) != -1 ||
cModel.Find("GT-P3113", true) != -1 ||
cModel.Find("GT-P5100", true) != -1 ||
cModel.Find("GT-P5110", true) != -1 ||
cModel.Find("GT-P5113", true) != -1 ||
cModel.Find("XT890", true) != -1;
if (isBlocklisted) {
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
aFailureId = "FEATURE_FAILURE_4_2_HW";
return NS_OK;
}
}
else if (CompareVersions(mOSVersion.get(), "4.3.0") < 0)
{
// Blocklist all Sony devices
if (cManufacturer.Find("Sony", true) != -1) {
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
aFailureId = "FEATURE_FAILURE_4_3_SONY";
return NS_OK;
}
}
}
if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_ENCODE) {
if (mozilla::AndroidBridge::Bridge()) {
*aStatus = mozilla::AndroidBridge::Bridge()->GetHWEncoderCapability() ? nsIGfxInfo::FEATURE_STATUS_OK : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
aFailureId = "FEATURE_FAILURE_WEBRTC_ENCODE";
return NS_OK;
}
}
if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_DECODE) {
if (mozilla::AndroidBridge::Bridge()) {
*aStatus = mozilla::AndroidBridge::Bridge()->GetHWDecoderCapability() ? nsIGfxInfo::FEATURE_STATUS_OK : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
aFailureId = "FEATURE_FAILURE_WEBRTC_DECODE";
return NS_OK;
}
}
if (aFeature == FEATURE_VP8_HW_DECODE || aFeature == FEATURE_VP9_HW_DECODE) {
NS_LossyConvertUTF16toASCII model(mModel);
bool isBlocked =
// GIFV crash, see bug 1232911.
model.Equals("GT-N8013", nsCaseInsensitiveCStringComparator());
if (isBlocked) {
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
aFailureId = "FEATURE_FAILURE_VPx";
} else {
*aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
}
return NS_OK;
}
}
return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
}
#ifdef DEBUG
// Implement nsIGfxInfoDebug
NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString & aVendorID)
{
mGLStrings->SpoofVendor(NS_LossyConvertUTF16toASCII(aVendorID));
return NS_OK;
}
NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString & aDeviceID)
{
mGLStrings->SpoofRenderer(NS_LossyConvertUTF16toASCII(aDeviceID));
return NS_OK;
}
NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString & aDriverVersion)
{
mGLStrings->SpoofVersion(NS_LossyConvertUTF16toASCII(aDriverVersion));
return NS_OK;
}
NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion)
{
EnsureInitialized();
mOSVersion = aVersion;
return NS_OK;
}
#endif
nsString GfxInfo::Model()
{
EnsureInitialized();
return mModel;
}
nsString GfxInfo::Hardware()
{
EnsureInitialized();
return mHardware;
}
nsString GfxInfo::Product()
{
EnsureInitialized();
return mProduct;
}
nsString GfxInfo::Manufacturer()
{
EnsureInitialized();
return mManufacturer;
}
uint32_t GfxInfo::OperatingSystemVersion()
{
EnsureInitialized();
return mOSVersionInteger;
}
}
}

102
widget/android/GfxInfo.h Normal file
View file

@ -0,0 +1,102 @@
/* vim: se cin sw=2 ts=2 et : */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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/. */
#ifndef __mozilla_widget_GfxInfo_h__
#define __mozilla_widget_GfxInfo_h__
#include "GfxInfoBase.h"
#include "GfxDriverInfo.h"
#include "nsString.h"
#include "mozilla/UniquePtr.h"
namespace mozilla {
namespace widget {
class GfxInfo : public GfxInfoBase
{
private:
~GfxInfo();
public:
GfxInfo();
// We only declare the subset of nsIGfxInfo that we actually implement. The
// rest is brought forward from GfxInfoBase.
NS_IMETHOD GetD2DEnabled(bool *aD2DEnabled) override;
NS_IMETHOD GetDWriteEnabled(bool *aDWriteEnabled) override;
NS_IMETHOD GetDWriteVersion(nsAString & aDwriteVersion) override;
NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams) override;
NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription) override;
NS_IMETHOD GetAdapterDriver(nsAString & aAdapterDriver) override;
NS_IMETHOD GetAdapterVendorID(nsAString & aAdapterVendorID) override;
NS_IMETHOD GetAdapterDeviceID(nsAString & aAdapterDeviceID) override;
NS_IMETHOD GetAdapterSubsysID(nsAString & aAdapterSubsysID) override;
NS_IMETHOD GetAdapterRAM(nsAString & aAdapterRAM) override;
NS_IMETHOD GetAdapterDriverVersion(nsAString & aAdapterDriverVersion) override;
NS_IMETHOD GetAdapterDriverDate(nsAString & aAdapterDriverDate) override;
NS_IMETHOD GetAdapterDescription2(nsAString & aAdapterDescription) override;
NS_IMETHOD GetAdapterDriver2(nsAString & aAdapterDriver) override;
NS_IMETHOD GetAdapterVendorID2(nsAString & aAdapterVendorID) override;
NS_IMETHOD GetAdapterDeviceID2(nsAString & aAdapterDeviceID) override;
NS_IMETHOD GetAdapterSubsysID2(nsAString & aAdapterSubsysID) override;
NS_IMETHOD GetAdapterRAM2(nsAString & aAdapterRAM) override;
NS_IMETHOD GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion) override;
NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate) override;
NS_IMETHOD GetIsGPU2Active(bool *aIsGPU2Active) override;
using GfxInfoBase::GetFeatureStatus;
using GfxInfoBase::GetFeatureSuggestedDriverVersion;
using GfxInfoBase::GetWebGLParameter;
void EnsureInitialized();
virtual nsString Model() override;
virtual nsString Hardware() override;
virtual nsString Product() override;
virtual nsString Manufacturer() override;
#ifdef DEBUG
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIGFXINFODEBUG
#endif
virtual uint32_t OperatingSystemVersion() override;
protected:
virtual nsresult GetFeatureStatusImpl(int32_t aFeature,
int32_t *aStatus,
nsAString & aSuggestedDriverVersion,
const nsTArray<GfxDriverInfo>& aDriverInfo,
nsACString &aFailureId,
OperatingSystem* aOS = nullptr) override;
virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo() override;
private:
void AddCrashReportAnnotations();
bool mInitialized;
class GLStrings;
UniquePtr<GLStrings> mGLStrings;
nsCString mAdapterDescription;
OperatingSystem mOS;
nsString mModel, mHardware, mManufacturer, mProduct;
nsCString mOSVersion;
uint32_t mOSVersionInteger;
int32_t mSDKVersion;
};
} // namespace widget
} // namespace mozilla
#endif /* __mozilla_widget_GfxInfo_h__ */

View file

@ -0,0 +1,881 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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 "NativeJSContainer.h"
#include <jni.h>
#include "Bundle.h"
#include "GeneratedJNINatives.h"
#include "MainThreadUtils.h"
#include "jsapi.h"
#include "nsJSUtils.h"
#include <mozilla/Vector.h>
#include <mozilla/jni/Accessors.h>
#include <mozilla/jni/Refs.h>
#include <mozilla/jni/Utils.h>
/**
* NativeJSContainer.cpp implements the native methods in both
* NativeJSContainer and NativeJSObject, using JSAPI to retrieve values from a
* JSObject and using JNI to return those values to Java code.
*/
namespace mozilla {
namespace widget {
namespace {
bool CheckThread()
{
if (!NS_IsMainThread()) {
jni::ThrowException("java/lang/IllegalThreadStateException",
"Not on Gecko thread");
return false;
}
return true;
}
template<class C, typename T> bool
CheckJNIArgument(const jni::Ref<C, T>& arg)
{
if (!arg) {
jni::ThrowException("java/lang/IllegalArgumentException",
"Null argument");
}
return !!arg;
}
nsresult
CheckSDKCall(nsresult rv)
{
if (NS_FAILED(rv)) {
jni::ThrowException("java/lang/UnsupportedOperationException",
"SDK JNI call failed");
}
return rv;
}
// Convert a JNI string to a char16_t string that JSAPI expects.
class JSJNIString final
{
JNIEnv* const mEnv;
jni::String::Param mJNIString;
const char16_t* const mJSString;
public:
JSJNIString(JNIEnv* env, jni::String::Param str)
: mEnv(env)
, mJNIString(str)
, mJSString(!str ? nullptr : reinterpret_cast<const char16_t*>(
mEnv->GetStringChars(str.Get(), nullptr)))
{}
~JSJNIString() {
if (mJNIString) {
mEnv->ReleaseStringChars(mJNIString.Get(),
reinterpret_cast<const jchar*>(mJSString));
}
}
operator const char16_t*() const {
return mJSString;
}
size_t Length() const {
return static_cast<size_t>(mEnv->GetStringLength(mJNIString.Get()));
}
};
} // namepsace
class NativeJSContainerImpl final
: public NativeJSObject::Natives<NativeJSContainerImpl>
, public NativeJSContainer::Natives<NativeJSContainerImpl>
{
typedef NativeJSContainerImpl Self;
typedef NativeJSContainer::Natives<NativeJSContainerImpl> ContainerBase;
typedef NativeJSObject::Natives<NativeJSContainerImpl> ObjectBase;
typedef JS::PersistentRooted<JSObject*> PersistentObject;
JNIEnv* const mEnv;
// Context that the object is valid in
JSContext* const mJSContext;
// Root JS object
PersistentObject mJSObject;
// Children objects
Vector<NativeJSObject::GlobalRef, 0> mChildren;
bool CheckObject() const
{
if (!mJSObject) {
jni::ThrowException("java/lang/NullPointerException",
"Null JSObject");
}
return !!mJSObject;
}
bool CheckJSCall(bool result) const
{
if (!result) {
JS_ClearPendingException(mJSContext);
jni::ThrowException("java/lang/UnsupportedOperationException",
"JSAPI call failed");
}
return result;
}
// Check that a JS Value contains a particular property type as indicaed by
// the property's InValue method (e.g. StringProperty::InValue).
bool CheckProperty(bool (Self::*InValue)(JS::HandleValue) const,
JS::HandleValue val) const
{
if (!(this->*InValue)(val)) {
// XXX this can happen when converting a double array inside a
// Bundle, because double arrays can be misidentified as an int
// array. The workaround is to add a dummy first element to the
// array that is a floating point value, i.e. [0.5, ...].
jni::ThrowException(
"org/mozilla/gecko/util/NativeJSObject$InvalidPropertyException",
"Property type mismatch");
return false;
}
return true;
}
// Primitive properties
template<bool (JS::Value::*IsType)() const> bool
PrimitiveInValue(JS::HandleValue val) const
{
return (static_cast<const JS::Value&>(val).*IsType)();
}
template<typename U, U (JS::Value::*ToType)() const> U
PrimitiveFromValue(JS::HandleValue val) const
{
return (static_cast<const JS::Value&>(val).*ToType)();
}
template<class Prop> typename Prop::NativeArray
PrimitiveNewArray(JS::HandleObject array, size_t length) const
{
typedef typename Prop::JNIType JNIType;
// Fill up a temporary buffer for our array, then use
// JNIEnv::Set*ArrayRegion to fill out array in one go.
UniquePtr<JNIType[]> buffer = MakeUnique<JNIType[]>(length);
for (size_t i = 0; i < length; i++) {
JS::RootedValue elem(mJSContext);
if (!CheckJSCall(JS_GetElement(mJSContext, array, i, &elem)) ||
!CheckProperty(Prop::InValue, elem)) {
return nullptr;
}
buffer[i] = JNIType((this->*Prop::FromValue)(elem));
}
auto jarray = Prop::NativeArray::Adopt(
mEnv, (mEnv->*Prop::NewJNIArray)(length));
if (!jarray) {
return nullptr;
}
(mEnv->*Prop::SetJNIArrayRegion)(
jarray.Get(), 0, length, buffer.get());
if (mEnv->ExceptionCheck()) {
return nullptr;
}
return jarray;
}
template<typename U, typename UA, typename V, typename VA,
bool (JS::Value::*IsType)() const,
U (JS::Value::*ToType)() const,
VA (JNIEnv::*NewArray_)(jsize),
void (JNIEnv::*SetArrayRegion_)(VA, jsize, jsize, const V*)>
struct PrimitiveProperty
{
// C++ type for a primitive property (e.g. bool)
typedef U NativeType;
// C++ type for the fallback value used in opt* methods
typedef U NativeFallback;
// Type for an array of the primitive type (e.g. BooleanArray::LocalRef)
typedef typename UA::LocalRef NativeArray;
// Type for the fallback value used in opt*Array methods
typedef const typename UA::Ref ArrayFallback;
// JNI type (e.g. jboolean)
typedef V JNIType;
// JNIEnv function to create a new JNI array of the primiive type
typedef decltype(NewArray_) NewJNIArray_t;
static constexpr NewJNIArray_t NewJNIArray = NewArray_;
// JNIEnv function to fill a JNI array of the primiive type
typedef decltype(SetArrayRegion_) SetJNIArrayRegion_t;
static constexpr SetJNIArrayRegion_t SetJNIArrayRegion = SetArrayRegion_;
// Function to determine if a JS Value contains the primitive type
typedef decltype(&Self::PrimitiveInValue<IsType>) InValue_t;
static constexpr InValue_t InValue = &Self::PrimitiveInValue<IsType>;
// Function to convert a JS Value to the primitive type
typedef decltype(&Self::PrimitiveFromValue<U, ToType>) FromValue_t;
static constexpr FromValue_t FromValue
= &Self::PrimitiveFromValue<U, ToType>;
// Function to convert a JS array to a JNI array
typedef decltype(&Self::PrimitiveNewArray<PrimitiveProperty>) NewArray_t;
static constexpr NewArray_t NewArray
= &Self::PrimitiveNewArray<PrimitiveProperty>;
};
// String properties
bool StringInValue(JS::HandleValue val) const
{
return val.isString();
}
jni::String::LocalRef
StringFromValue(const JS::HandleString str) const
{
nsAutoJSString autoStr;
if (!CheckJSCall(autoStr.init(mJSContext, str))) {
return nullptr;
}
// StringParam can automatically convert a nsString to jstring.
return jni::StringParam(autoStr, mEnv);
}
jni::String::LocalRef
StringFromValue(JS::HandleValue val)
{
const JS::RootedString str(mJSContext, val.toString());
return StringFromValue(str);
}
// Bundle properties
sdk::Bundle::LocalRef
BundleFromValue(const JS::HandleObject obj)
{
JS::Rooted<JS::IdVector> ids(mJSContext, JS::IdVector(mJSContext));
if (!CheckJSCall(JS_Enumerate(mJSContext, obj, &ids))) {
return nullptr;
}
const size_t length = ids.length();
sdk::Bundle::LocalRef newBundle(mEnv);
NS_ENSURE_SUCCESS(CheckSDKCall(
sdk::Bundle::New(length, &newBundle)), nullptr);
// Iterate through each property of the JS object. For each property,
// determine its type from a list of supported types, and convert that
// proeprty to the supported type.
for (size_t i = 0; i < ids.length(); i++) {
const JS::RootedId id(mJSContext, ids[i]);
JS::RootedValue idVal(mJSContext);
if (!CheckJSCall(JS_IdToValue(mJSContext, id, &idVal))) {
return nullptr;
}
const JS::RootedString idStr(mJSContext,
JS::ToString(mJSContext, idVal));
if (!CheckJSCall(!!idStr)) {
return nullptr;
}
jni::String::LocalRef name = StringFromValue(idStr);
JS::RootedValue val(mJSContext);
if (!name ||
!CheckJSCall(JS_GetPropertyById(mJSContext, obj, id, &val))) {
return nullptr;
}
#define PUT_IN_BUNDLE_IF_TYPE_IS(TYPE) \
if ((this->*TYPE##Property::InValue)(val)) { \
auto jval = (this->*TYPE##Property::FromValue)(val); \
if (mEnv->ExceptionCheck()) { \
return nullptr; \
} \
NS_ENSURE_SUCCESS(CheckSDKCall( \
newBundle->Put##TYPE(name, jval)), nullptr); \
continue; \
} \
((void) 0) // Accommodate trailing semicolon.
// Scalar values are faster to check, so check them first.
PUT_IN_BUNDLE_IF_TYPE_IS(Boolean);
// Int can be casted to double, so check int first.
PUT_IN_BUNDLE_IF_TYPE_IS(Int);
PUT_IN_BUNDLE_IF_TYPE_IS(Double);
PUT_IN_BUNDLE_IF_TYPE_IS(String);
// There's no "putObject", so don't check ObjectProperty
// Check for array types if scalar checks all failed.
// XXX empty arrays are treated as boolean arrays. Workaround is
// to always have a dummy element to create a non-empty array.
PUT_IN_BUNDLE_IF_TYPE_IS(BooleanArray);
// XXX because we only check the first element of an array,
// a double array can potentially be seen as an int array.
// When that happens, the Bundle conversion will fail.
PUT_IN_BUNDLE_IF_TYPE_IS(IntArray);
PUT_IN_BUNDLE_IF_TYPE_IS(DoubleArray);
PUT_IN_BUNDLE_IF_TYPE_IS(StringArray);
// There's no "putObjectArray", so don't check ObjectArrayProperty
// There's no "putBundleArray", so don't check BundleArrayProperty
// Use Bundle as the default catch-all for objects
PUT_IN_BUNDLE_IF_TYPE_IS(Bundle);
#undef PUT_IN_BUNDLE_IF_TYPE_IS
// We tried all supported types; just bail.
jni::ThrowException("java/lang/UnsupportedOperationException",
"Unsupported property type");
return nullptr;
}
return jni::Object::LocalRef::Adopt(newBundle.Env(),
newBundle.Forget());
}
sdk::Bundle::LocalRef
BundleFromValue(JS::HandleValue val)
{
if (val.isNull()) {
return nullptr;
}
JS::RootedObject object(mJSContext, &val.toObject());
return BundleFromValue(object);
}
// Object properties
bool ObjectInValue(JS::HandleValue val) const
{
return val.isObjectOrNull();
}
NativeJSObject::LocalRef
ObjectFromValue(JS::HandleValue val)
{
if (val.isNull()) {
return nullptr;
}
JS::RootedObject object(mJSContext, &val.toObject());
return CreateChild(object);
}
template<class Prop> typename Prop::NativeArray
ObjectNewArray(JS::HandleObject array, size_t length)
{
auto jarray = Prop::NativeArray::Adopt(mEnv, mEnv->NewObjectArray(
length, typename Prop::ClassType::Context().ClassRef(),
nullptr));
if (!jarray) {
return nullptr;
}
// For object arrays, we have to set each element separately.
for (size_t i = 0; i < length; i++) {
JS::RootedValue elem(mJSContext);
if (!CheckJSCall(JS_GetElement(mJSContext, array, i, &elem)) ||
!CheckProperty(Prop::InValue, elem)) {
return nullptr;
}
mEnv->SetObjectArrayElement(
jarray.Get(), i, (this->*Prop::FromValue)(elem).Get());
if (mEnv->ExceptionCheck()) {
return nullptr;
}
}
return jarray;
}
template<class Class,
bool (Self::*InValue_)(JS::HandleValue) const,
typename Class::LocalRef (Self::*FromValue_)(JS::HandleValue)>
struct BaseObjectProperty
{
// JNI class for the object type (e.g. jni::String)
typedef Class ClassType;
// See comments in PrimitiveProperty.
typedef typename ClassType::LocalRef NativeType;
typedef const typename ClassType::Ref NativeFallback;
typedef typename jni::ObjectArray::LocalRef NativeArray;
typedef const jni::ObjectArray::Ref ArrayFallback;
typedef decltype(InValue_) InValue_t;
static constexpr InValue_t InValue = InValue_;
typedef decltype(FromValue_) FromValue_t;
static constexpr FromValue_t FromValue = FromValue_;
typedef decltype(&Self::ObjectNewArray<BaseObjectProperty>) NewArray_t;
static constexpr NewArray_t NewArray
= &Self::ObjectNewArray<BaseObjectProperty>;
};
// Array properties
template<class Prop> bool
ArrayInValue(JS::HandleValue val) const
{
if (!val.isObject()) {
return false;
}
JS::RootedObject obj(mJSContext, &val.toObject());
bool isArray;
uint32_t length = 0;
if (!JS_IsArrayObject(mJSContext, obj, &isArray) ||
!isArray ||
!JS_GetArrayLength(mJSContext, obj, &length)) {
JS_ClearPendingException(mJSContext);
return false;
}
if (!length) {
// Empty arrays are always okay.
return true;
}
// We only check to see the first element is the target type. If the
// array has mixed types, we'll throw an error during actual conversion.
JS::RootedValue element(mJSContext);
if (!JS_GetElement(mJSContext, obj, 0, &element)) {
JS_ClearPendingException(mJSContext);
return false;
}
return (this->*Prop::InValue)(element);
}
template<class Prop> typename Prop::NativeArray
ArrayFromValue(JS::HandleValue val)
{
JS::RootedObject obj(mJSContext, &val.toObject());
uint32_t length = 0;
if (!CheckJSCall(JS_GetArrayLength(mJSContext, obj, &length))) {
return nullptr;
}
return (this->*Prop::NewArray)(obj, length);
}
template<class Prop>
struct ArrayProperty
{
// See comments in PrimitiveProperty.
typedef typename Prop::NativeArray NativeType;
typedef typename Prop::ArrayFallback NativeFallback;
typedef decltype(&Self::ArrayInValue<Prop>) InValue_t;
static constexpr InValue_t InValue
= &Self::ArrayInValue<Prop>;
typedef decltype(&Self::ArrayFromValue<Prop>) FromValue_t;
static constexpr FromValue_t FromValue
= &Self::ArrayFromValue<Prop>;
};
// "Has" property is a special property type that is used to implement
// NativeJSObject.has, by returning true from InValue and FromValue for
// every existing property, and having false as the fallback value for
// when a property doesn't exist.
bool HasValue(JS::HandleValue val) const
{
return true;
}
struct HasProperty
{
// See comments in PrimitiveProperty.
typedef bool NativeType;
typedef bool NativeFallback;
typedef decltype(&Self::HasValue) HasValue_t;
static constexpr HasValue_t InValue = &Self::HasValue;
static constexpr HasValue_t FromValue = &Self::HasValue;
};
// Statically cast from bool to jboolean (unsigned char); it works
// since false and JNI_FALSE have the same value (0), and true and
// JNI_TRUE have the same value (1).
typedef PrimitiveProperty<
bool, jni::BooleanArray, jboolean, jbooleanArray,
&JS::Value::isBoolean, &JS::Value::toBoolean,
&JNIEnv::NewBooleanArray, &JNIEnv::SetBooleanArrayRegion>
BooleanProperty;
typedef PrimitiveProperty<
double, jni::DoubleArray, jdouble, jdoubleArray,
&JS::Value::isNumber, &JS::Value::toNumber,
&JNIEnv::NewDoubleArray, &JNIEnv::SetDoubleArrayRegion>
DoubleProperty;
typedef PrimitiveProperty<
int32_t, jni::IntArray, jint, jintArray,
&JS::Value::isInt32, &JS::Value::toInt32,
&JNIEnv::NewIntArray, &JNIEnv::SetIntArrayRegion>
IntProperty;
typedef BaseObjectProperty<
jni::String, &Self::StringInValue, &Self::StringFromValue>
StringProperty;
typedef BaseObjectProperty<
sdk::Bundle, &Self::ObjectInValue, &Self::BundleFromValue>
BundleProperty;
typedef BaseObjectProperty<
NativeJSObject, &Self::ObjectInValue, &Self::ObjectFromValue>
ObjectProperty;
typedef ArrayProperty<BooleanProperty> BooleanArrayProperty;
typedef ArrayProperty<DoubleProperty> DoubleArrayProperty;
typedef ArrayProperty<IntProperty> IntArrayProperty;
typedef ArrayProperty<StringProperty> StringArrayProperty;
typedef ArrayProperty<BundleProperty> BundleArrayProperty;
typedef ArrayProperty<ObjectProperty> ObjectArrayProperty;
template<class Prop>
typename Prop::NativeType
GetProperty(jni::String::Param name,
typename Prop::NativeFallback* fallback = nullptr)
{
if (!CheckThread() || !CheckObject()) {
return typename Prop::NativeType();
}
const JSJNIString nameStr(mEnv, name);
JS::RootedValue val(mJSContext);
if (!CheckJNIArgument(name) ||
!CheckJSCall(JS_GetUCProperty(
mJSContext, mJSObject, nameStr, nameStr.Length(), &val))) {
return typename Prop::NativeType();
}
// Strictly, null is different from undefined in JS. However, in
// practice, null is often used to indicate a property doesn't exist in
// the same manner as undefined. Therefore, we treat null in the same
// way as undefined when checking property existence (bug 1014965).
if (val.isUndefined() || val.isNull()) {
if (fallback) {
return mozilla::Move(*fallback);
}
jni::ThrowException(
"org/mozilla/gecko/util/NativeJSObject$InvalidPropertyException",
"Property does not exist");
return typename Prop::NativeType();
}
if (!CheckProperty(Prop::InValue, val)) {
return typename Prop::NativeType();
}
return (this->*Prop::FromValue)(val);
}
NativeJSObject::LocalRef CreateChild(JS::HandleObject object)
{
auto instance = NativeJSObject::New();
mozilla::UniquePtr<NativeJSContainerImpl> impl(
new NativeJSContainerImpl(instance.Env(), mJSContext, object));
ObjectBase::AttachNative(instance, mozilla::Move(impl));
if (!mChildren.append(NativeJSObject::GlobalRef(instance))) {
MOZ_CRASH();
}
return instance;
}
NativeJSContainerImpl(JNIEnv* env, JSContext* cx, JS::HandleObject object)
: mEnv(env)
, mJSContext(cx)
, mJSObject(cx, object)
{}
public:
~NativeJSContainerImpl()
{
// Dispose of all children on destruction. The children will in turn
// dispose any of their children (i.e. our grandchildren) and so on.
NativeJSObject::LocalRef child(mEnv);
for (size_t i = 0; i < mChildren.length(); i++) {
child = mChildren[i];
ObjectBase::GetNative(child)->ObjectBase::DisposeNative(child);
}
}
static NativeJSContainer::LocalRef
CreateInstance(JSContext* cx, JS::HandleObject object)
{
auto instance = NativeJSContainer::New();
mozilla::UniquePtr<NativeJSContainerImpl> impl(
new NativeJSContainerImpl(instance.Env(), cx, object));
ContainerBase::AttachNative(instance, mozilla::Move(impl));
return instance;
}
// NativeJSContainer methods
void DisposeNative(const NativeJSContainer::LocalRef& instance)
{
if (!CheckThread()) {
return;
}
ContainerBase::DisposeNative(instance);
}
NativeJSContainer::LocalRef Clone()
{
if (!CheckThread()) {
return nullptr;
}
return CreateInstance(mJSContext, mJSObject);
}
// NativeJSObject methods
bool GetBoolean(jni::String::Param name)
{
return GetProperty<BooleanProperty>(name);
}
bool OptBoolean(jni::String::Param name, bool fallback)
{
return GetProperty<BooleanProperty>(name, &fallback);
}
jni::BooleanArray::LocalRef
GetBooleanArray(jni::String::Param name)
{
return GetProperty<BooleanArrayProperty>(name);
}
jni::BooleanArray::LocalRef
OptBooleanArray(jni::String::Param name, jni::BooleanArray::Param fallback)
{
return GetProperty<BooleanArrayProperty>(name, &fallback);
}
jni::Object::LocalRef
GetBundle(jni::String::Param name)
{
return GetProperty<BundleProperty>(name);
}
jni::Object::LocalRef
OptBundle(jni::String::Param name, jni::Object::Param fallback)
{
// Because the GetProperty expects a sdk::Bundle::Param,
// we have to do conversions here from jni::Object::Param.
const auto& fb = sdk::Bundle::Ref::From(fallback.Get());
return GetProperty<BundleProperty>(name, &fb);
}
jni::ObjectArray::LocalRef
GetBundleArray(jni::String::Param name)
{
return GetProperty<BundleArrayProperty>(name);
}
jni::ObjectArray::LocalRef
OptBundleArray(jni::String::Param name, jni::ObjectArray::Param fallback)
{
return GetProperty<BundleArrayProperty>(name, &fallback);
}
double GetDouble(jni::String::Param name)
{
return GetProperty<DoubleProperty>(name);
}
double OptDouble(jni::String::Param name, double fallback)
{
return GetProperty<DoubleProperty>(name, &fallback);
}
jni::DoubleArray::LocalRef
GetDoubleArray(jni::String::Param name)
{
return GetProperty<DoubleArrayProperty>(name);
}
jni::DoubleArray::LocalRef
OptDoubleArray(jni::String::Param name, jni::DoubleArray::Param fallback)
{
jni::DoubleArray::LocalRef fb(fallback);
return GetProperty<DoubleArrayProperty>(name, &fb);
}
int GetInt(jni::String::Param name)
{
return GetProperty<IntProperty>(name);
}
int OptInt(jni::String::Param name, int fallback)
{
return GetProperty<IntProperty>(name, &fallback);
}
jni::IntArray::LocalRef
GetIntArray(jni::String::Param name)
{
return GetProperty<IntArrayProperty>(name);
}
jni::IntArray::LocalRef
OptIntArray(jni::String::Param name, jni::IntArray::Param fallback)
{
jni::IntArray::LocalRef fb(fallback);
return GetProperty<IntArrayProperty>(name, &fb);
}
NativeJSObject::LocalRef
GetObject(jni::String::Param name)
{
return GetProperty<ObjectProperty>(name);
}
NativeJSObject::LocalRef
OptObject(jni::String::Param name, NativeJSObject::Param fallback)
{
return GetProperty<ObjectProperty>(name, &fallback);
}
jni::ObjectArray::LocalRef
GetObjectArray(jni::String::Param name)
{
return GetProperty<ObjectArrayProperty>(name);
}
jni::ObjectArray::LocalRef
OptObjectArray(jni::String::Param name, jni::ObjectArray::Param fallback)
{
return GetProperty<ObjectArrayProperty>(name, &fallback);
}
jni::String::LocalRef
GetString(jni::String::Param name)
{
return GetProperty<StringProperty>(name);
}
jni::String::LocalRef
OptString(jni::String::Param name, jni::String::Param fallback)
{
return GetProperty<StringProperty>(name, &fallback);
}
jni::ObjectArray::LocalRef
GetStringArray(jni::String::Param name)
{
return GetProperty<StringArrayProperty>(name);
}
jni::ObjectArray::LocalRef
OptStringArray(jni::String::Param name, jni::ObjectArray::Param fallback)
{
return GetProperty<StringArrayProperty>(name, &fallback);
}
bool Has(jni::String::Param name)
{
bool no = false;
// Fallback to false indicating no such property.
return GetProperty<HasProperty>(name, &no);
}
jni::Object::LocalRef ToBundle()
{
if (!CheckThread() || !CheckObject()) {
return nullptr;
}
return BundleFromValue(mJSObject);
}
private:
static bool AppendJSON(const char16_t* buf, uint32_t len, void* data)
{
static_cast<nsAutoString*>(data)->Append(buf, len);
return true;
}
public:
jni::String::LocalRef ToString()
{
if (!CheckThread() || !CheckObject()) {
return nullptr;
}
JS::RootedValue value(mJSContext, JS::ObjectValue(*mJSObject));
nsAutoString json;
if (!CheckJSCall(JS_Stringify(mJSContext, &value, nullptr,
JS::NullHandleValue, AppendJSON, &json))) {
return nullptr;
}
return jni::StringParam(json, mEnv);
}
};
// Define the "static constexpr" members of our property types (e.g.
// PrimitiveProperty<>::InValue). This is tricky because there are a lot of
// template parameters, so we use macros to make it simpler.
#define DEFINE_PRIMITIVE_PROPERTY_MEMBER(Name) \
template<typename U, typename UA, typename V, typename VA, \
bool (JS::Value::*I)() const, \
U (JS::Value::*T)() const, \
VA (JNIEnv::*N)(jsize), \
void (JNIEnv::*S)(VA, jsize, jsize, const V*)> \
constexpr typename NativeJSContainerImpl \
::PrimitiveProperty<U, UA, V, VA, I, T, N, S>::Name##_t \
NativeJSContainerImpl::PrimitiveProperty<U, UA, V, VA, I, T, N, S>::Name
DEFINE_PRIMITIVE_PROPERTY_MEMBER(NewJNIArray);
DEFINE_PRIMITIVE_PROPERTY_MEMBER(SetJNIArrayRegion);
DEFINE_PRIMITIVE_PROPERTY_MEMBER(InValue);
DEFINE_PRIMITIVE_PROPERTY_MEMBER(FromValue);
DEFINE_PRIMITIVE_PROPERTY_MEMBER(NewArray);
#undef DEFINE_PRIMITIVE_PROPERTY_MEMBER
#define DEFINE_OBJECT_PROPERTY_MEMBER(Name) \
template<class C, \
bool (NativeJSContainerImpl::*I)(JS::HandleValue) const, \
typename C::LocalRef (NativeJSContainerImpl::*F)(JS::HandleValue)> \
constexpr typename NativeJSContainerImpl \
::BaseObjectProperty<C, I, F>::Name##_t \
NativeJSContainerImpl::BaseObjectProperty<C, I, F>::Name
DEFINE_OBJECT_PROPERTY_MEMBER(InValue);
DEFINE_OBJECT_PROPERTY_MEMBER(FromValue);
DEFINE_OBJECT_PROPERTY_MEMBER(NewArray);
#undef DEFINE_OBJECT_PROPERTY_MEMBER
template<class P> constexpr typename NativeJSContainerImpl::ArrayProperty<P>
::InValue_t NativeJSContainerImpl::ArrayProperty<P>::InValue;
template<class P> constexpr typename NativeJSContainerImpl::ArrayProperty<P>
::FromValue_t NativeJSContainerImpl::ArrayProperty<P>::FromValue;
constexpr NativeJSContainerImpl::HasProperty::HasValue_t
NativeJSContainerImpl::HasProperty::InValue;
constexpr NativeJSContainerImpl::HasProperty::HasValue_t
NativeJSContainerImpl::HasProperty::FromValue;
NativeJSContainer::LocalRef
CreateNativeJSContainer(JSContext* cx, JS::HandleObject object)
{
return NativeJSContainerImpl::CreateInstance(cx, object);
}
} // namespace widget
} // namespace mozilla

View file

@ -0,0 +1,22 @@
/* -*- Mode: c++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4; -*- */
/* 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/. */
#ifndef NativeJSObject_h__
#define NativeJSObject_h__
#include "GeneratedJNIWrappers.h"
#include "jsapi.h"
namespace mozilla {
namespace widget {
java::NativeJSContainer::LocalRef
CreateNativeJSContainer(JSContext* cx, JS::HandleObject object);
} // namespace widget
} // namespace mozilla
#endif // NativeJSObject_h__

View file

@ -0,0 +1,324 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
#ifndef PrefsHelper_h
#define PrefsHelper_h
#include "GeneratedJNINatives.h"
#include "MainThreadUtils.h"
#include "nsAppShell.h"
#include "nsCOMPtr.h"
#include "nsVariant.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
namespace mozilla {
class PrefsHelper
: public java::PrefsHelper::Natives<PrefsHelper>
{
PrefsHelper() = delete;
static bool GetVariantPref(nsIObserverService* aObsServ,
nsIWritableVariant* aVariant,
jni::Object::Param aPrefHandler,
const jni::String::LocalRef& aPrefName)
{
if (NS_FAILED(aObsServ->NotifyObservers(aVariant, "android-get-pref",
aPrefName->ToString().get()))) {
return false;
}
uint16_t varType = nsIDataType::VTYPE_EMPTY;
if (NS_FAILED(aVariant->GetDataType(&varType))) {
return false;
}
int32_t type = java::PrefsHelper::PREF_INVALID;
bool boolVal = false;
int32_t intVal = 0;
nsAutoString strVal;
switch (varType) {
case nsIDataType::VTYPE_BOOL:
type = java::PrefsHelper::PREF_BOOL;
if (NS_FAILED(aVariant->GetAsBool(&boolVal))) {
return false;
}
break;
case nsIDataType::VTYPE_INT32:
type = java::PrefsHelper::PREF_INT;
if (NS_FAILED(aVariant->GetAsInt32(&intVal))) {
return false;
}
break;
case nsIDataType::VTYPE_ASTRING:
type = java::PrefsHelper::PREF_STRING;
if (NS_FAILED(aVariant->GetAsAString(strVal))) {
return false;
}
break;
default:
return false;
}
jni::StringParam jstrVal(type == java::PrefsHelper::PREF_STRING ?
jni::StringParam(strVal, aPrefName.Env()) :
jni::StringParam(nullptr));
if (aPrefHandler) {
java::PrefsHelper::CallPrefHandler(
aPrefHandler, type, aPrefName,
boolVal, intVal, jstrVal);
} else {
java::PrefsHelper::OnPrefChange(
aPrefName, type, boolVal, intVal, jstrVal);
}
return true;
}
static bool SetVariantPref(nsIObserverService* aObsServ,
nsIWritableVariant* aVariant,
jni::String::Param aPrefName,
bool aFlush,
int32_t aType,
bool aBoolVal,
int32_t aIntVal,
jni::String::Param aStrVal)
{
nsresult rv = NS_ERROR_FAILURE;
switch (aType) {
case java::PrefsHelper::PREF_BOOL:
rv = aVariant->SetAsBool(aBoolVal);
break;
case java::PrefsHelper::PREF_INT:
rv = aVariant->SetAsInt32(aIntVal);
break;
case java::PrefsHelper::PREF_STRING:
rv = aVariant->SetAsAString(aStrVal->ToString());
break;
}
if (NS_SUCCEEDED(rv)) {
rv = aObsServ->NotifyObservers(aVariant, "android-set-pref",
aPrefName->ToString().get());
}
uint16_t varType = nsIDataType::VTYPE_EMPTY;
if (NS_SUCCEEDED(rv)) {
rv = aVariant->GetDataType(&varType);
}
// We use set-to-empty to signal the pref was handled.
const bool handled = varType == nsIDataType::VTYPE_EMPTY;
if (NS_SUCCEEDED(rv) && handled && aFlush) {
rv = Preferences::GetService()->SavePrefFile(nullptr);
}
if (NS_SUCCEEDED(rv)) {
return handled;
}
NS_WARNING(nsPrintfCString("Failed to set pref %s",
aPrefName->ToCString().get()).get());
// Pretend we handled the pref.
return true;
}
public:
static void GetPrefs(const jni::Class::LocalRef& aCls,
jni::ObjectArray::Param aPrefNames,
jni::Object::Param aPrefHandler)
{
nsTArray<jni::Object::LocalRef> nameRefArray(aPrefNames->GetElements());
nsCOMPtr<nsIObserverService> obsServ;
nsCOMPtr<nsIWritableVariant> value;
nsAdoptingString strVal;
for (jni::Object::LocalRef& nameRef : nameRefArray) {
jni::String::LocalRef nameStr(mozilla::Move(nameRef));
const nsCString& name = nameStr->ToCString();
int32_t type = java::PrefsHelper::PREF_INVALID;
bool boolVal = false;
int32_t intVal = 0;
switch (Preferences::GetType(name.get())) {
case nsIPrefBranch::PREF_BOOL:
type = java::PrefsHelper::PREF_BOOL;
boolVal = Preferences::GetBool(name.get());
break;
case nsIPrefBranch::PREF_INT:
type = java::PrefsHelper::PREF_INT;
intVal = Preferences::GetInt(name.get());
break;
case nsIPrefBranch::PREF_STRING:
type = java::PrefsHelper::PREF_STRING;
strVal = Preferences::GetLocalizedString(name.get());
if (!strVal) {
strVal = Preferences::GetString(name.get());
}
break;
default:
// Pref not found; try to find it.
if (!obsServ) {
obsServ = services::GetObserverService();
if (!obsServ) {
continue;
}
}
if (value) {
value->SetAsEmpty();
} else {
value = new nsVariant();
}
if (!GetVariantPref(obsServ, value,
aPrefHandler, nameStr)) {
NS_WARNING(nsPrintfCString("Failed to get pref %s",
name.get()).get());
}
continue;
}
java::PrefsHelper::CallPrefHandler(
aPrefHandler, type, nameStr, boolVal, intVal,
jni::StringParam(type == java::PrefsHelper::PREF_STRING ?
jni::StringParam(strVal, aCls.Env()) :
jni::StringParam(nullptr)));
}
java::PrefsHelper::CallPrefHandler(
aPrefHandler, java::PrefsHelper::PREF_FINISH,
nullptr, false, 0, nullptr);
}
static void SetPref(jni::String::Param aPrefName,
bool aFlush,
int32_t aType,
bool aBoolVal,
int32_t aIntVal,
jni::String::Param aStrVal)
{
const nsCString& name = aPrefName->ToCString();
if (Preferences::GetType(name.get()) == nsIPrefBranch::PREF_INVALID) {
// No pref; try asking first.
nsCOMPtr<nsIObserverService> obsServ =
services::GetObserverService();
nsCOMPtr<nsIWritableVariant> value = new nsVariant();
if (obsServ && SetVariantPref(obsServ, value, aPrefName, aFlush,
aType, aBoolVal, aIntVal, aStrVal)) {
// The "pref" has changed; send a notification.
GetVariantPref(obsServ, value, nullptr,
jni::String::LocalRef(aPrefName));
return;
}
}
switch (aType) {
case java::PrefsHelper::PREF_BOOL:
Preferences::SetBool(name.get(), aBoolVal);
break;
case java::PrefsHelper::PREF_INT:
Preferences::SetInt(name.get(), aIntVal);
break;
case java::PrefsHelper::PREF_STRING:
Preferences::SetString(name.get(), aStrVal->ToString());
break;
default:
MOZ_ASSERT(false, "Invalid pref type");
}
if (aFlush) {
Preferences::GetService()->SavePrefFile(nullptr);
}
}
static void AddObserver(const jni::Class::LocalRef& aCls,
jni::ObjectArray::Param aPrefNames,
jni::Object::Param aPrefHandler,
jni::ObjectArray::Param aPrefsToObserve)
{
// Call observer immediately with existing pref values.
GetPrefs(aCls, aPrefNames, aPrefHandler);
if (!aPrefsToObserve) {
return;
}
nsTArray<jni::Object::LocalRef> nameRefArray(
aPrefsToObserve->GetElements());
nsAppShell* const appShell = nsAppShell::Get();
MOZ_ASSERT(appShell);
for (jni::Object::LocalRef& nameRef : nameRefArray) {
jni::String::LocalRef nameStr(mozilla::Move(nameRef));
MOZ_ALWAYS_SUCCEEDS(Preferences::AddStrongObserver(
appShell, nameStr->ToCString().get()));
}
}
static void RemoveObserver(const jni::Class::LocalRef& aCls,
jni::ObjectArray::Param aPrefsToUnobserve)
{
nsTArray<jni::Object::LocalRef> nameRefArray(
aPrefsToUnobserve->GetElements());
nsAppShell* const appShell = nsAppShell::Get();
MOZ_ASSERT(appShell);
for (jni::Object::LocalRef& nameRef : nameRefArray) {
jni::String::LocalRef nameStr(mozilla::Move(nameRef));
MOZ_ALWAYS_SUCCEEDS(Preferences::RemoveObserver(
appShell, nameStr->ToCString().get()));
}
}
static void OnPrefChange(const char16_t* aData)
{
const nsCString& name = NS_LossyConvertUTF16toASCII(aData);
int32_t type = -1;
bool boolVal = false;
int32_t intVal = false;
nsAdoptingString strVal;
switch (Preferences::GetType(name.get())) {
case nsIPrefBranch::PREF_BOOL:
type = java::PrefsHelper::PREF_BOOL;
boolVal = Preferences::GetBool(name.get());
break;
case nsIPrefBranch::PREF_INT:
type = java::PrefsHelper::PREF_INT;
intVal = Preferences::GetInt(name.get());
break;
case nsIPrefBranch::PREF_STRING:
type = java::PrefsHelper::PREF_STRING;
strVal = Preferences::GetLocalizedString(name.get());
if (!strVal) {
strVal = Preferences::GetString(name.get());
}
break;
default:
NS_WARNING(nsPrintfCString("Invalid pref %s",
name.get()).get());
return;
}
java::PrefsHelper::OnPrefChange(
name, type, boolVal, intVal,
jni::StringParam(type == java::PrefsHelper::PREF_STRING ?
jni::StringParam(strVal) : jni::StringParam(nullptr)));
}
};
} // namespace
#endif // PrefsHelper_h

View file

@ -0,0 +1,2 @@
android.graphics.Rect
android.graphics.RectF

View file

@ -0,0 +1 @@
android.os.Bundle

View file

@ -0,0 +1 @@
android.view.KeyEvent

View file

@ -0,0 +1,27 @@
# 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/.
# Bug 1099345 - The SDK's lint code (used by the code generator) does not enjoy
# concurrent access to a cache that it generates.
.NOTPARALLEL:
annotation_processor_jar_files := \
$(DEPTH)/build/annotationProcessors/annotationProcessors.jar \
$(ANDROID_TOOLS)/lib/lint.jar \
$(ANDROID_TOOLS)/lib/lint-checks.jar \
$(NULL)
sdk_processor := \
$(JAVA) \
-Dcom.android.tools.lint.bindir='$(ANDROID_TOOLS)' \
-classpath $(subst $(NULL) ,:,$(strip $(annotation_processor_jar_files))) \
org.mozilla.gecko.annotationProcessors.SDKProcessor
# For the benefit of readers: the following pattern rule says that,
# for example, MediaCodec.cpp and MediaCodec.h can be produced from
# MediaCodec-classes.txt. This formulation invokes the SDK processor
# at most once.
%.cpp %.h: $(ANDROID_SDK)/android.jar %-classes.txt $(annotation_processor_jar_files)
$(sdk_processor) $(ANDROID_SDK)/android.jar $(srcdir)/$*-classes.txt $(CURDIR) $* 16

View file

@ -0,0 +1,5 @@
android.media.MediaCodec
android.media.MediaCodec$BufferInfo
android.media.MediaCodec$CryptoInfo
android.media.MediaDrm$KeyStatus
android.media.MediaFormat

View file

@ -0,0 +1 @@
android.view.MotionEvent

View file

@ -0,0 +1,2 @@
android.graphics.SurfaceTexture
android.view.Surface

View file

@ -0,0 +1 @@
android.view.ViewConfiguration

View file

@ -0,0 +1,41 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
# List of stems to generate .cpp and .h files for. To add a stem, add it to
# this list and ensure that $(stem)-classes.txt exists in this directory.
generated = [
'AndroidRect',
'Bundle',
'KeyEvent',
'MediaCodec',
'MotionEvent',
'SurfaceTexture',
'ViewConfiguration'
]
SOURCES += ['!%s.cpp' % stem for stem in generated]
EXPORTS += ['!%s.h' % stem for stem in generated]
# We'd like to add these to a future GENERATED_EXPORTS list, but for now we mark
# them as generated here and manually install them in Makefile.in.
GENERATED_FILES += [stem + '.h' for stem in generated]
# There is an unfortunate race condition when using generated SOURCES and
# pattern rules (see Makefile.in) that manifests itself as a VPATH resolution
# conflict: MediaCodec.o looks for MediaCodec.cpp and $(CURDIR)/MediaCodec.cpp,
# and the pattern rule is matched but doesn't resolve both sources, causing a
# failure. Adding the SOURCES to GENERATED_FILES causes the sources
# to be built at export time, which is before MediaCodec.o needs them; and by
# the time MediaCodec.o is built, the source is in place and the VPATH
# resolution works as expected.
GENERATED_FILES += [f[1:] for f in SOURCES]
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/widget/android',
]

View file

@ -0,0 +1,244 @@
// GENERATED CODE
// Generated by the Java program at /build/annotationProcessors at compile time
// from annotations on Java methods. To update, change the annotations on the
// corresponding Java methods and rerun the build. Manually updating this file
// will cause your build to fail.
#ifndef FennecJNINatives_h
#define FennecJNINatives_h
#include "FennecJNIWrappers.h"
#include "mozilla/jni/Natives.h"
namespace mozilla {
namespace java {
template<class Impl>
class ANRReporter::Natives : public mozilla::jni::NativeImpl<ANRReporter, Impl>
{
public:
static const JNINativeMethod methods[3];
};
template<class Impl>
const JNINativeMethod ANRReporter::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<ANRReporter::GetNativeStack_t>(
mozilla::jni::NativeStub<ANRReporter::GetNativeStack_t, Impl>
::template Wrap<&Impl::GetNativeStack>),
mozilla::jni::MakeNativeMethod<ANRReporter::ReleaseNativeStack_t>(
mozilla::jni::NativeStub<ANRReporter::ReleaseNativeStack_t, Impl>
::template Wrap<&Impl::ReleaseNativeStack>),
mozilla::jni::MakeNativeMethod<ANRReporter::RequestNativeStack_t>(
mozilla::jni::NativeStub<ANRReporter::RequestNativeStack_t, Impl>
::template Wrap<&Impl::RequestNativeStack>)
};
template<class Impl>
class GeckoJavaSampler::Natives : public mozilla::jni::NativeImpl<GeckoJavaSampler, Impl>
{
public:
static const JNINativeMethod methods[1];
};
template<class Impl>
const JNINativeMethod GeckoJavaSampler::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<GeckoJavaSampler::GetProfilerTime_t>(
mozilla::jni::NativeStub<GeckoJavaSampler::GetProfilerTime_t, Impl>
::template Wrap<&Impl::GetProfilerTime>)
};
template<class Impl>
class MemoryMonitor::Natives : public mozilla::jni::NativeImpl<MemoryMonitor, Impl>
{
public:
static const JNINativeMethod methods[1];
};
template<class Impl>
const JNINativeMethod MemoryMonitor::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<MemoryMonitor::DispatchMemoryPressure_t>(
mozilla::jni::NativeStub<MemoryMonitor::DispatchMemoryPressure_t, Impl>
::template Wrap<&Impl::DispatchMemoryPressure>)
};
template<class Impl>
class PresentationMediaPlayerManager::Natives : public mozilla::jni::NativeImpl<PresentationMediaPlayerManager, Impl>
{
public:
static const JNINativeMethod methods[3];
};
template<class Impl>
const JNINativeMethod PresentationMediaPlayerManager::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<PresentationMediaPlayerManager::AddPresentationSurface_t>(
mozilla::jni::NativeStub<PresentationMediaPlayerManager::AddPresentationSurface_t, Impl>
::template Wrap<&Impl::AddPresentationSurface>),
mozilla::jni::MakeNativeMethod<PresentationMediaPlayerManager::InvalidateAndScheduleComposite_t>(
mozilla::jni::NativeStub<PresentationMediaPlayerManager::InvalidateAndScheduleComposite_t, Impl>
::template Wrap<&Impl::InvalidateAndScheduleComposite>),
mozilla::jni::MakeNativeMethod<PresentationMediaPlayerManager::RemovePresentationSurface_t>(
mozilla::jni::NativeStub<PresentationMediaPlayerManager::RemovePresentationSurface_t, Impl>
::template Wrap<&Impl::RemovePresentationSurface>)
};
template<class Impl>
class ScreenManagerHelper::Natives : public mozilla::jni::NativeImpl<ScreenManagerHelper, Impl>
{
public:
static const JNINativeMethod methods[2];
};
template<class Impl>
const JNINativeMethod ScreenManagerHelper::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<ScreenManagerHelper::AddDisplay_t>(
mozilla::jni::NativeStub<ScreenManagerHelper::AddDisplay_t, Impl>
::template Wrap<&Impl::AddDisplay>),
mozilla::jni::MakeNativeMethod<ScreenManagerHelper::RemoveDisplay_t>(
mozilla::jni::NativeStub<ScreenManagerHelper::RemoveDisplay_t, Impl>
::template Wrap<&Impl::RemoveDisplay>)
};
template<class Impl>
class Telemetry::Natives : public mozilla::jni::NativeImpl<Telemetry, Impl>
{
public:
static const JNINativeMethod methods[5];
};
template<class Impl>
const JNINativeMethod Telemetry::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<Telemetry::AddHistogram_t>(
mozilla::jni::NativeStub<Telemetry::AddHistogram_t, Impl>
::template Wrap<&Impl::AddHistogram>),
mozilla::jni::MakeNativeMethod<Telemetry::AddKeyedHistogram_t>(
mozilla::jni::NativeStub<Telemetry::AddKeyedHistogram_t, Impl>
::template Wrap<&Impl::AddKeyedHistogram>),
mozilla::jni::MakeNativeMethod<Telemetry::AddUIEvent_t>(
mozilla::jni::NativeStub<Telemetry::AddUIEvent_t, Impl>
::template Wrap<&Impl::AddUIEvent>),
mozilla::jni::MakeNativeMethod<Telemetry::StartUISession_t>(
mozilla::jni::NativeStub<Telemetry::StartUISession_t, Impl>
::template Wrap<&Impl::StartUISession>),
mozilla::jni::MakeNativeMethod<Telemetry::StopUISession_t>(
mozilla::jni::NativeStub<Telemetry::StopUISession_t, Impl>
::template Wrap<&Impl::StopUISession>)
};
template<class Impl>
class ThumbnailHelper::Natives : public mozilla::jni::NativeImpl<ThumbnailHelper, Impl>
{
public:
static const JNINativeMethod methods[1];
};
template<class Impl>
const JNINativeMethod ThumbnailHelper::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<ThumbnailHelper::RequestThumbnail_t>(
mozilla::jni::NativeStub<ThumbnailHelper::RequestThumbnail_t, Impl>
::template Wrap<&Impl::RequestThumbnail>)
};
template<class Impl>
class ZoomedView::Natives : public mozilla::jni::NativeImpl<ZoomedView, Impl>
{
public:
static const JNINativeMethod methods[1];
};
template<class Impl>
const JNINativeMethod ZoomedView::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<ZoomedView::RequestZoomedViewData_t>(
mozilla::jni::NativeStub<ZoomedView::RequestZoomedViewData_t, Impl>
::template Wrap<&Impl::RequestZoomedViewData>)
};
template<class Impl>
class CodecProxy::NativeCallbacks::Natives : public mozilla::jni::NativeImpl<NativeCallbacks, Impl>
{
public:
static const JNINativeMethod methods[5];
};
template<class Impl>
const JNINativeMethod CodecProxy::NativeCallbacks::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::DisposeNative_t>(
mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::DisposeNative_t, Impl>
::template Wrap<&Impl::DisposeNative>),
mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::OnError_t>(
mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::OnError_t, Impl>
::template Wrap<&Impl::OnError>),
mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::OnInputExhausted_t>(
mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::OnInputExhausted_t, Impl>
::template Wrap<&Impl::OnInputExhausted>),
mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::OnOutput_t>(
mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::OnOutput_t, Impl>
::template Wrap<&Impl::OnOutput>),
mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::OnOutputFormatChanged_t>(
mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::OnOutputFormatChanged_t, Impl>
::template Wrap<&Impl::OnOutputFormatChanged>)
};
template<class Impl>
class MediaDrmProxy::NativeMediaDrmProxyCallbacks::Natives : public mozilla::jni::NativeImpl<NativeMediaDrmProxyCallbacks, Impl>
{
public:
static const JNINativeMethod methods[7];
};
template<class Impl>
const JNINativeMethod MediaDrmProxy::NativeMediaDrmProxyCallbacks::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnRejectPromise_t>(
mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnRejectPromise_t, Impl>
::template Wrap<&Impl::OnRejectPromise>),
mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionBatchedKeyChanged_t>(
mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionBatchedKeyChanged_t, Impl>
::template Wrap<&Impl::OnSessionBatchedKeyChanged>),
mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionClosed_t>(
mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionClosed_t, Impl>
::template Wrap<&Impl::OnSessionClosed>),
mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionCreated_t>(
mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionCreated_t, Impl>
::template Wrap<&Impl::OnSessionCreated>),
mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionError_t>(
mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionError_t, Impl>
::template Wrap<&Impl::OnSessionError>),
mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionMessage_t>(
mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionMessage_t, Impl>
::template Wrap<&Impl::OnSessionMessage>),
mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionUpdated_t>(
mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionUpdated_t, Impl>
::template Wrap<&Impl::OnSessionUpdated>)
};
} /* java */
} /* mozilla */
#endif // FennecJNINatives_h

Some files were not shown because too many files have changed in this diff Show more