summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WebCore/config.h2
-rw-r--r--WebCore/html/HTMLOptionElement.h12
-rw-r--r--WebCore/page/FrameView.cpp23
-rw-r--r--WebCore/page/FrameView.h4
-rw-r--r--WebCore/platform/android/PlatformBridge.h4
-rw-r--r--WebCore/platform/android/PopupMenuAndroid.cpp33
-rw-r--r--WebCore/platform/android/PopupMenuAndroid.h6
-rw-r--r--WebCore/platform/android/RenderThemeAndroid.cpp77
-rw-r--r--WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp61
-rw-r--r--WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h15
-rw-r--r--WebCore/platform/graphics/android/BaseLayerAndroid.cpp8
-rw-r--r--WebCore/platform/graphics/android/BaseTile.cpp28
-rw-r--r--WebCore/platform/graphics/android/BaseTile.h5
-rw-r--r--WebCore/platform/graphics/android/GLWebViewState.cpp23
-rw-r--r--WebCore/platform/graphics/android/GLWebViewState.h3
-rw-r--r--WebCore/platform/graphics/android/LayerAndroid.cpp106
-rw-r--r--WebCore/platform/graphics/android/LayerAndroid.h11
-rw-r--r--WebCore/platform/graphics/android/MediaLayer.cpp13
-rw-r--r--WebCore/platform/graphics/android/MediaLayer.h3
-rw-r--r--WebCore/platform/graphics/android/MediaTexture.cpp73
-rw-r--r--WebCore/platform/graphics/android/MediaTexture.h5
-rw-r--r--WebCore/platform/graphics/android/ShaderProgram.cpp23
-rw-r--r--WebCore/platform/graphics/android/ShaderProgram.h4
-rw-r--r--WebCore/platform/graphics/android/TextureOwner.h2
-rw-r--r--WebCore/platform/graphics/android/TexturesGenerator.cpp4
-rw-r--r--WebCore/platform/graphics/android/TiledPage.cpp91
-rw-r--r--WebCore/platform/graphics/android/TiledPage.h2
-rw-r--r--WebCore/platform/graphics/android/TilesManager.cpp128
-rw-r--r--WebCore/platform/graphics/android/TilesManager.h26
-rw-r--r--WebCore/rendering/RenderBox.cpp14
-rw-r--r--WebCore/rendering/RenderLayer.cpp3
-rw-r--r--WebCore/rendering/RenderTheme.cpp2
-rw-r--r--WebCore/rendering/RenderTheme.h2
-rw-r--r--WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp2
-rw-r--r--WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp6
-rw-r--r--WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h2
-rw-r--r--WebKit/android/WebCoreSupport/PlatformBridge.cpp8
-rw-r--r--WebKit/android/WebCoreSupport/WebCookieJar.cpp27
-rw-r--r--WebKit/android/WebCoreSupport/WebCookieJar.h6
-rw-r--r--WebKit/android/WebCoreSupport/WebRequest.cpp2
-rw-r--r--WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp39
-rw-r--r--WebKit/android/jni/CookieManager.cpp21
-rw-r--r--WebKit/android/jni/WebCoreFrameBridge.cpp103
-rw-r--r--WebKit/android/jni/WebCoreFrameBridge.h14
-rw-r--r--WebKit/android/jni/WebViewCore.cpp858
-rw-r--r--WebKit/android/jni/WebViewCore.h38
-rw-r--r--WebKit/android/nav/CachedFrame.cpp18
-rw-r--r--WebKit/android/nav/CachedLayer.cpp1
-rw-r--r--WebKit/android/nav/WebView.cpp30
-rw-r--r--WebKit/android/plugins/ANPOpenGLInterface.cpp3
-rw-r--r--WebKit/android/plugins/PluginWidgetAndroid.cpp32
-rw-r--r--WebKit/android/plugins/PluginWidgetAndroid.h2
52 files changed, 1115 insertions, 913 deletions
diff --git a/WebCore/config.h b/WebCore/config.h
index 7174c4b..6117fef 100644
--- a/WebCore/config.h
+++ b/WebCore/config.h
@@ -160,7 +160,7 @@
#define ANDROID_META_SUPPORT
// Converts ListBoxes to dropdown popup lists.
-#define ANDROID_LISTBOX_USES_MENU_LIST
+#define ENABLE_NO_LISTBOX_RENDERING 1
#define ANDROID_MULTIPLE_WINDOWS
#define ANDROID_CSS_RING
diff --git a/WebCore/html/HTMLOptionElement.h b/WebCore/html/HTMLOptionElement.h
index deac66a..c1791d7 100644
--- a/WebCore/html/HTMLOptionElement.h
+++ b/WebCore/html/HTMLOptionElement.h
@@ -27,13 +27,6 @@
#include "HTMLFormControlElement.h"
#include "OptionElement.h"
-#if PLATFORM(ANDROID)
-namespace android {
-class WebViewCore;
-class ListBoxReply;
-};
-#endif
-
namespace WebCore {
class HTMLSelectElement;
@@ -41,11 +34,6 @@ class HTMLSelectElement;
class HTMLOptionElement : public HTMLFormControlElement, public OptionElement {
friend class HTMLSelectElement;
friend class RenderMenuList;
-#if PLATFORM(ANDROID)
- friend class RenderThemeAndroid;
- friend class android::WebViewCore;
- friend class android::ListBoxReply;
-#endif
public:
static PassRefPtr<HTMLOptionElement> create(Document*, HTMLFormElement*);
diff --git a/WebCore/page/FrameView.cpp b/WebCore/page/FrameView.cpp
index 5314a32..1f03599 100644
--- a/WebCore/page/FrameView.cpp
+++ b/WebCore/page/FrameView.cpp
@@ -1067,6 +1067,29 @@ void FrameView::removeFixedObject()
updateCanBlitOnScrollRecursively();
}
+#if PLATFORM(ANDROID)
+// When the screen size change, fixed positioned element should be updated.
+void FrameView::updatePositionedObjects()
+{
+ RenderBlock::PositionedObjectsListHashSet* positionedObjects = 0;
+ if (RenderView* root = m_frame->contentRenderer())
+ positionedObjects = root->positionedObjects();
+
+ if (!positionedObjects || positionedObjects->isEmpty())
+ return;
+
+ RenderBlock::PositionedObjectsListHashSet::const_iterator end = positionedObjects->end();
+ for (RenderBlock::PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
+ RenderBox* renderBox = *it;
+ if (renderBox->style()->position() != FixedPosition)
+ continue;
+
+ renderBox->computeLogicalWidth();
+ renderBox->computeLogicalHeight();
+ }
+}
+#endif
+
bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
{
const size_t fixedObjectThreshold = 5;
diff --git a/WebCore/page/FrameView.h b/WebCore/page/FrameView.h
index 1b5b322..4135045 100644
--- a/WebCore/page/FrameView.h
+++ b/WebCore/page/FrameView.h
@@ -97,6 +97,10 @@ public:
bool needsFullRepaint() const { return m_doFullRepaint; }
+#if PLATFORM(ANDROID)
+ void updatePositionedObjects();
+#endif
+
#if USE(ACCELERATED_COMPOSITING)
void updateCompositingLayers();
diff --git a/WebCore/platform/android/PlatformBridge.h b/WebCore/platform/android/PlatformBridge.h
index 3f559d5..faa823e 100644
--- a/WebCore/platform/android/PlatformBridge.h
+++ b/WebCore/platform/android/PlatformBridge.h
@@ -149,8 +149,8 @@ public:
static int memoryUsageMB();
static int actualMemoryUsageMB();
- static int visibleScreenWidth(const FrameView*);
- static int visibleScreenHeight(const FrameView*);
+ static int screenWidthInDocCoord(const FrameView*);
+ static int screenHeightInDocCoord(const FrameView*);
};
}
diff --git a/WebCore/platform/android/PopupMenuAndroid.cpp b/WebCore/platform/android/PopupMenuAndroid.cpp
index 2bae724..f4c351f 100644
--- a/WebCore/platform/android/PopupMenuAndroid.cpp
+++ b/WebCore/platform/android/PopupMenuAndroid.cpp
@@ -31,7 +31,7 @@
class PopupReply : public android::WebCoreReply {
public:
- PopupReply(const IntRect& rect, android::WebViewCore* view, PopupMenuClient* client)
+ PopupReply(const IntRect& rect, android::WebViewCore* view, ListPopupMenuClient* client)
: m_rect(rect)
, m_viewImpl(view)
, m_popupClient(client)
@@ -53,9 +53,23 @@ public:
m_viewImpl->contentInvalidate(m_rect);
}
- virtual void replyIntArray(const int*, int) {
- // Should never be called.
- SkASSERT(false);
+ virtual void replyIntArray(const int* values, int count)
+ {
+ if (m_popupClient) {
+ m_popupClient->popupDidHide();
+ if (0 == count) {
+ m_popupClient->valueChanged(-1, true);
+ } else {
+ for (int i = 0; i < count; i++) {
+ m_popupClient->listBoxSelectItem(values[i],
+ i != 0 /* allowMultiplySelection */,
+ false /* shift */,
+ i == count - 1 /* fireOnChangeNow */);
+ }
+ }
+ }
+ if (m_viewImpl)
+ m_viewImpl->contentInvalidate(m_rect);
}
void disconnectClient()
@@ -67,12 +81,12 @@ private:
IntRect m_rect;
// FIXME: Do not need this if we handle ChromeClientAndroid::formStateDidChange
android::WebViewCore* m_viewImpl;
- PopupMenuClient* m_popupClient;
+ ListPopupMenuClient* m_popupClient;
};
namespace WebCore {
-PopupMenuAndroid::PopupMenuAndroid(PopupMenuClient* menuList)
+PopupMenuAndroid::PopupMenuAndroid(ListPopupMenuClient* menuList)
: m_popupClient(menuList)
, m_reply(0)
{
@@ -91,8 +105,7 @@ void PopupMenuAndroid::disconnectClient()
m_reply = 0;
}
}
-// Copied from WebViewCore.cpp. Once we move ListBox handling to this class,
-// we can remove the one in WebViewCore.cpp.
+
// Convert a WTF::String into an array of characters where the first
// character represents the length, for easy conversion to java.
static uint16_t* stringConverter(const WTF::String& text)
@@ -122,9 +135,7 @@ void PopupMenuAndroid::show(const IntRect& rect, FrameView* frameView, int)
SkTDArray<int> enabledArray;
SkTDArray<int> selectedArray;
int size = m_popupClient->listSize();
- // If we use this for ListBoxes in addition to MenuLists, we will need to
- // account for 'multiple'
- bool multiple = false;
+ bool multiple = m_popupClient->multiple();
for (int i = 0; i < size; i++) {
*names.append() = stringConverter(m_popupClient->itemText(i));
if (m_popupClient->itemIsSeparator(i)) {
diff --git a/WebCore/platform/android/PopupMenuAndroid.h b/WebCore/platform/android/PopupMenuAndroid.h
index 48bce44..6c2c015 100644
--- a/WebCore/platform/android/PopupMenuAndroid.h
+++ b/WebCore/platform/android/PopupMenuAndroid.h
@@ -34,18 +34,18 @@ class PopupReply;
namespace WebCore {
class FrameView;
-class PopupMenuClient;
+class ListPopupMenuClient;
class PopupMenuAndroid : public PopupMenu {
public:
- PopupMenuAndroid(PopupMenuClient*);
+ PopupMenuAndroid(ListPopupMenuClient*);
virtual ~PopupMenuAndroid();
virtual void show(const IntRect&, FrameView*, int);
virtual void hide() { }
virtual void updateFromElement() { }
virtual void disconnectClient();
private:
- PopupMenuClient* m_popupClient;
+ ListPopupMenuClient* m_popupClient;
PopupReply* m_reply;
};
diff --git a/WebCore/platform/android/RenderThemeAndroid.cpp b/WebCore/platform/android/RenderThemeAndroid.cpp
index 87e7a6d..b43e0e6 100644
--- a/WebCore/platform/android/RenderThemeAndroid.cpp
+++ b/WebCore/platform/android/RenderThemeAndroid.cpp
@@ -351,57 +351,9 @@ void RenderThemeAndroid::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* sty
bool RenderThemeAndroid::paintTextArea(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
{
- if (!obj->isListBox())
- return true;
-
- paintCombo(obj, info, rect);
- RenderStyle* style = obj->style();
- if (style)
- style->setColor(Color::transparent);
- Node* node = obj->node();
- if (!node || !node->hasTagName(HTMLNames::selectTag))
- return true;
-
- HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node);
- // The first item may be visible. Make sure it does not draw.
- // If it has a style, it overrides the RenderListBox's style, so we
- // need to make sure both are set to transparent.
- node = select->item(0);
- if (node) {
- RenderObject* renderer = node->renderer();
- if (renderer) {
- RenderStyle* renderStyle = renderer->style();
- if (renderStyle)
- renderStyle->setColor(Color::transparent);
- }
- }
- // Find the first selected option, and draw its text.
- // FIXME: In a later change, if there is more than one item selected,
- // draw a string that says "X items" like iPhone Safari does
- int index = select->selectedIndex();
- node = select->item(index);
- if (!node || !node->hasTagName(HTMLNames::optionTag))
- return true;
-
- HTMLOptionElement* option = static_cast<HTMLOptionElement*>(node);
- String label = option->textIndentedToRespectGroupLabel();
- SkRect r(rect);
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
- // Values for text size and positioning determined by trial and error
- paint.setTextSize(r.height() - SkIntToScalar(6));
-
- SkCanvas* canvas = getCanvasFromInfo(info);
- int saveCount = canvas->save();
- r.fRight -= SkIntToScalar(RenderSkinCombo::extraWidth());
- canvas->clipRect(r);
- canvas->drawText(label.characters(), label.length() << 1,
- r.fLeft + SkIntToScalar(5), r.fBottom - SkIntToScalar(5), paint);
- canvas->restoreToCount(saveCount);
-
- return true;
+ if (obj->isMenuList())
+ paintCombo(obj, info, rect);
+ return true;
}
void RenderThemeAndroid::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
@@ -414,16 +366,7 @@ bool RenderThemeAndroid::paintSearchField(RenderObject*, const PaintInfo&, const
return true;
}
-void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
-{
- style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed));
- style->setMaxHeight(Length(style->fontSize() + listboxPadding, Fixed));
- // Make webkit draw invisible, since it will simply draw the first element
- style->setColor(Color::transparent);
- addIntrinsicMargins(style);
-}
-
-static void adjustMenuListStyleCommon(RenderStyle* style, Element* e)
+static void adjustMenuListStyleCommon(RenderStyle* style)
{
// Added to make room for our arrow and make the touch target less cramped.
style->setPaddingLeft(Length(RenderSkinCombo::padding(), Fixed));
@@ -432,9 +375,14 @@ static void adjustMenuListStyleCommon(RenderStyle* style, Element* e)
style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed));
}
+void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
+{
+ adjustMenuListButtonStyle(0, style, 0);
+}
+
void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const
{
- adjustMenuListStyleCommon(style, e);
+ adjustMenuListStyleCommon(style);
addIntrinsicMargins(style);
}
@@ -450,7 +398,8 @@ bool RenderThemeAndroid::paintMenuList(RenderObject* obj, const PaintInfo& info,
return paintCombo(obj, info, rect);
}
-void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const
+void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*,
+ RenderStyle* style, Element*) const
{
// Copied from RenderThemeSafari.
const float baseFontSize = 11.0f;
@@ -468,7 +417,7 @@ void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyl
const int padding = 4;
style->setPaddingTop(Length(padding, Fixed));
style->setPaddingLeft(Length(padding, Fixed));
- adjustMenuListStyleCommon(style, e);
+ adjustMenuListStyleCommon(style);
}
bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect)
diff --git a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp
index fdc6860..d16b53e 100644
--- a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp
+++ b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp
@@ -42,9 +42,13 @@ BackedDoubleBufferedTexture::BackedDoubleBufferedTexture(uint32_t w, uint32_t h,
SkBitmap* bitmap,
SkBitmap::Config config)
: DoubleBufferedTexture(eglGetCurrentContext())
+ , m_x(-1)
+ , m_y(-1)
, m_usedLevel(-1)
, m_config(config)
, m_owner(0)
+ , m_delayedReleaseOwner(0)
+ , m_delayedRelease(false)
, m_busy(false)
{
m_size.set(w, h);
@@ -115,15 +119,27 @@ TextureInfo* BackedDoubleBufferedTexture::producerLock()
void BackedDoubleBufferedTexture::producerRelease()
{
DoubleBufferedTexture::producerRelease();
- android::Mutex::Autolock lock(m_busyLock);
- m_busy = false;
+ setNotBusy();
}
void BackedDoubleBufferedTexture::producerReleaseAndSwap()
{
DoubleBufferedTexture::producerReleaseAndSwap();
+ setNotBusy();
+}
+
+void BackedDoubleBufferedTexture::setNotBusy()
+{
android::Mutex::Autolock lock(m_busyLock);
m_busy = false;
+ if (m_delayedRelease) {
+ if (m_owner == m_delayedReleaseOwner) {
+ m_owner->removeOwned(this);
+ m_owner = 0;
+ }
+ m_delayedRelease = false;
+ m_delayedReleaseOwner = 0;
+ }
}
bool BackedDoubleBufferedTexture::busy()
@@ -173,24 +189,45 @@ bool BackedDoubleBufferedTexture::setOwner(TextureOwner* owner)
{
// if the writable texture is busy (i.e. currently being written to) then we
// can't change the owner out from underneath that texture
- android::Mutex::Autolock lock(m_busyLock);
- if (!m_busy) {
+ m_busyLock.lock();
+ bool busy = m_busy;
+ m_busyLock.unlock();
+ if (!busy) {
+ // if we are not busy we can try to remove the texture from the layer;
+ // LayerAndroid::removeTexture() is protected by the same lock as
+ // LayerAndroid::paintBitmapGL(), so either we execute removeTexture()
+ // first and paintBitmapGL() will bail out, or we execute it after,
+ // and paintBitmapGL() will mark the texture as busy before
+ // relinquishing the lock. LayerAndroid::removeTexture() will call
+ // BackedDoubleBufferedTexture::release(), which will then do nothing
+ // if the texture is busy and we then don't return true.
+ bool proceed = true;
if (m_owner && m_owner != owner)
- m_owner->removeTexture(this);
- m_owner = owner;
- owner->addOwned(this);
- return true;
+ proceed = m_owner->removeTexture(this);
+
+ if (proceed) {
+ m_owner = owner;
+ owner->addOwned(this);
+ return true;
+ }
}
return false;
}
-void BackedDoubleBufferedTexture::release(TextureOwner* owner)
+bool BackedDoubleBufferedTexture::release(TextureOwner* owner)
{
+ android::Mutex::Autolock lock(m_busyLock);
if (m_owner == owner) {
- m_owner->removeOwned(this);
- m_owner = 0;
+ if (!m_busy) {
+ m_owner->removeOwned(this);
+ m_owner = 0;
+ return true;
+ } else {
+ m_delayedRelease = true;
+ m_delayedReleaseOwner = owner;
+ }
}
-
+ return false;
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h
index eea5807..b1f170b 100644
--- a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h
+++ b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h
@@ -68,7 +68,7 @@ public:
// allows consumer thread to assign ownership of the texture to the tile. It
// returns false if ownership cannot be transferred because the tile is busy
bool acquire(TextureOwner* owner);
- void release(TextureOwner* owner);
+ bool release(TextureOwner* owner);
// set the texture owner if not busy. Return false if busy, true otherwise.
bool setOwner(TextureOwner* owner);
@@ -78,12 +78,19 @@ public:
SkCanvas* canvas(); // only used by the producer thread
bool busy();
+ void setNotBusy();
const SkSize& getSize() const { return m_size; }
+ int x() { return m_x; }
+ int y() { return m_y; }
+ void setTile(int x, int y) { m_x = x; m_y = y; }
+
private:
void destroyTextures(SharedTexture** textures);
+ int m_x;
+ int m_y;
SkBitmap* m_bitmap;
bool m_sharedBitmap;
SkSize m_size;
@@ -92,6 +99,12 @@ private:
SkBitmap::Config m_config;
TextureOwner* m_owner;
+ // When trying to release a texture, we may delay this if the texture is
+ // currently used (busy being painted). We use the following two variables
+ // to do so in setNotBusy()
+ TextureOwner* m_delayedReleaseOwner;
+ bool m_delayedRelease;
+
// This values signals that the texture is currently in use by the consumer.
// This allows us to prevent the owner of the texture from changing while the
// consumer is holding a lock on the texture.
diff --git a/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
index d7ea5e6..2f0e999 100644
--- a/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
+++ b/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
@@ -36,8 +36,6 @@
#include <wtf/CurrentTime.h>
#endif // USE(ACCELERATED_COMPOSITING)
-#define HARDWARE_ACCELERATION
-
#ifdef DEBUG
#include <cutils/log.h>
@@ -70,8 +68,9 @@ BaseLayerAndroid::BaseLayerAndroid()
BaseLayerAndroid::~BaseLayerAndroid()
{
-#ifdef HARDWARE_ACCELERATION
- TilesManager::instance()->removeOperationsForBaseLayer(this);
+#if USE(ACCELERATED_COMPOSITING)
+ if (TilesManager::hardwareAccelerationEnabled())
+ TilesManager::instance()->removeOperationsForBaseLayer(this);
#endif
m_content.clear();
#ifdef DEBUG_COUNT
@@ -312,6 +311,7 @@ bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect,
scale = m_glWebViewState->futureScale();
}
compositedRoot->setScale(scale);
+ compositedRoot->computeTextureSize();
compositedRoot->reserveGLTextures();
#ifdef DEBUG
diff --git a/WebCore/platform/graphics/android/BaseTile.cpp b/WebCore/platform/graphics/android/BaseTile.cpp
index 2753fb2..e5275c6 100644
--- a/WebCore/platform/graphics/android/BaseTile.cpp
+++ b/WebCore/platform/graphics/android/BaseTile.cpp
@@ -107,13 +107,14 @@ void BaseTile::reserveTexture()
m_texture = texture;
}
-void BaseTile::removeTexture(BackedDoubleBufferedTexture* texture)
+bool BaseTile::removeTexture(BackedDoubleBufferedTexture* texture)
{
XLOG("%x removeTexture res: %x... page %x", this, m_texture, m_page);
// We update atomically, so paintBitmap() can see the correct value
android::AutoMutex lock(m_atomicSync);
if (m_texture == texture)
m_texture = 0;
+ return true;
}
void BaseTile::setScale(float scale)
@@ -174,6 +175,9 @@ void BaseTile::draw(float transparency, SkRect& rect)
return;
}
+ if (m_texture->x() != m_x || m_texture->y() != m_y)
+ return;
+
TextureInfo* textureInfo = m_texture->consumerLock();
if (!textureInfo) {
XLOG("%x (%d, %d) trying to draw, but no textureInfo!", this, x(), y());
@@ -198,6 +202,20 @@ bool BaseTile::isTileReady()
return !m_dirty;
}
+void BaseTile::drawTileInfo(SkCanvas* canvas,
+ BackedDoubleBufferedTexture* texture,
+ int x, int y, float scale)
+{
+ SkPaint paint;
+ char str[256];
+ snprintf(str, 256, "(%d,%d) %.2f, tile %x, texture: %x",
+ x, y, scale, this, texture);
+ paint.setARGB(255, 0, 0, 0);
+ canvas->drawText(str, strlen(str), 50, 100, paint);
+ paint.setARGB(255, 255, 0, 0);
+ canvas->drawText(str, strlen(str), 51, 101, paint);
+}
+
// This is called from the texture generation thread
void BaseTile::paintBitmap()
{
@@ -218,6 +236,7 @@ void BaseTile::paintBitmap()
const int y = m_y;
TiledPage* tiledPage = m_page;
+ texture->producerAcquireContext();
TextureInfo* textureInfo = texture->producerLock();
// at this point we can safely check the ownership (if the texture got
@@ -227,8 +246,9 @@ void BaseTile::paintBitmap()
return;
}
- float tileWidth = textureInfo->m_width;
- float tileHeight = textureInfo->m_height;
+ SkSize size = texture->getSize();
+ float tileWidth = size.width();
+ float tileHeight = size.height();
const float invScale = 1 / scale;
float w = tileWidth * invScale;
@@ -255,8 +275,10 @@ void BaseTile::paintBitmap()
paint.setARGB(128, 0, 0, 255);
canvas->drawLine(0, 0, tileWidth, 0, paint);
canvas->drawLine(tileWidth, 0, tileWidth, tileHeight, paint);
+ drawTileInfo(canvas, texture, x, y, scale);
#endif
+ texture->setTile(x, y);
texture->producerUpdate(textureInfo);
m_atomicSync.lock();
diff --git a/WebCore/platform/graphics/android/BaseTile.h b/WebCore/platform/graphics/android/BaseTile.h
index d22849d..af7df3a 100644
--- a/WebCore/platform/graphics/android/BaseTile.h
+++ b/WebCore/platform/graphics/android/BaseTile.h
@@ -75,6 +75,9 @@ public:
// the only thread-safe function called by the background thread
void paintBitmap();
+ void drawTileInfo(SkCanvas* canvas,
+ BackedDoubleBufferedTexture* texture,
+ int x, int y, float scale);
void markAsDirty(const unsigned int pictureCount);
bool isDirty();
@@ -87,7 +90,7 @@ public:
BackedDoubleBufferedTexture* texture() { return m_texture; }
// TextureOwner implementation
- virtual void removeTexture(BackedDoubleBufferedTexture* texture);
+ virtual bool removeTexture(BackedDoubleBufferedTexture* texture);
virtual TiledPage* page() { return m_page; }
private:
diff --git a/WebCore/platform/graphics/android/GLWebViewState.cpp b/WebCore/platform/graphics/android/GLWebViewState.cpp
index 3c1d40a..5ba094b 100644
--- a/WebCore/platform/graphics/android/GLWebViewState.cpp
+++ b/WebCore/platform/graphics/android/GLWebViewState.cpp
@@ -108,9 +108,9 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const IntRect& rect)
// We only update the layers if we are not currently
// waiting for a tiledPage to be painted
if (m_baseLayerUpdate) {
+ layer->safeRef();
m_currentBaseLayer->safeUnref();
m_currentBaseLayer = layer;
- m_currentBaseLayer->safeRef();
}
inval(rect);
}
@@ -118,9 +118,9 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const IntRect& rect)
void GLWebViewState::unlockBaseLayerUpdate() {
m_baseLayerUpdate = true;
android::Mutex::Autolock lock(m_baseLayerLock);
+ m_baseLayer->safeRef();
m_currentBaseLayer->safeUnref();
m_currentBaseLayer = m_baseLayer;
- m_currentBaseLayer->safeRef();
inval(m_invalidateRect);
IntRect empty;
m_invalidateRect = empty;
@@ -287,6 +287,25 @@ void GLWebViewState::setViewport(SkRect& viewport, float scale)
static_cast<int>(floorf(viewport.fTop * invTileContentHeight)),
static_cast<int>(ceilf(viewport.fRight * invTileContentWidth)),
static_cast<int>(ceilf(viewport.fBottom * invTileContentHeight)));
+
+ int maxTextureCount = (m_viewportTileBounds.width() + TilesManager::instance()->expandedTileBoundsX() * 2 + 1) *
+ (m_viewportTileBounds.height() + TilesManager::instance()->expandedTileBoundsY() * 2 + 1) * 2;
+ TilesManager::instance()->setMaxTextureCount(maxTextureCount);
+ m_tiledPageA->updateBaseTileSize();
+ m_tiledPageB->updateBaseTileSize();
+}
+
+bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, float scale, SkColor color)
+{
+ m_baseLayerLock.lock();
+ BaseLayerAndroid* baseLayer = m_currentBaseLayer;
+ baseLayer->safeRef();
+ m_baseLayerLock.unlock();
+ if (!baseLayer)
+ return false;
+ bool ret = baseLayer->drawGL(rect, viewport, scale, color);
+ baseLayer->safeUnref();
+ return ret;
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/android/GLWebViewState.h b/WebCore/platform/graphics/android/GLWebViewState.h
index 7fa5e39..2082f2c 100644
--- a/WebCore/platform/graphics/android/GLWebViewState.h
+++ b/WebCore/platform/graphics/android/GLWebViewState.h
@@ -205,6 +205,9 @@ public:
return false;
}
+ bool drawGL(IntRect& rect, SkRect& viewport,
+ float scale, SkColor color = SK_ColorWHITE);
+
private:
void inval(const IntRect& rect); // caller must hold m_baseLayerLock
diff --git a/WebCore/platform/graphics/android/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp
index 5d6d8ff..bee423c 100644
--- a/WebCore/platform/graphics/android/LayerAndroid.cpp
+++ b/WebCore/platform/graphics/android/LayerAndroid.cpp
@@ -157,28 +157,31 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : SkLayer(),
#endif
}
-void LayerAndroid::removeTexture(BackedDoubleBufferedTexture* aTexture)
+bool LayerAndroid::removeTexture(BackedDoubleBufferedTexture* aTexture)
{
LayerTexture* texture = static_cast<LayerTexture*>(aTexture);
android::AutoMutex lock(m_atomicSync);
+
+ bool textureReleased = true;
if (!texture) { // remove ourself from both textures
if (m_drawingTexture)
- m_drawingTexture->release(this);
+ textureReleased &= m_drawingTexture->release(this);
if (m_reservedTexture &&
m_reservedTexture != m_drawingTexture)
- m_reservedTexture->release(this);
+ textureReleased &= m_reservedTexture->release(this);
} else {
if (m_drawingTexture && m_drawingTexture == texture)
- m_drawingTexture->release(this);
+ textureReleased &= m_drawingTexture->release(this);
if (m_reservedTexture &&
m_reservedTexture == texture &&
m_reservedTexture != m_drawingTexture)
- m_reservedTexture->release(this);
+ textureReleased &= m_reservedTexture->release(this);
}
if (m_drawingTexture && m_drawingTexture->owner() != this)
m_drawingTexture = 0;
if (m_reservedTexture && m_reservedTexture->owner() != this)
m_reservedTexture = 0;
+ return textureReleased;
}
LayerAndroid::~LayerAndroid()
@@ -585,7 +588,7 @@ bool LayerAndroid::needsTexture()
&& m_recordingPicture->width() && m_recordingPicture->height());
}
-IntRect LayerAndroid::clippedRect()
+IntRect LayerAndroid::clippedRect() const
{
IntRect r(0, 0, getWidth(), getHeight());
IntRect tr = drawTransform().mapRect(r);
@@ -600,10 +603,20 @@ bool LayerAndroid::outsideViewport()
m_layerTextureRect.height() == 0;
}
-int LayerAndroid::countTextureSize()
+int LayerAndroid::fullTextureSize() const
+{
+ return getWidth() * m_scale * getHeight() * m_scale * 4;
+}
+
+int LayerAndroid::clippedTextureSize() const
{
IntRect cr = clippedRect();
- int size = cr.width() * cr.height() * 4;
+ return cr.width() * cr.height() * 4;
+}
+
+int LayerAndroid::countTextureSize()
+{
+ int size = clippedTextureSize();
int count = this->countChildren();
for (int i = 0; i < count; i++)
size += getChild(i)->countTextureSize();
@@ -619,6 +632,69 @@ int LayerAndroid::nbLayers()
return nb;
}
+void LayerAndroid::collect(Vector<LayerAndroid*>& layers, int& size)
+{
+ m_layerTextureRect = clippedRect();
+ if (!outsideViewport()) {
+ layers.append(this);
+ size += fullTextureSize();
+ }
+ int count = this->countChildren();
+ for (int i = 0; i < count; i++)
+ getChild(i)->collect(layers, size);
+}
+
+static inline bool compareLayerFullSize(const LayerAndroid* a, const LayerAndroid* b)
+{
+ const int sizeA = a->fullTextureSize();
+ const int sizeB = b->fullTextureSize();
+ return sizeA > sizeB;
+}
+
+void LayerAndroid::computeTextureSize()
+{
+ // First, we collect the layers, computing m_layerTextureRect
+ // as being clipped against the viewport
+ Vector <LayerAndroid*> layers;
+ int total = 0;
+ collect(layers, total);
+
+ // Then we sort them by the size the full texture would need
+ std::stable_sort(layers.begin(), layers.end(), compareLayerFullSize);
+
+ // Now, let's determinate which layer can use a full texture
+ int max = TilesManager::instance()->maxLayersAllocation();
+ int maxLayerSize = TilesManager::instance()->maxLayerAllocation();
+ XLOG("*** layers sorted by size ***");
+ XLOG("total memory needed: %d bytes (%d Mb), max %d Mb",
+ total, total / 1024 / 1024, max / 1024 / 1024);
+ for (unsigned int i = 0; i < layers.size(); i++) {
+ LayerAndroid* layer = layers[i];
+ bool clipped = true;
+ // If we are under the maximum, and the layer inspected
+ // needs a texture less than the maxLayerSize, use the full texture.
+ if ((total < max) &&
+ (layer->fullTextureSize() < maxLayerSize) &&
+ (layer->getWidth() * m_scale < TilesManager::instance()->getMaxTextureSize()) &&
+ (layer->getHeight() * m_scale < TilesManager::instance()->getMaxTextureSize())) {
+ IntRect full(0, 0, layer->getWidth(), layer->getHeight());
+ layer->m_layerTextureRect = full;
+ clipped = false;
+ } else {
+ // Otherwise, the layer is clipped; update the total
+ total -= layer->fullTextureSize();
+ total += layer->clippedTextureSize();
+ }
+ XLOG("Layer %d (%.2f, %.2f) %d bytes (clipped: %s)",
+ layer->uniqueId(), layer->getWidth(), layer->getHeight(),
+ layer->fullTextureSize(),
+ clipped ? "YES" : "NO");
+ }
+ XLOG("total memory used after clipping: %d bytes (%d Mb), max %d Mb",
+ total, total / 1024 / 1024, max / 1024 / 1024);
+ XLOG("*** end of sorted layers ***");
+}
+
void LayerAndroid::showLayers(int indent)
{
IntRect cr = clippedRect();
@@ -655,14 +731,10 @@ void LayerAndroid::reserveGLTextures()
if (!needsTexture())
return;
- LayerTexture* reservedTexture = 0;
-
- // Compute the layer size & position we need (clipped to the viewport)
- m_layerTextureRect = clippedRect();
-
if (outsideViewport())
return;
+ LayerTexture* reservedTexture = 0;
reservedTexture = TilesManager::instance()->getExistingTextureForLayer(
this, m_layerTextureRect);
@@ -682,9 +754,11 @@ void LayerAndroid::reserveGLTextures()
android::AutoMutex lock(m_atomicSync);
// we set the reservedTexture if it's different from the drawing texture
if (m_reservedTexture != reservedTexture &&
- ((m_reservedTexture != m_drawingTexture) ||
+ ((reservedTexture != m_drawingTexture) ||
(m_reservedTexture == 0 && m_drawingTexture == 0))) {
- if (m_reservedTexture)
+ // Call release on the reserved texture if it is not the same as the
+ // drawing texture.
+ if (m_reservedTexture && (m_reservedTexture != m_drawingTexture))
m_reservedTexture->release(this);
m_reservedTexture = reservedTexture;
}
@@ -857,7 +931,7 @@ void LayerAndroid::paintBitmapGL()
// If LayerAndroid::removeTexture() is called before us, we'd have bailed
// out early as texture would have been null; if it is called after us, we'd
// have marked the texture has being busy, and the texture will not be
- // destroy immediately.
+ // destroyed immediately.
texture->producerAcquireContext();
TextureInfo* textureInfo = texture->producerLock();
m_atomicSync.unlock();
diff --git a/WebCore/platform/graphics/android/LayerAndroid.h b/WebCore/platform/graphics/android/LayerAndroid.h
index f4fea49..2cb56c1 100644
--- a/WebCore/platform/graphics/android/LayerAndroid.h
+++ b/WebCore/platform/graphics/android/LayerAndroid.h
@@ -94,7 +94,7 @@ public:
virtual ~LayerAndroid();
// TextureOwner methods
- virtual void removeTexture(BackedDoubleBufferedTexture* texture);
+ virtual bool removeTexture(BackedDoubleBufferedTexture* texture);
LayerTexture* texture() { return m_reservedTexture; }
virtual TiledPage* page() { return 0; }
@@ -102,7 +102,7 @@ public:
void setTransform(const TransformationMatrix& matrix) { m_transform = matrix; }
FloatPoint translation() const;
SkRect bounds() const;
- IntRect clippedRect();
+ IntRect clippedRect() const;
bool outsideViewport();
// Debug/info functions
@@ -110,6 +110,13 @@ public:
int nbLayers();
void showLayers(int indent = 0);
+ // Texture size functions
+ void computeTextureSize();
+ void collect(Vector<LayerAndroid*>& layers,
+ int& size);
+ int clippedTextureSize() const;
+ int fullTextureSize() const;
+
// called on the root layer
void reserveGLTextures();
void createGLTextures();
diff --git a/WebCore/platform/graphics/android/MediaLayer.cpp b/WebCore/platform/graphics/android/MediaLayer.cpp
index fac94f5..7a4c02d 100644
--- a/WebCore/platform/graphics/android/MediaLayer.cpp
+++ b/WebCore/platform/graphics/android/MediaLayer.cpp
@@ -40,11 +40,11 @@
namespace WebCore {
-MediaLayer::MediaLayer() : LayerAndroid(false)
+MediaLayer::MediaLayer(jobject weakWebViewRef) : LayerAndroid(false)
{
m_bufferedTexture = new MediaTexture(EGL_NO_CONTEXT);
m_bufferedTexture->incStrong(this);
- m_videoTexture = new VideoTexture();
+ m_videoTexture = new VideoTexture(weakWebViewRef);
m_videoTexture->incStrong(this);
m_currentTextureInfo = 0;
@@ -78,6 +78,8 @@ bool MediaLayer::drawGL(SkMatrix& matrix)
// draw any video content if present
m_videoTexture->drawVideo(drawTransform());
+ bool needsInval = true;
+
// draw the primary content
if (m_bufferedTexture) {
TextureInfo* textureInfo = m_bufferedTexture->consumerLock();
@@ -95,14 +97,13 @@ bool MediaLayer::drawGL(SkMatrix& matrix)
TilesManager::instance()->shader()->drawLayerQuad(m, rect,
textureInfo->m_textureId,
1.0f); //TODO fix this m_drawOpacity
+ if (!rect.isEmpty())
+ needsInval = false;
}
m_bufferedTexture->consumerRelease();
}
- drawChildrenGL(matrix);
-
- //TODO allow plugins to specify when they should be drawn
- return true;
+ return drawChildrenGL(matrix) || needsInval;
}
ANativeWindow* MediaLayer::acquireNativeWindowForVideo()
diff --git a/WebCore/platform/graphics/android/MediaLayer.h b/WebCore/platform/graphics/android/MediaLayer.h
index dec6427..15bd6d8 100644
--- a/WebCore/platform/graphics/android/MediaLayer.h
+++ b/WebCore/platform/graphics/android/MediaLayer.h
@@ -21,6 +21,7 @@
#include "MediaTexture.h"
#include "LayerAndroid.h"
+#include <jni.h>
namespace android {
class SurfaceTexture;
@@ -31,7 +32,7 @@ namespace WebCore {
class MediaLayer : public LayerAndroid {
public:
- MediaLayer();
+ MediaLayer(jobject weakWebViewRef);
MediaLayer(const MediaLayer& layer);
virtual ~MediaLayer();
diff --git a/WebCore/platform/graphics/android/MediaTexture.cpp b/WebCore/platform/graphics/android/MediaTexture.cpp
index 8481a20..a92b570 100644
--- a/WebCore/platform/graphics/android/MediaTexture.cpp
+++ b/WebCore/platform/graphics/android/MediaTexture.cpp
@@ -24,6 +24,8 @@
#include <gui/SurfaceTexture.h>
#include <gui/SurfaceTextureClient.h>
#include <wtf/CurrentTime.h>
+#include <JNIUtility.h>
+#include "WebCoreJni.h"
#define LAYER_DEBUG
#undef LAYER_DEBUG
@@ -45,8 +47,46 @@
namespace WebCore {
-VideoTexture::VideoTexture()
+class VideoListener : public android::SurfaceTexture::FrameAvailableListener {
+
+public:
+ VideoListener(jobject weakWebViewRef)
+ : m_weakWebViewRef(weakWebViewRef)
+ , m_postInvalMethod(0)
+ {
+ if (!m_weakWebViewRef)
+ return;
+
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ jobject localWebViewRef = env->NewLocalRef(m_weakWebViewRef);
+ if (localWebViewRef) {
+ jclass wvClass = env->GetObjectClass(localWebViewRef);
+ m_postInvalMethod = env->GetMethodID(wvClass, "postInvalidate", "()V");
+ env->DeleteLocalRef(wvClass);
+ env->DeleteLocalRef(localWebViewRef);
+ }
+ checkException(env);
+ }
+
+ virtual void onFrameAvailable()
+ {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ jobject localWebViewRef = env->NewLocalRef(m_weakWebViewRef);
+ if (localWebViewRef) {
+ env->CallVoidMethod(localWebViewRef, m_postInvalMethod);
+ env->DeleteLocalRef(localWebViewRef);
+ }
+ checkException(env);
+ }
+
+private:
+ jobject m_weakWebViewRef;
+ jmethodID m_postInvalMethod;
+};
+
+VideoTexture::VideoTexture(jobject weakWebViewRef) : android::LightRefBase<VideoTexture>()
{
+ m_weakWebViewRef = weakWebViewRef;
m_textureId = 0;
m_dimensions.setEmpty();
m_newWindowRequest = false;
@@ -58,6 +98,10 @@ VideoTexture::~VideoTexture()
releaseNativeWindow();
if (m_textureId)
glDeleteTextures(1, &m_textureId);
+ if (m_weakWebViewRef) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ env->DeleteWeakGlobalRef(m_weakWebViewRef);
+ }
}
void VideoTexture::initNativeWindowIfNeeded()
@@ -73,6 +117,11 @@ void VideoTexture::initNativeWindowIfNeeded()
m_surfaceTexture = new android::SurfaceTexture(m_textureId);
m_surfaceTextureClient = new android::SurfaceTextureClient(m_surfaceTexture);
+
+ //setup callback
+ sp<VideoListener> listener = new VideoListener(m_weakWebViewRef);
+ m_surfaceTexture->setFrameAvailableListener(listener);
+
m_newWindowRequest = false;
m_newWindowReady = true;
m_newVideoRequestCond.signal();
@@ -109,8 +158,23 @@ ANativeWindow* VideoTexture::requestNewWindow()
}
m_newWindowRequest = true;
+
+ // post an inval message to the UI thread to fulfill the request
+ if (m_weakWebViewRef) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ jobject localWebViewRef = env->NewLocalRef(m_weakWebViewRef);
+ if (localWebViewRef) {
+ jclass wvClass = env->GetObjectClass(localWebViewRef);
+ jmethodID postInvalMethod = env->GetMethodID(wvClass, "postInvalidate", "()V");
+ env->CallVoidMethod(localWebViewRef, postInvalMethod);
+ env->DeleteLocalRef(wvClass);
+ env->DeleteLocalRef(localWebViewRef);
+ }
+ checkException(env);
+ }
+
//block until the request can be fulfilled or we time out
- m_newVideoRequestCond.waitRelative(m_videoLock, 1000000000); // 1 sec
+ m_newVideoRequestCond.waitRelative(m_videoLock, 500000000); // .5 sec
if (m_surfaceTextureClient.get())
m_newWindowReady = false;
@@ -128,6 +192,11 @@ void VideoTexture::releaseNativeWindow()
{
android::Mutex::Autolock lock(m_videoLock);
m_dimensions.setEmpty();
+
+ if (m_surfaceTexture.get())
+ m_surfaceTexture->setFrameAvailableListener(0);
+
+ // clear the strong pointer references
m_surfaceTextureClient.clear();
m_surfaceTexture.clear();
}
diff --git a/WebCore/platform/graphics/android/MediaTexture.h b/WebCore/platform/graphics/android/MediaTexture.h
index 156a67f..189905c 100644
--- a/WebCore/platform/graphics/android/MediaTexture.h
+++ b/WebCore/platform/graphics/android/MediaTexture.h
@@ -23,6 +23,7 @@
#include "DoubleBufferedTexture.h"
#include "LayerAndroid.h"
#include <utils/RefBase.h>
+#include <jni.h>
namespace android {
class SurfaceTexture;
@@ -40,7 +41,7 @@ public:
class VideoTexture : public android::LightRefBase<VideoTexture> {
public:
- VideoTexture();
+ VideoTexture(jobject weakWebViewRef);
~VideoTexture();
void initNativeWindowIfNeeded();
@@ -60,6 +61,8 @@ private:
bool m_newWindowRequest;
bool m_newWindowReady;
+ jobject m_weakWebViewRef;
+
android::Mutex m_videoLock;
android::Condition m_newVideoRequestCond;
};
diff --git a/WebCore/platform/graphics/android/ShaderProgram.cpp b/WebCore/platform/graphics/android/ShaderProgram.cpp
index 8da6855..c4129f1 100644
--- a/WebCore/platform/graphics/android/ShaderProgram.cpp
+++ b/WebCore/platform/graphics/android/ShaderProgram.cpp
@@ -140,8 +140,6 @@ GLuint ShaderProgram::createProgram(const char* pVertexSource, const char* pFrag
}
glDeleteProgram(program);
program = -1;
- } else {
- XLOG("couldn't link the shader!");
}
}
return program;
@@ -156,15 +154,21 @@ void ShaderProgram::init()
{
m_program = createProgram(gVertexShader, gFragmentShader);
m_videoProgram = createProgram(gVideoVertexShader, gVideoFragmentShader);
+ if (m_program == -1 || m_videoProgram == -1)
+ return;
m_hProjectionMatrix = glGetUniformLocation(m_program, "projectionMatrix");
m_hAlpha = glGetUniformLocation(m_program, "alpha");
m_hTexSampler = glGetUniformLocation(m_program, "s_texture");
+ m_hPosition = glGetAttribLocation(m_program, "vPosition");
+
m_hVideoProjectionMatrix = glGetUniformLocation(m_videoProgram, "projectionMatrix");
m_hVideoTextureMatrix = glGetUniformLocation(m_videoProgram, "textureMatrix");
m_hVideoTexSampler = glGetUniformLocation(m_videoProgram, "s_yuvTexture");
+ m_hVideoPosition = glGetAttribLocation(m_program, "vPosition");
+
const GLfloat coord[] = {
0.0f, 0.0f, // C
1.0f, 0.0f, // D
@@ -214,9 +218,8 @@ void ShaderProgram::drawQuad(SkRect& geometry, int textureId, float opacity)
glBindTexture(GL_TEXTURE_2D, textureId);
glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
- glBindAttribLocation(program(), 1, "vPosition");
+ glEnableVertexAttribArray(m_hPosition);
+ glVertexAttribPointer(m_hPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
glUniform1f(alpha(), opacity);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
@@ -290,9 +293,8 @@ void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix,
glBindTexture(GL_TEXTURE_2D, textureId);
glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
- glBindAttribLocation(program(), 1, "vPosition");
+ glEnableVertexAttribArray(m_hPosition);
+ glVertexAttribPointer(m_hPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
glUniform1f(alpha(), opacity);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
@@ -318,9 +320,8 @@ void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix,
glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
- glBindAttribLocation(m_videoProgram, 1, "vPosition");
+ glEnableVertexAttribArray(m_hVideoPosition);
+ glVertexAttribPointer(m_hVideoPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
diff --git a/WebCore/platform/graphics/android/ShaderProgram.h b/WebCore/platform/graphics/android/ShaderProgram.h
index 1f94290..5e2045c 100644
--- a/WebCore/platform/graphics/android/ShaderProgram.h
+++ b/WebCore/platform/graphics/android/ShaderProgram.h
@@ -72,6 +72,10 @@ class ShaderProgram {
int m_hVideoProjectionMatrix;
int m_hVideoTextureMatrix;
int m_hVideoTexSampler;
+
+ // attribs
+ GLint m_hPosition;
+ GLint m_hVideoPosition;
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/android/TextureOwner.h b/WebCore/platform/graphics/android/TextureOwner.h
index c421e8a..684efac 100644
--- a/WebCore/platform/graphics/android/TextureOwner.h
+++ b/WebCore/platform/graphics/android/TextureOwner.h
@@ -36,7 +36,7 @@ class BackedDoubleBufferedTexture;
class TextureOwner {
public:
virtual ~TextureOwner();
- virtual void removeTexture(BackedDoubleBufferedTexture* texture) = 0;
+ virtual bool removeTexture(BackedDoubleBufferedTexture* texture) = 0;
virtual TiledPage* page() = 0;
void addOwned(BackedDoubleBufferedTexture*);
diff --git a/WebCore/platform/graphics/android/TexturesGenerator.cpp b/WebCore/platform/graphics/android/TexturesGenerator.cpp
index cdf4b5a..5b9c809 100644
--- a/WebCore/platform/graphics/android/TexturesGenerator.cpp
+++ b/WebCore/platform/graphics/android/TexturesGenerator.cpp
@@ -126,10 +126,6 @@ void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter)
status_t TexturesGenerator::readyToRun()
{
- TilesManager::instance()->enableTextures();
- XLOG("Textures enabled (context acquired...)");
- TilesManager::instance()->paintTexturesDefault();
- XLOG("Textures painted");
TilesManager::instance()->markGeneratorAsReady();
XLOG("Thread ready to run");
return NO_ERROR;
diff --git a/WebCore/platform/graphics/android/TiledPage.cpp b/WebCore/platform/graphics/android/TiledPage.cpp
index 68f38ab..620aa6f 100644
--- a/WebCore/platform/graphics/android/TiledPage.cpp
+++ b/WebCore/platform/graphics/android/TiledPage.cpp
@@ -49,18 +49,30 @@
#endif // DEBUG
+#define MAX_TILES 256
+
namespace WebCore {
using namespace android;
TiledPage::TiledPage(int id, GLWebViewState* state)
- : m_id(id)
+ : m_baseTiles(0)
+ , m_baseTileSize(0)
+ , m_id(id)
, m_scale(1)
, m_invScale(1)
, m_glWebViewState(state)
, m_latestPictureInval(0)
, m_prepare(false)
{
+ m_baseTiles = new BaseTile[MAX_TILES];
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->increment("TiledPage");
+#endif
+}
+
+void TiledPage::updateBaseTileSize()
+{
// This value must be at least 1 greater than the max number of allowed
// textures. This is because prepare() asks for a tile before it reserves
// a texture for that tile. If all textures are currently in use by the
@@ -69,12 +81,10 @@ TiledPage::TiledPage(int id, GLWebViewState* state)
// to reserveTexture() will cause some other tile in the page to lose it's
// texture and become available, thus ensuring that we always have at least
// one tile that is available.
- m_baseTileSize = TilesManager::maxTextureCount() + 1;
- m_baseTiles = new BaseTile[m_baseTileSize];
-
-#ifdef DEBUG_COUNT
- ClassTracker::instance()->increment("TiledPage");
-#endif
+ int baseTileSize = TilesManager::instance()->maxTextureCount() + 1;
+ if (baseTileSize > m_baseTileSize)
+ m_baseTileSize = baseTileSize;
+ XLOG("Allocate %d tiles", m_baseTileSize);
}
TiledPage::~TiledPage()
@@ -154,18 +164,20 @@ void TiledPage::prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y
availableTile = &tile;
}
- if (!currentTile) {
+ if (!currentTile && availableTile) {
currentTile = availableTile;
currentTile->setContents(this, x, y);
}
- currentTile->setScale(m_scale);
+ if (currentTile) {
+ currentTile->setScale(m_scale);
- // ensure there is a texture associated with the tile and then check to
- // see if the texture is dirty and in need of repainting
- currentTile->reserveTexture();
- if (currentTile->isDirty())
- set->add(currentTile);
+ // ensure there is a texture associated with the tile and then check to
+ // see if the texture is dirty and in need of repainting
+ currentTile->reserveTexture();
+ if (currentTile->isDirty())
+ set->add(currentTile);
+ }
}
}
@@ -210,7 +222,6 @@ void TiledPage::updateTileState(const SkIRect& tileBounds)
int d = std::max(dx, dy);
- XLOG("setTileLevel tile: %x, fxy(%d, %d), level: %d", tile, tileBounds.fLeft, tileBounds.fTop, d);
tile.setUsedLevel(d);
}
@@ -233,43 +244,29 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound
int nbTilesWidth = tileBounds.width();
int nbTilesHeight = tileBounds.height();
- const int lastTileX = tileBounds.fRight - 1;
- const int lastTileY = tileBounds.fBottom - 1;
+ int lastTileX = tileBounds.fRight - 1;
+ int lastTileY = tileBounds.fBottom - 1;
const int baseContentHeight = m_glWebViewState->baseContentHeight();
const int baseContentWidth = m_glWebViewState->baseContentWidth();
TileSet* highResSet = new TileSet(this, nbTilesHeight, nbTilesWidth);
+ // Expand number of tiles to allow tiles outside of viewport to be prepared for
+ // smoother scrolling.
int nTilesToPrepare = nbTilesWidth * nbTilesHeight;
int nMaxTilesPerPage = m_baseTileSize / 2;
-
- // PREPARE OFF-SCREEN TILES FOR SMOOTHER SCROLLING
- // if you are going down and you are not already at the bottom of the page
- // go ahead and prepare the tiles just off-screen beneath the viewport.
- // Ensure we have enough tiles to do this with.
- if (nTilesToPrepare + nbTilesWidth <= nMaxTilesPerPage) {
- if (goingDown && baseContentHeight > lastTileY * TilesManager::tileHeight())
- nbTilesHeight++;
- // if you are going up and you are not already at the top of the page go
- // ahead and prepare the tiles just off-screen above the viewport.
- else if (!goingDown && firstTileY > 0) {
- firstTileY--;
- nbTilesHeight++;
- }
+ int expandX = TilesManager::instance()->expandedTileBoundsX();
+ int expandY = TilesManager::instance()->expandedTileBoundsY();
+ if (nTilesToPrepare + (nbTilesHeight * expandX * 2) <= nMaxTilesPerPage) {
+ firstTileX -= expandX;
+ lastTileX += expandX;
+ nbTilesWidth += expandX * 2;
}
-
- if (nTilesToPrepare + nbTilesHeight <= nMaxTilesPerPage) {
- // if you are going right and you are not already at the edge of the page go
- // ahead and prepare the tiles just off-screen to the right of the viewport.
- if (!goingLeft && baseContentWidth > lastTileX * TilesManager::tileWidth())
- nbTilesWidth++;
- // if you are going left and you are not already at the edge of the page go
- // ahead and prepare the tiles just off-screen to the left of the viewport.
- else if (goingLeft && firstTileX > 0) {
- firstTileX--;
- nbTilesWidth++;
- }
+ if (nTilesToPrepare + (nbTilesWidth * expandY * 2) <= nMaxTilesPerPage) {
+ firstTileY -= expandY;
+ lastTileY += expandY;
+ nbTilesHeight += expandY * 2;
}
// We chose to prepare tiles depending on the scroll direction. Tiles are
@@ -320,10 +317,16 @@ void TiledPage::draw(float transparency, const SkIRect& tileBounds)
const float tileWidth = TilesManager::tileWidth() * m_invScale;
const float tileHeight = TilesManager::tileHeight() * m_invScale;
+ SkIRect actualTileBounds = tileBounds;
+ actualTileBounds.fTop -= TilesManager::instance()->expandedTileBoundsY();
+ actualTileBounds.fBottom += TilesManager::instance()->expandedTileBoundsY();
+ actualTileBounds.fLeft -= TilesManager::instance()->expandedTileBoundsX();
+ actualTileBounds.fRight += TilesManager::instance()->expandedTileBoundsX();
+
XLOG("WE DRAW %x (%.2f) with transparency %.2f", this, scale(), transparency);
for (int j = 0; j < m_baseTileSize; j++) {
BaseTile& tile = m_baseTiles[j];
- if (tileBounds.contains(tile.x(), tile.y())) {
+ if (actualTileBounds.contains(tile.x(), tile.y())) {
SkRect rect;
rect.fLeft = tile.x() * tileWidth;
diff --git a/WebCore/platform/graphics/android/TiledPage.h b/WebCore/platform/graphics/android/TiledPage.h
index 6424f34..e449107 100644
--- a/WebCore/platform/graphics/android/TiledPage.h
+++ b/WebCore/platform/graphics/android/TiledPage.h
@@ -73,6 +73,8 @@ public:
void invalidateRect(const IntRect& invalRect, const unsigned int pictureCount);
void setUsable(bool usable);
+ void updateBaseTileSize();
+
private:
void updateTileState(const SkIRect& tileBounds);
void prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y, TileSet* set);
diff --git a/WebCore/platform/graphics/android/TilesManager.cpp b/WebCore/platform/graphics/android/TilesManager.cpp
index 4b53a54..571d9cc 100644
--- a/WebCore/platform/graphics/android/TilesManager.cpp
+++ b/WebCore/platform/graphics/android/TilesManager.cpp
@@ -54,20 +54,34 @@
// one viewport, otherwise the allocation may stall.
// We need n textures for one TiledPage, and another n textures for the
// second page used when scaling.
-// In our case, we use 300x300 textures. On the tablet, this equals to
-// at least 24 (6 * 4) textures, hence 48.
-#define MAX_TEXTURE_ALLOCATION 48
+// In our case, we use 300x300 textures. On the tablet, this equates to
+// at least 5 * 3 = 15 textures. We can also enable offscreen textures
+#define EXPANDED_TILE_BOUNDS_X 1
+#define EXPANDED_TILE_BOUNDS_Y 4
+#define MAX_TEXTURE_ALLOCATION (5+EXPANDED_TILE_BOUNDS_X*2)*(3+EXPANDED_TILE_BOUNDS_Y*2)*2
#define TILE_WIDTH 300
#define TILE_HEIGHT 300
// Define a maximum amount of ram used by layers
-#define MAX_LAYERS_ALLOCATION 20971520 // 20Mb
+#define MAX_LAYERS_ALLOCATION 33554432 // 32Mb
+// Define a maximum amount of ram used by one layer
+#define MAX_LAYER_ALLOCATION 8388608 // 8Mb
#define BYTES_PER_PIXEL 4 // 8888 config
namespace WebCore {
+GLint TilesManager::getMaxTextureSize()
+{
+ static GLint maxTextureSize = 0;
+ if (!maxTextureSize)
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
+ return maxTextureSize;
+}
+
TilesManager::TilesManager()
: m_layersMemoryUsage(0)
+ , m_maxTextureCount(0)
+ , m_expandedTileBounds(false)
, m_generatorReady(false)
{
XLOG("TilesManager ctor");
@@ -76,33 +90,27 @@ TilesManager::TilesManager()
m_tilesBitmap->setConfig(SkBitmap::kARGB_8888_Config, tileWidth(), tileHeight());
m_tilesBitmap->allocPixels();
m_tilesBitmap->eraseColor(0);
- for (int i = 0; i < MAX_TEXTURE_ALLOCATION; i++) {
- BackedDoubleBufferedTexture* texture = new BackedDoubleBufferedTexture(
- tileWidth(), tileHeight(), m_tilesBitmap);
- // the atomic load ensures that the texture has been fully initialized
- // before we pass a pointer for other threads to operate on
- m_textures.append(reinterpret_cast<BackedDoubleBufferedTexture*>(
- android_atomic_acquire_load(reinterpret_cast<int32_t*>(&texture))));
- }
- XLOG("TilesManager ctor - init textures done");
-
m_pixmapsGenerationThread = new TexturesGenerator();
m_pixmapsGenerationThread->run("TexturesGenerator");
-
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
- m_totalMaxTextureSize = m_maxTextureSize * m_maxTextureSize * BYTES_PER_PIXEL;
- XLOG("Max texture size %d", m_maxTextureSize);
}
-// Has to be run on the texture generation threads
-void TilesManager::enableTextures()
+void TilesManager::allocateTiles()
{
- android::Mutex::Autolock lock(m_texturesLock);
- for (unsigned int i = 0; i < m_textures.size(); i++) {
- BackedDoubleBufferedTexture* texture = m_textures[i];
- texture->producerAcquireContext();
+ int nbTexturesToAllocate = m_maxTextureCount - m_textures.size();
+ XLOG("%d tiles to allocate (%d textures planned)", nbTexturesToAllocate, m_maxTextureCount);
+ int nbTexturesAllocated = 0;
+ for (int i = 0; i < nbTexturesToAllocate; i++) {
+ BackedDoubleBufferedTexture* texture = new BackedDoubleBufferedTexture(
+ tileWidth(), tileHeight(), m_tilesBitmap);
+ // the atomic load ensures that the texture has been fully initialized
+ // before we pass a pointer for other threads to operate on
+ BackedDoubleBufferedTexture* loadedTexture =
+ reinterpret_cast<BackedDoubleBufferedTexture*>(
+ android_atomic_acquire_load(reinterpret_cast<int32_t*>(&texture)));
+ m_textures.append(loadedTexture);
+ nbTexturesAllocated++;
}
- XLOG("enableTextures");
+ XLOG("allocated %d textures", nbTexturesAllocated);
}
void TilesManager::printTextures()
@@ -128,36 +136,6 @@ void TilesManager::printTextures()
#endif // DEBUG
}
-void TilesManager::paintTexturesDefault()
-{
- android::Mutex::Autolock lock(m_texturesLock);
- for (unsigned int i = 0; i < m_textures.size(); i++) {
- for (int j = 0; j < 2; j++) {
- BackedDoubleBufferedTexture* texture = m_textures[i];
- TextureInfo* textureInfo = texture->producerLock();
- SkCanvas* canvas = texture->canvas();
-#ifdef DEBUG
- if (j)
- canvas->drawARGB(255, 0, 0, 255);
- else
- canvas->drawARGB(255, 255, 0, 255);
- SkPaint paint;
- paint.setARGB(128, 255, 0, 0);
- paint.setStrokeWidth(3);
- canvas->drawLine(0, 0, tileWidth(), tileHeight(), paint);
- paint.setARGB(128, 0, 255, 0);
- canvas->drawLine(0, tileHeight(), tileWidth(), 0, paint);
- paint.setARGB(128, 0, 0, 255);
- canvas->drawLine(0, 0, tileWidth(), 0, paint);
- canvas->drawLine(tileWidth(), 0, tileWidth(), tileHeight(), paint);
-#else
- canvas->drawARGB(255, 255, 255, 255);
-#endif // DEBUG
- texture->producerUpdate(textureInfo);
- }
- }
-}
-
void TilesManager::resetTextureUsage(TiledPage* page)
{
android::Mutex::Autolock lock(m_texturesLock);
@@ -340,11 +318,13 @@ LayerTexture* TilesManager::createTextureForLayer(LayerAndroid* layer, const Int
unsigned int size = w * h * BYTES_PER_PIXEL;
// We will not allocate textures that:
- // 1) cannot be handled by the graphic card (m_maxTextureSize &
- // m_totalMaxTextureSize)
+ // 1) cannot be handled by the graphic card (maxTextureSize &
+ // totalMaxTextureSize)
// 2) will make us go past our texture limit (MAX_LAYERS_ALLOCATION)
- bool large = w > m_maxTextureSize || h > m_maxTextureSize || size > m_totalMaxTextureSize;
+ GLint maxTextureSize = getMaxTextureSize();
+ unsigned totalMaxTextureSize = maxTextureSize * maxTextureSize * BYTES_PER_PIXEL;
+ bool large = w > maxTextureSize || h > maxTextureSize || size > totalMaxTextureSize;
XLOG("createTextureForLayer(%d) @scale %.2f => %d, %d (too large? %x)", layer->uniqueId(),
layer->getScale(), w, h, large);
@@ -370,9 +350,31 @@ LayerTexture* TilesManager::createTextureForLayer(LayerAndroid* layer, const Int
return texture;
}
+int TilesManager::maxLayersAllocation()
+{
+ return MAX_LAYERS_ALLOCATION;
+}
+
+int TilesManager::maxLayerAllocation()
+{
+ return MAX_LAYER_ALLOCATION;
+}
+
int TilesManager::maxTextureCount()
{
- return MAX_TEXTURE_ALLOCATION;
+ android::Mutex::Autolock lock(m_texturesLock);
+ return m_maxTextureCount;
+}
+
+void TilesManager::setMaxTextureCount(int max)
+{
+ XLOG("setMaxTextureCount: %d", max);
+ if (m_maxTextureCount >= max && m_maxTextureCount)
+ return;
+
+ android::Mutex::Autolock lock(m_texturesLock);
+ m_maxTextureCount = max;
+ allocateTiles();
}
float TilesManager::tileWidth()
@@ -385,6 +387,14 @@ float TilesManager::tileHeight()
return TILE_HEIGHT;
}
+int TilesManager::expandedTileBoundsX() {
+ return m_expandedTileBounds ? EXPANDED_TILE_BOUNDS_X : 0;
+}
+
+int TilesManager::expandedTileBoundsY() {
+ return m_expandedTileBounds ? EXPANDED_TILE_BOUNDS_Y : 0;
+}
+
TilesManager* TilesManager::instance()
{
if (!gInstance) {
diff --git a/WebCore/platform/graphics/android/TilesManager.h b/WebCore/platform/graphics/android/TilesManager.h
index 6cd8bcd..eeb38fe 100644
--- a/WebCore/platform/graphics/android/TilesManager.h
+++ b/WebCore/platform/graphics/android/TilesManager.h
@@ -44,6 +44,12 @@ class TileSet;
class TilesManager {
public:
static TilesManager* instance();
+ static GLint getMaxTextureSize();
+
+ static bool hardwareAccelerationEnabled()
+ {
+ return gInstance != 0;
+ }
void removeOperationsForPage(TiledPage* page)
{
@@ -83,14 +89,23 @@ public:
}
void printTextures();
- void enableTextures();
void resetTextureUsage(TiledPage* page);
- void paintTexturesDefault();
- static int maxTextureCount();
+ int maxLayersAllocation();
+ int maxLayerAllocation();
+ int maxTextureCount();
+ void setMaxTextureCount(int max);
static float tileWidth();
static float tileHeight();
+ int expandedTileBoundsX();
+ int expandedTileBoundsY();
+
+ void allocateTiles();
+
+ void setExpandedTileBounds(bool enabled) {
+ m_expandedTileBounds = enabled;
+ }
private:
@@ -107,8 +122,9 @@ private:
Vector<LayerTexture*> m_layersTextures;
unsigned int m_layersMemoryUsage;
- GLint m_maxTextureSize;
- unsigned int m_totalMaxTextureSize;
+
+ int m_maxTextureCount;
+ bool m_expandedTileBounds;
bool m_generatorReady;
diff --git a/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp
index fe78fd5..ebd7d54 100644
--- a/WebCore/rendering/RenderBox.cpp
+++ b/WebCore/rendering/RenderBox.cpp
@@ -39,7 +39,9 @@
#include "FloatQuad.h"
#include "Frame.h"
#include "Page.h"
+#if PLATFORM(ANDROID)
#include "PlatformBridge.h"
+#endif
#include "RenderArena.h"
#include "RenderFlexibleBox.h"
#include "RenderInline.h"
@@ -2078,13 +2080,14 @@ void RenderBox::computeBlockDirectionMargins(RenderBlock* containingBlock)
int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* containingBlock) const
{
+#if PLATFORM(ANDROID)
// Fixed element's position should be decided by the visible screen size.
// That is in the doc coordindate.
if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
const RenderView* view = toRenderView(containingBlock);
- return PlatformBridge::visibleScreenWidth(view->frameView());
+ return PlatformBridge::screenWidthInDocCoord(view->frameView());
}
-
+#endif
if (containingBlock->isBox()) {
const RenderBox* containingBlockBox = toRenderBox(containingBlock);
return containingBlockBox->width() - containingBlockBox->borderLeft() - containingBlockBox->borderRight() - containingBlockBox->verticalScrollbarWidth();
@@ -2114,14 +2117,15 @@ int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* con
}
int RenderBox::containingBlockHeightForPositioned(const RenderBoxModelObject* containingBlock) const
-{
+{
+#if PLATFORM(ANDROID)
// Fixed element's position should be decided by the visible screen size.
// That is in the doc coordindate.
if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
const RenderView* view = toRenderView(containingBlock);
- return PlatformBridge::visibleScreenHeight(view->frameView());
+ return PlatformBridge::screenHeightInDocCoord(view->frameView());
}
-
+#endif
int heightResult = 0;
if (containingBlock->isBox())
heightResult = toRenderBox(containingBlock)->height();
diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp
index 1b1273e..559f25c 100644
--- a/WebCore/rendering/RenderLayer.cpp
+++ b/WebCore/rendering/RenderLayer.cpp
@@ -2180,7 +2180,8 @@ RenderLayer::updateScrollInfoAfterLayout()
m_hasOverflowScroll = hasOverflowScroll;
dirtyZOrderLists();
dirtyStackingContextZOrderLists();
- renderer()->node()->setNeedsStyleRecalc(SyntheticStyleChange);
+ if (renderer()->node())
+ renderer()->node()->setNeedsStyleRecalc(SyntheticStyleChange);
}
#endif
}
diff --git a/WebCore/rendering/RenderTheme.cpp b/WebCore/rendering/RenderTheme.cpp
index 522bd4d..538b6c6 100644
--- a/WebCore/rendering/RenderTheme.cpp
+++ b/WebCore/rendering/RenderTheme.cpp
@@ -198,7 +198,7 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El
return adjustTextFieldStyle(selector, style, e);
case TextAreaPart:
return adjustTextAreaStyle(selector, style, e);
-#ifdef ANDROID_LISTBOX_USES_MENU_LIST
+#if ENABLE(NO_LISTBOX_RENDERING)
case ListboxPart:
return adjustListboxStyle(selector, style, e);
#endif
diff --git a/WebCore/rendering/RenderTheme.h b/WebCore/rendering/RenderTheme.h
index aedb8eb..13c69e6 100644
--- a/WebCore/rendering/RenderTheme.h
+++ b/WebCore/rendering/RenderTheme.h
@@ -236,7 +236,7 @@ protected:
virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&) { return true; }
-#ifdef ANDROID_LISTBOX_USES_MENU_LIST
+#if ENABLE(NO_LISTBOX_RENDERING)
virtual void adjustListboxStyle(CSSStyleSelector*, RenderStyle*, Element*) const {}
#endif
virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
index f0958d9..fb5701a 100644
--- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
@@ -536,7 +536,7 @@ bool ChromeClientAndroid::selectItemWritingDirectionIsNatural()
PassRefPtr<PopupMenu> ChromeClientAndroid::createPopupMenu(PopupMenuClient* client) const
{
- return adoptRef(new PopupMenuAndroid(client));
+ return adoptRef(new PopupMenuAndroid(static_cast<ListPopupMenuClient*>(client)));
}
PassRefPtr<SearchPopupMenu> ChromeClientAndroid::createSearchPopupMenu(PopupMenuClient*) const
diff --git a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
index cc21dad..535c0da 100644
--- a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
@@ -577,6 +577,12 @@ void FrameLoaderClientAndroid::dispatchWillSubmitForm(FramePolicyFunction func,
(m_frame->loader()->policyChecker()->*func)(PolicyUse);
}
+void FrameLoaderClientAndroid::dispatchWillSendSubmitEvent(HTMLFormElement* form)
+{
+ if (m_webFrame->shouldSaveFormData())
+ m_webFrame->saveFormData(form);
+}
+
void FrameLoaderClientAndroid::dispatchDidLoadMainResource(DocumentLoader*) {
notImplemented();
}
diff --git a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h
index 964ac6e..034333e 100644
--- a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h
+++ b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h
@@ -223,7 +223,7 @@ namespace android {
void enableOnDemandPlugins() { m_onDemandPluginsEnabled = true; }
void dispatchDidChangeIcons();
- void dispatchWillSendSubmitEvent(HTMLFormElement*) { }
+ void dispatchWillSendSubmitEvent(HTMLFormElement*);
private:
CacheBuilder m_cacheBuilder;
Frame* m_frame;
diff --git a/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/WebKit/android/WebCoreSupport/PlatformBridge.cpp
index b34ff8c..8d8d809 100644
--- a/WebKit/android/WebCoreSupport/PlatformBridge.cpp
+++ b/WebKit/android/WebCoreSupport/PlatformBridge.cpp
@@ -160,16 +160,16 @@ FloatRect PlatformBridge::screenRect()
}
// The visible size on screen in document coordinate
-int PlatformBridge::visibleScreenWidth(const WebCore::FrameView* frameView)
+int PlatformBridge::screenWidthInDocCoord(const WebCore::FrameView* frameView)
{
android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView);
- return webViewCore->visibleScreenWidth();
+ return webViewCore->screenWidth();
}
-int PlatformBridge::visibleScreenHeight(const WebCore::FrameView* frameView)
+int PlatformBridge::screenHeightInDocCoord(const WebCore::FrameView* frameView)
{
android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView);
- return webViewCore->visibleScreenHeight();
+ return webViewCore->screenHeight();
}
String PlatformBridge::computeDefaultLanguage()
diff --git a/WebKit/android/WebCoreSupport/WebCookieJar.cpp b/WebKit/android/WebCoreSupport/WebCookieJar.cpp
index d290b5a..9c1d7fa 100644
--- a/WebKit/android/WebCoreSupport/WebCookieJar.cpp
+++ b/WebKit/android/WebCoreSupport/WebCookieJar.cpp
@@ -37,6 +37,8 @@
namespace android {
static WTF::Mutex instanceMutex;
+static bool isFirstInstanceCreated = false;
+static bool fileSchemeCookiesEnabled = false;
static const std::string& databaseDirectory()
{
@@ -99,6 +101,9 @@ scoped_refptr<WebCookieJar>* instance(bool isPrivateBrowsing)
WebCookieJar* WebCookieJar::get(bool isPrivateBrowsing)
{
MutexLocker lock(instanceMutex);
+ if (!isFirstInstanceCreated && fileSchemeCookiesEnabled)
+ net::CookieMonster::EnableFileScheme();
+ isFirstInstanceCreated = true;
scoped_refptr<WebCookieJar>* instancePtr = instance(isPrivateBrowsing);
if (!instancePtr->get())
*instancePtr = new WebCookieJar(databaseDirectory(isPrivateBrowsing));
@@ -117,9 +122,6 @@ void WebCookieJar::cleanup(bool isPrivateBrowsing)
WebCookieJar::WebCookieJar(const std::string& databaseFilePath)
: m_allowCookies(true)
{
- // This is needed for the page cycler. See http://b/2944150
- net::CookieMonster::EnableFileScheme();
-
// Setup the permissions for the file
const char* cDatabasePath = databaseFilePath.c_str();
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
@@ -130,6 +132,7 @@ WebCookieJar::WebCookieJar(const std::string& databaseFilePath)
if (fd >= 0)
close(fd);
}
+
FilePath cookiePath(databaseFilePath.c_str());
m_cookieDb = new SQLitePersistentCookieStore(cookiePath);
m_cookieStore = new net::CookieMonster(m_cookieDb.get(), 0);
@@ -227,4 +230,22 @@ void WebCookieJar::flush()
semaphore->Wait(2);
}
+bool WebCookieJar::acceptFileSchemeCookies()
+{
+ MutexLocker lock(instanceMutex);
+ return fileSchemeCookiesEnabled;
+}
+
+void WebCookieJar::setAcceptFileSchemeCookies(bool accept)
+{
+ // The Chromium HTTP stack only reflects changes to this flag when creating
+ // a new CookieMonster instance. While we could track whether any
+ // CookieMonster instances currently exist, this would be complicated and is
+ // not required, so we only allow this flag to be changed before the first
+ // instance is created.
+ MutexLocker lock(instanceMutex);
+ if (!isFirstInstanceCreated)
+ fileSchemeCookiesEnabled = accept;
+}
+
}
diff --git a/WebKit/android/WebCoreSupport/WebCookieJar.h b/WebKit/android/WebCoreSupport/WebCookieJar.h
index 2f32e1a..1f4266c 100644
--- a/WebKit/android/WebCoreSupport/WebCookieJar.h
+++ b/WebKit/android/WebCoreSupport/WebCookieJar.h
@@ -49,6 +49,12 @@ public:
bool allowCookies();
void setAllowCookies(bool allow);
+ // Getter and setter for whether we accept cookies for file scheme URLS.
+ // Defaults to false. Note that calls to the setter are ignored once the
+ // first instance of this class has been created.
+ static bool acceptFileSchemeCookies();
+ static void setAcceptFileSchemeCookies(bool);
+
// Instead of this it would probably be better to add the cookie methods
// here so the rest of WebKit doesn't have to know about Chromium classes
net::CookieStore* cookieStore() { return m_cookieStore.get(); }
diff --git a/WebKit/android/WebCoreSupport/WebRequest.cpp b/WebKit/android/WebCoreSupport/WebRequest.cpp
index e44b600..a14036f 100644
--- a/WebKit/android/WebCoreSupport/WebRequest.cpp
+++ b/WebKit/android/WebCoreSupport/WebRequest.cpp
@@ -473,7 +473,7 @@ void WebRequest::startReading()
if (!read(&bytesRead)) {
if (m_request && m_request->status().is_io_pending())
return; // Wait for OnReadCompleted()
- finish(false);
+ return finish(false);
}
// bytesRead == 0 indicates finished
diff --git a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp
index 5c54000..642a81a 100644
--- a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp
+++ b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp
@@ -38,7 +38,6 @@
#include "WebResourceRequest.h"
#include <wtf/text/CString.h>
-#include <sstream>
namespace android {
@@ -88,6 +87,8 @@ bool WebUrlLoaderClient::isActive() const
{
if (m_cancelling)
return false;
+ if (!m_resourceHandle)
+ return false;
if (!m_resourceHandle->client())
return false;
if (m_finished)
@@ -344,30 +345,6 @@ void WebUrlLoaderClient::maybeCallOnMainThread(Task* task)
}
}
-namespace {
-// Convert a CertPrincipal into string readable by Java code.
-// The expected format is "CN=xxx, O=xxx, OU=xxx" (see SslCertificate.DName).
-// If there are multiple organization names, we print them all.
-static std::string certPrincipalToString(const net::CertPrincipal& cp)
-{
- std::string result;
- if (!cp.common_name.empty()) {
- result += "CN=";
- result += cp.common_name;
- }
- std::vector<std::string>::const_iterator i;
- for (i = cp.organization_names.begin(); i != cp.organization_names.end(); ++i) {
- result += result.empty() ? "O=" : ", O=";
- result += *i;
- }
- for (i = cp.organization_unit_names.begin(); i != cp.organization_unit_names.end(); ++i) {
- result += result.empty() ? "OU=" : ", OU=";
- result += *i;
- }
- return result;
-}
-}
-
// Response methods
void WebUrlLoaderClient::didReceiveResponse(PassOwnPtr<WebResponse> webResponse)
{
@@ -379,13 +356,11 @@ void WebUrlLoaderClient::didReceiveResponse(PassOwnPtr<WebResponse> webResponse)
if (m_isMainResource) {
// If we got an SSL certificate, tell the WebView about it.
- const net::SSLInfo& ssl = m_response->getSslInfo();
- if (ssl.cert) {
- m_webFrame->setCertificate(
- certPrincipalToString(ssl.cert->subject()),
- certPrincipalToString(ssl.cert->issuer()),
- 1000L * ssl.cert->valid_start().ToDoubleT(),
- 1000L * ssl.cert->valid_expiry().ToDoubleT());
+ const net::SSLInfo& ssl_info = m_response->getSslInfo();
+ if (ssl_info.is_valid()) {
+ std::vector<std::string> chain_bytes;
+ ssl_info.cert->GetChainDEREncodedBytes(&chain_bytes);
+ m_webFrame->setCertificate(chain_bytes[0]);
}
}
}
diff --git a/WebKit/android/jni/CookieManager.cpp b/WebKit/android/jni/CookieManager.cpp
index 87c7fa8..a9c68fd 100644
--- a/WebKit/android/jni/CookieManager.cpp
+++ b/WebKit/android/jni/CookieManager.cpp
@@ -155,6 +155,25 @@ static void flushCookieStore(JNIEnv*, jobject)
#endif
}
+static bool acceptFileSchemeCookies(JNIEnv*, jobject)
+{
+#if USE(CHROME_NETWORK_STACK)
+ return WebCookieJar::acceptFileSchemeCookies();
+#else
+ // File scheme cookies are always accepted with the Android HTTP stack.
+ return true;
+#endif
+}
+
+static void setAcceptFileSchemeCookies(JNIEnv*, jobject, jboolean accept)
+{
+#if USE(CHROME_NETWORK_STACK)
+ WebCookieJar::setAcceptFileSchemeCookies(accept);
+#else
+ // File scheme cookies are always accepted with the Android HTTP stack.
+#endif
+}
+
static JNINativeMethod gCookieManagerMethods[] = {
{ "nativeAcceptCookie", "()Z", (void*) acceptCookie },
{ "nativeGetCookie", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getCookie },
@@ -165,6 +184,8 @@ static JNINativeMethod gCookieManagerMethods[] = {
{ "nativeSetAcceptCookie", "(Z)V", (void*) setAcceptCookie },
{ "nativeSetCookie", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) setCookie },
{ "nativeFlushCookieStore", "()V", (void*) flushCookieStore },
+ { "nativeAcceptFileSchemeCookies", "()Z", (void*) acceptFileSchemeCookies },
+ { "nativeSetAcceptFileSchemeCookies", "(Z)V", (void*) setAcceptFileSchemeCookies },
};
int registerCookieManager(JNIEnv* env)
diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp
index 9780d2d..c187d92 100644
--- a/WebKit/android/jni/WebCoreFrameBridge.cpp
+++ b/WebKit/android/jni/WebCoreFrameBridge.cpp
@@ -44,7 +44,6 @@
#include "Element.h"
#include "FocusController.h"
#include "Font.h"
-#include "FormState.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClientAndroid.h"
@@ -220,6 +219,8 @@ struct WebFrame::JavaBrowserFrame
jmethodID mDidReceiveData;
jmethodID mDidFinishLoading;
jmethodID mSetCertificate;
+ jmethodID mShouldSaveFormData;
+ jmethodID mSaveFormData;
AutoJObject frame(JNIEnv* env) {
return getRealObject(env, mObj);
}
@@ -290,8 +291,9 @@ WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page*
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V");
mJavaFrame->mDidReceiveData = env->GetMethodID(clazz, "didReceiveData", "([BI)V");
mJavaFrame->mDidFinishLoading = env->GetMethodID(clazz, "didFinishLoading", "()V");
- mJavaFrame->mSetCertificate = env->GetMethodID(clazz, "setCertificate",
- "(Ljava/lang/String;Ljava/lang/String;JJ)V");
+ mJavaFrame->mSetCertificate = env->GetMethodID(clazz, "setCertificate", "([B)V");
+ mJavaFrame->mShouldSaveFormData = env->GetMethodID(clazz, "shouldSaveFormData", "()Z");
+ mJavaFrame->mSaveFormData = env->GetMethodID(clazz, "saveFormData", "(Ljava/util/HashMap;)V");
env->DeleteLocalRef(clazz);
LOG_ASSERT(mJavaFrame->mStartLoadingResource, "Could not find method startLoadingResource");
@@ -322,6 +324,8 @@ WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page*
LOG_ASSERT(mJavaFrame->mDidReceiveData, "Could not find method didReceiveData");
LOG_ASSERT(mJavaFrame->mDidFinishLoading, "Could not find method didFinishLoading");
LOG_ASSERT(mJavaFrame->mSetCertificate, "Could not find method setCertificate");
+ LOG_ASSERT(mJavaFrame->mShouldSaveFormData, "Could not find method shouldSaveFormData");
+ LOG_ASSERT(mJavaFrame->mSaveFormData, "Could not find method saveFormData");
mUserAgent = WTF::String();
mUserInitiatedAction = false;
@@ -782,6 +786,16 @@ WebFrame::canHandleRequest(const WebCore::ResourceRequest& request)
return (ret == 0);
}
+bool
+WebFrame::shouldSaveFormData()
+{
+ JNIEnv* env = getJNIEnv();
+ jboolean ret = env->CallBooleanMethod(mJavaFrame->frame(env).get(),
+ mJavaFrame->mShouldSaveFormData);
+ checkException(env);
+ return ret;
+}
+
WebCore::Frame*
WebFrame::createWindow(bool dialog, bool userGesture)
{
@@ -950,20 +964,21 @@ WebFrame::didFinishLoading() {
#endif
#if USE(CHROME_NETWORK_STACK)
-void WebFrame::setCertificate(const std::string& issuedTo, const std::string& issuedBy, long long validNotBeforeMillis, long long validNotAfterMillis)
+void WebFrame::setCertificate(const std::string& cert)
{
#ifdef ANDROID_INSTRUMENT
TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
#endif
JNIEnv* env = getJNIEnv();
- jstring jIssuedTo = stdStringToJstring(env, issuedTo, true);
- jstring jIssuedBy = stdStringToJstring(env, issuedBy, true);
- env->CallVoidMethod(mJavaFrame->frame(env).get(),
- mJavaFrame->mSetCertificate, jIssuedTo, jIssuedBy, validNotBeforeMillis, validNotAfterMillis);
+ int len = cert.length();
+ jbyteArray jCert = env->NewByteArray(len);
+ jbyte* bytes = env->GetByteArrayElements(jCert, NULL);
+ cert.copy(reinterpret_cast<char*>(bytes), len);
+
+ env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSetCertificate, jCert);
- env->DeleteLocalRef(jIssuedTo);
- env->DeleteLocalRef(jIssuedBy);
+ env->DeleteLocalRef(jCert);
checkException(env);
}
#endif
@@ -1876,62 +1891,46 @@ static void SetUsernamePassword(JNIEnv *env, jobject obj,
}
}
-static jobject GetFormTextData(JNIEnv *env, jobject obj)
+void
+WebFrame::saveFormData(HTMLFormElement* form)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
- WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "GetFormTextData must take a valid frame pointer!");
- jobject hashMap = NULL;
-
- WTF::PassRefPtr<WebCore::HTMLCollection> collection = pFrame->document()->forms();
- if (collection->length() > 0) {
+ if (form->autoComplete()) {
+ JNIEnv* env = getJNIEnv();
jclass mapClass = env->FindClass("java/util/HashMap");
LOG_ASSERT(mapClass, "Could not find HashMap class!");
jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V");
LOG_ASSERT(init, "Could not find constructor for HashMap");
- hashMap = env->NewObject(mapClass, init, 1);
+ jobject hashMap = env->NewObject(mapClass, init, 1);
LOG_ASSERT(hashMap, "Could not create a new HashMap");
jmethodID put = env->GetMethodID(mapClass, "put",
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
LOG_ASSERT(put, "Could not find put method on HashMap");
-
- WebCore::HTMLFormElement* form;
- WebCore::HTMLInputElement* input;
- for (WebCore::Node* node = collection->firstItem();
- node && !node->namespaceURI().isNull() && !node->namespaceURI().isEmpty();
- node = collection->nextItem()) {
- form = static_cast<WebCore::HTMLFormElement*>(node);
- if (form->autoComplete()) {
- WTF::Vector<WebCore::HTMLFormControlElement*> elements = form->associatedElements();
- size_t size = elements.size();
- for (size_t i = 0; i < size; i++) {
- WebCore::HTMLFormControlElement* e = elements[i];
- if (e->hasTagName(WebCore::HTMLNames::inputTag)) {
- input = static_cast<WebCore::HTMLInputElement*>(e);
- if (input->isTextField() && !input->isPasswordField()
- && input->autoComplete()) {
- WTF::String value = input->value();
- int len = value.length();
- if (len) {
- const WTF::AtomicString& name = input->name();
- jstring key = wtfStringToJstring(env, name);
- jstring val = wtfStringToJstring(env, value);
- LOG_ASSERT(key && val, "name or value not set");
- env->CallObjectMethod(hashMap, put, key, val);
- env->DeleteLocalRef(key);
- env->DeleteLocalRef(val);
- }
- }
+ WTF::Vector<WebCore::HTMLFormControlElement*> elements = form->associatedElements();
+ size_t size = elements.size();
+ for (size_t i = 0; i < size; i++) {
+ WebCore::HTMLFormControlElement* e = elements[i];
+ if (e->hasTagName(WebCore::HTMLNames::inputTag)) {
+ WebCore::HTMLInputElement* input = static_cast<WebCore::HTMLInputElement*>(e);
+ if (input->isTextField() && !input->isPasswordField()
+ && input->autoComplete()) {
+ WTF::String value = input->value();
+ int len = value.length();
+ if (len) {
+ const WTF::AtomicString& name = input->name();
+ jstring key = wtfStringToJstring(env, name);
+ jstring val = wtfStringToJstring(env, value);
+ LOG_ASSERT(key && val, "name or value not set");
+ env->CallObjectMethod(hashMap, put, key, val);
+ env->DeleteLocalRef(key);
+ env->DeleteLocalRef(val);
}
}
}
}
+ env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSaveFormData, hashMap);
+ env->DeleteLocalRef(hashMap);
env->DeleteLocalRef(mapClass);
-
}
- return hashMap;
}
static void OrientationChanged(JNIEnv *env, jobject obj, int orientation)
@@ -2048,8 +2047,6 @@ static JNINativeMethod gBrowserFrameNativeMethods[] = {
(void*) GetUsernamePassword },
{ "setUsernamePassword", "(Ljava/lang/String;Ljava/lang/String;)V",
(void*) SetUsernamePassword },
- { "getFormTextData", "()Ljava/util/HashMap;",
- (void*) GetFormTextData },
{ "nativeOrientationChanged", "(I)V",
(void*) OrientationChanged },
{ "nativeAuthenticationProceed", "(ILjava/lang/String;Ljava/lang/String;)V",
diff --git a/WebKit/android/jni/WebCoreFrameBridge.h b/WebKit/android/jni/WebCoreFrameBridge.h
index ae62835..af7be60 100644
--- a/WebKit/android/jni/WebCoreFrameBridge.h
+++ b/WebKit/android/jni/WebCoreFrameBridge.h
@@ -37,6 +37,7 @@
#include <wtf/RefCounted.h>
namespace WebCore {
+ class HTMLFormElement;
class Frame;
class HistoryItem;
class Image;
@@ -125,18 +126,15 @@ class WebFrame : public WebCoreRefObject {
void maybeSavePassword(WebCore::Frame* frame, const WebCore::ResourceRequest& request);
- void setCertificate(const std::string& issuedTo, const std::string& issuedBy, long long validNotBeforeMillis, long long validNotAfterMillis);
+ void setCertificate(const std::string& cert);
/**
- * When the user initiates an action (via trackball, key-press, or touch),
- * we set mUserInitiatedAction to true. If a load happens due to this click,
- * then we ask the application if it wants to override
- * the load. Otherwise, we attempt to load the resource internally.
+ * When the user initiates a click, we set mUserInitiatedAction to true.
+ * If a load happens due to this click, then we ask the application if it wants
+ * to override the load. Otherwise, we attempt to load the resource internally.
*/
void setUserInitiatedAction(bool userInitiatedAction) { mUserInitiatedAction = userInitiatedAction; }
- bool userInitiatedAction() { return mUserInitiatedAction; }
-
WebCore::Page* page() const { return mPage; }
// Currently used only by the chrome net stack. A similar field is used by
@@ -151,6 +149,8 @@ class WebFrame : public WebCoreRefObject {
bool getUsernamePasswordFromDom(WebCore::Frame* frame, WTF::String& username, WTF::String& password);
jbyteArray getPostData(const WebCore::ResourceRequest& request);
+ bool shouldSaveFormData();
+ void saveFormData(WebCore::HTMLFormElement*);
private:
struct JavaBrowserFrame;
JavaBrowserFrame* mJavaFrame;
diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp
index 8361c17..8c0fade 100644
--- a/WebKit/android/jni/WebViewCore.cpp
+++ b/WebKit/android/jni/WebViewCore.cpp
@@ -35,6 +35,8 @@
#include "Chrome.h"
#include "ChromeClientAndroid.h"
#include "ChromiumIncludes.h"
+#include "ClientRect.h"
+#include "ClientRectList.h"
#include "Color.h"
#include "CSSPropertyNames.h"
#include "CSSValueKeywords.h"
@@ -250,9 +252,7 @@ struct WebViewCoreFields {
struct WebViewCore::JavaGlue {
jweak m_obj;
- jmethodID m_spawnScrollTo;
jmethodID m_scrollTo;
- jmethodID m_scrollBy;
jmethodID m_contentDraw;
jmethodID m_layersDraw;
jmethodID m_requestListBox;
@@ -342,15 +342,14 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
#endif
m_isPaused = false;
m_screenOnCounter = 0;
+ m_onlyScrollIfImeIsShowing = false;
LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
jclass clazz = env->GetObjectClass(javaWebViewCore);
m_javaGlue = new JavaGlue;
m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore);
- m_javaGlue->m_spawnScrollTo = GetJMethod(env, clazz, "contentSpawnScrollTo", "(II)V");
- m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(II)V");
- m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V");
+ m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZZ)V");
m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V");
m_javaGlue->m_layersDraw = GetJMethod(env, clazz, "layersDraw", "()V");
m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V");
@@ -486,8 +485,6 @@ void WebViewCore::reset(bool fromConstructor)
m_scrollOffsetY = 0;
m_screenWidth = 0;
m_screenHeight = 0;
- m_visibleScreenWidth = 0;
- m_visibleScreenHeight = 0;
m_groupForVisitedLinks = NULL;
m_currentNodeDomNavigationAxis = 0;
}
@@ -947,9 +944,8 @@ void WebViewCore::scrollTo(int x, int y, bool animate)
// LOGD("WebViewCore::scrollTo(%d %d)\n", x, y);
JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue->object(env).get(),
- animate ? m_javaGlue->m_spawnScrollTo : m_javaGlue->m_scrollTo,
- x, y);
+ env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollTo,
+ x, y, animate, m_onlyScrollIfImeIsShowing);
checkException(env);
}
@@ -971,16 +967,6 @@ void WebViewCore::viewInvalidate(const WebCore::IntRect& rect)
checkException(env);
}
-void WebViewCore::scrollBy(int dx, int dy, bool animate)
-{
- if (!(dx | dy))
- return;
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollBy,
- dx, dy, animate);
- checkException(env);
-}
-
void WebViewCore::contentDraw()
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
@@ -1151,13 +1137,14 @@ void WebViewCore::doMaxScroll(CacheBuilder::Direction dir)
default:
LOG_ASSERT(0, "unexpected focus selector");
}
- this->scrollBy(dx, dy, true);
+ WebCore::FrameView* view = m_mainFrame->view();
+ this->scrollTo(view->scrollX() + dx, view->scrollY() + dy, true);
}
-void WebViewCore::setScrollOffset(int moveGeneration, int userScrolled, int dx, int dy)
+void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy)
{
- DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), userScrolled=%d", dx, dy,
- m_scrollOffsetX, m_scrollOffsetY, userScrolled);
+ DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), sendScrollEvent=%d", dx, dy,
+ m_scrollOffsetX, m_scrollOffsetY, sendScrollEvent);
if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) {
m_scrollOffsetX = dx;
m_scrollOffsetY = dy;
@@ -1166,24 +1153,25 @@ void WebViewCore::setScrollOffset(int moveGeneration, int userScrolled, int dx,
// testing work correctly.
m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX,
m_scrollOffsetY);
- if (userScrolled) {
+ if (sendScrollEvent) {
m_mainFrame->eventHandler()->sendScrollEvent();
- }
- // Update history item to reflect the new scroll position.
- // This also helps save the history information when the browser goes to
- // background, so scroll position will be restored if browser gets
- // killed while in background.
- WebCore::HistoryController* history = m_mainFrame->loader()->history();
- // Because the history item saving could be heavy for large sites and
- // scrolling can generate lots of small scroll offset, the following code
- // reduces the saving frequency.
- static const int MIN_SCROLL_DIFF = 32;
- if (history->currentItem()) {
- WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint();
- if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF ||
- std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) {
- history->saveScrollPositionAndViewStateToItem(history->currentItem());
+ // Only update history position if it's user scrolled.
+ // Update history item to reflect the new scroll position.
+ // This also helps save the history information when the browser goes to
+ // background, so scroll position will be restored if browser gets
+ // killed while in background.
+ WebCore::HistoryController* history = m_mainFrame->loader()->history();
+ // Because the history item saving could be heavy for large sites and
+ // scrolling can generate lots of small scroll offset, the following code
+ // reduces the saving frequency.
+ static const int MIN_SCROLL_DIFF = 32;
+ if (history->currentItem()) {
+ WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint();
+ if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF ||
+ std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) {
+ history->saveScrollPositionAndViewStateToItem(history->currentItem());
+ }
}
}
@@ -1229,6 +1217,12 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
// Don't reflow if the diff is small.
const bool reflow = otw && textWrapWidth &&
((float) abs(otw - textWrapWidth) / textWrapWidth) >= 0.01f;
+
+ // When the screen size change, fixed positioned element should be updated.
+ // This is supposed to be light weighted operation without a full layout.
+ if (osh != screenHeight || osw != screenWidth)
+ m_mainFrame->view()->updatePositionedObjects();
+
if (ow != width || (!ignoreHeight && oh != height) || reflow) {
WebCore::RenderObject *r = m_mainFrame->contentRenderer();
DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r,
@@ -1322,8 +1316,11 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
// If this was in response to touching a textfield and showing the IME,
// the IME may now cover textfield. Bring it back into view.
// If the scale changed, however, this was the result of a zoom.
- if (oldScale == m_scale)
+ if (oldScale == m_scale && osh > screenHeight) {
+ m_onlyScrollIfImeIsShowing = true;
revealSelection();
+ m_onlyScrollIfImeIsShowing = false;
+ }
// update the currently visible screen as perceived by the plugin
sendPluginVisibleScreen();
}
@@ -2084,18 +2081,18 @@ String WebViewCore::modifySelection(const int direction, const int axis)
if (selection->rangeCount() > 1)
selection->removeAllRanges();
switch (axis) {
- case AXIS_CHARACTER:
- case AXIS_WORD:
- case AXIS_SENTENCE:
- return modifySelectionTextNavigationAxis(selection, direction, axis);
- case AXIS_HEADING:
- case AXIS_SIBLING:
- case AXIS_PARENT_FIRST_CHILD:
- case AXIS_DOCUMENT:
- return modifySelectionDomNavigationAxis(selection, direction, axis);
- default:
- LOGE("Invalid navigation axis: %d", axis);
- return String();
+ case AXIS_CHARACTER:
+ case AXIS_WORD:
+ case AXIS_SENTENCE:
+ return modifySelectionTextNavigationAxis(selection, direction, axis);
+ case AXIS_HEADING:
+ case AXIS_SIBLING:
+ case AXIS_PARENT_FIRST_CHILD:
+ case AXIS_DOCUMENT:
+ return modifySelectionDomNavigationAxis(selection, direction, axis);
+ default:
+ LOGE("Invalid navigation axis: %d", axis);
+ return String();
}
}
@@ -2123,10 +2120,10 @@ void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node)
String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis)
{
- // TODO: Add support of IFrames.
- HTMLElement* body = m_mainFrame->document()->body();
+ Node* body = m_mainFrame->document()->body();
ExceptionCode ec = 0;
+ String markup;
// initialize the selection if necessary
if (selection->rangeCount() == 0) {
@@ -2151,14 +2148,13 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i
if (ec)
return String();
selection->addRange(rangeRef.get());
- } else if (direction == DIRECTION_FORWARD) {
- selection->setPosition(body->firstDescendant(), 0, ec);
} else {
- selection->setPosition(body->lastDescendant(), 0, ec);
+ selection->setPosition(body, 0, ec);
}
if (ec)
return String();
}
+
// collapse the selection
if (direction == DIRECTION_FORWARD)
selection->collapseToEnd(ec);
@@ -2167,126 +2163,52 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i
if (ec)
return String();
- Node* oldAnchorNode = selection->anchorNode();
- if (!oldAnchorNode)
- return String();
-
// Make sure the anchor node is a text node since we are generating
// the markup of the selection which includes the anchor, the focus,
// and any crossed nodes. Forcing the condition that the selection
// starts and ends on text nodes guarantees symmetric selection markup.
+ // Also this way the text content, rather its container, is highlighted.
Node* anchorNode = selection->anchorNode();
if (anchorNode->isElementNode()) {
- int anchorOffset = rangeCompliantChildOffset(anchorNode,
- selection->anchorOffset());
- anchorNode = selection->anchorNode()->childNodes()->item(anchorOffset);
- Node* nextAnchorNode = traverseVisibleNonEmptyNonWhitespaceTextNode(
- anchorNode, body, direction);
- if (!nextAnchorNode)
+ // Collapsed selection while moving forward points to the
+ // next unvisited node and while moving backward to the
+ // last visited node.
+ if (direction == DIRECTION_FORWARD)
+ advanceAnchorNode(selection, direction, markup, false, ec);
+ else
+ advanceAnchorNode(selection, direction, markup, true, ec);
+ if (ec)
return String();
- if (direction == DIRECTION_FORWARD) {
- Node* skippedControl = getFirstIntermediaryInputOrButton(anchorNode,
- nextAnchorNode);
- if (skippedControl) {
- IntRect bounds = static_cast<Element*>(
- skippedControl)->boundsInWindowSpace();
- selectAt(bounds.center().x(), bounds.center().y());
- selection->setBaseAndExtent(skippedControl,
- caretMinOffset(skippedControl), skippedControl,
- caretMaxOffset(skippedControl), ec);
- if (ec)
- return String();
- return formatMarkup(selection).stripWhiteSpace();
- } else {
- selection->setPosition(nextAnchorNode, 0, ec);
- if (ec)
- return String();
- }
- } else {
- Node* skippedControl = getFirstIntermediaryInputOrButton(
- nextAnchorNode, anchorNode);
- if (skippedControl) {
- IntRect bounds = static_cast<Element*>(
- skippedControl)->boundsInWindowSpace();
- selectAt(bounds.center().x(), bounds.center().y());
- selection->setBaseAndExtent(skippedControl,
- caretMaxOffset(skippedControl), skippedControl,
- caretMinOffset(skippedControl), ec);
- if (ec)
- return String();
- return formatMarkup(selection).stripWhiteSpace();
- } else {
- selection->setPosition(nextAnchorNode,
- caretMaxOffset(nextAnchorNode), ec);
- if (ec)
- return String();
- }
- }
+ if (!markup.isEmpty())
+ return markup;
}
// If the selection is at the end of a non white space text move
// it to the next visible text node with non white space content.
// This is a workaround for the selection getting stuck.
anchorNode = selection->anchorNode();
- if (!anchorNode)
- return String();
if (anchorNode->isTextNode()) {
if (direction == DIRECTION_FORWARD) {
String suffix = anchorNode->textContent().substring(
- selection->anchorOffset(), caretMaxOffset(anchorNode));
+ selection->anchorOffset(), caretMaxOffset(anchorNode));
+ // If at the end of non white space text we advance the
+ // anchor node to either an input element or non empty text.
if (suffix.stripWhiteSpace().isEmpty()) {
- Node* nextAnchorNode =
- traverseVisibleNonEmptyNonWhitespaceTextNode(anchorNode,
- body, direction);
- if (!nextAnchorNode)
- return String();
- Node* skippedControl = getFirstIntermediaryInputOrButton(
- anchorNode, nextAnchorNode);
- if (skippedControl) {
- IntRect bounds = static_cast<Element*>(
- skippedControl)->boundsInWindowSpace();
- selectAt(bounds.center().x(), bounds.center().y());
- selection->setBaseAndExtent(skippedControl,
- caretMinOffset(skippedControl), skippedControl,
- caretMaxOffset(skippedControl), ec);
- if (ec)
- return String();
- return formatMarkup(selection).stripWhiteSpace();
- } else {
- selection->setPosition(nextAnchorNode, 0, ec);
- if (ec)
- return String();
- }
+ advanceAnchorNode(selection, direction, markup, true, ec);
}
} else {
String prefix = anchorNode->textContent().substring(0,
- selection->anchorOffset());
+ selection->anchorOffset());
+ // If at the end of non white space text we advance the
+ // anchor node to either an input element or non empty text.
if (prefix.stripWhiteSpace().isEmpty()) {
- Node* nextAnchorNode =
- traverseVisibleNonEmptyNonWhitespaceTextNode(anchorNode,
- body, direction);
- if (!nextAnchorNode)
- return String();
- Node* skippedControl = getFirstIntermediaryInputOrButton(
- nextAnchorNode, anchorNode);
- if (skippedControl) {
- IntRect bounds = static_cast<Element*>(
- skippedControl)->boundsInWindowSpace();
- selectAt(bounds.center().x(), bounds.center().y());
- selection->setBaseAndExtent(skippedControl,
- caretMaxOffset(skippedControl), skippedControl,
- caretMinOffset(skippedControl), ec);
- if (ec)
- return String();
- return formatMarkup(selection).stripWhiteSpace();
- } else {
- selection->setPosition(nextAnchorNode,
- caretMaxOffset(nextAnchorNode), ec);
- if (ec)
- return String();
- }
+ advanceAnchorNode(selection, direction, markup, true, ec);
}
}
+ if (ec)
+ return String();
+ if (!markup.isEmpty())
+ return markup;
}
// extend the selection
@@ -2308,176 +2230,111 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i
// Make sure the focus node is a text node in order to have the
// selection generate symmetric markup because the latter
- // includes all nodes crossed by the selection.
+ // includes all nodes crossed by the selection. Also this way
+ // the text content, rather its container, is highlighted.
Node* focusNode = selection->focusNode();
if (focusNode->isElementNode()) {
- int focusOffset = rangeCompliantChildOffset(focusNode,
- selection->focusOffset());
+ focusNode = getImplicitAnchorOrFocusNode(selection->focusNode(),
+ selection->focusOffset(), direction);
+ if (!focusNode)
+ return String();
if (direction == DIRECTION_FORWARD) {
- focusNode =
- focusNode->childNodes()->item(focusOffset)->lastDescendant();
- if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) {
- focusNode = traverseVisibleNonEmptyNonWhitespaceTextNode(
- focusNode, body, DIRECTION_BACKWARD);
- if (!focusNode)
+ focusNode = focusNode->traversePreviousSiblingPostOrder(body);
+ if (focusNode && !isContentTextNode(focusNode)) {
+ Node* textNode = traverseNextContentTextNode(focusNode,
+ anchorNode, DIRECTION_BACKWARD);
+ if (textNode)
+ anchorNode = textNode;
+ }
+ if (focusNode && isContentTextNode(focusNode)) {
+ selection->extend(focusNode, caretMaxOffset(focusNode), ec);
+ if (ec)
return String();
}
- selection->extend(focusNode, caretMaxOffset(focusNode), ec);
- if (ec)
- return String();
} else {
- focusNode =
- focusNode->childNodes()->item(focusOffset)->firstDescendant();
- if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) {
- focusNode = traverseVisibleNonEmptyNonWhitespaceTextNode(
- focusNode, body, DIRECTION_FORWARD);
- if (!focusNode)
+ focusNode = focusNode->traverseNextSibling();
+ if (focusNode && !isContentTextNode(focusNode)) {
+ Node* textNode = traverseNextContentTextNode(focusNode,
+ anchorNode, DIRECTION_FORWARD);
+ if (textNode)
+ anchorNode = textNode;
+ }
+ if (anchorNode && isContentTextNode(anchorNode)) {
+ selection->extend(focusNode, 0, ec);
+ if (ec)
return String();
}
- selection->extend(focusNode, 0, ec);
- if (ec)
- return String();
}
}
// Enforce that the selection does not cross anchor boundaries. This is
// a workaround for the asymmetric behavior of WebKit while crossing
// anchors.
- // NOTE: The code is asymmetric since the logic is based off the common
- // ancestor in both directions - backward and forward.
- // TODO: Factor out common code repeated below.
- anchorNode = selection->anchorNode();
- focusNode = selection->focusNode();
- if (anchorNode != focusNode
- && anchorNode->isTextNode()
- && focusNode->isTextNode()) {
- Node* commonAncestor = Range::commonAncestorContainer(anchorNode,
- focusNode);
- Node* currentNode = 0;
- bool selectionAdjusted = false;
- if (direction == DIRECTION_FORWARD) {
- // catch if the anchor is in a link but the focus is not
- if (!commonAncestor->hasTagName(WebCore::HTMLNames::aTag)) {
- currentNode = anchorNode;
- while (currentNode != commonAncestor) {
- if (isVisible(currentNode) && isInputControl(currentNode)) {
- focusNode = currentNode->lastDescendant();
- if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) {
- focusNode =
- traverseVisibleNonEmptyNonWhitespaceTextNode(
- focusNode, commonAncestor,
- DIRECTION_BACKWARD);
- if (!focusNode)
- return String();
- }
- selection->extend(focusNode, caretMaxOffset(focusNode),
- ec);
- if (ec)
- return String();
- selectionAdjusted = true;
- break;
- }
- currentNode = currentNode->parentNode();
+ anchorNode = getImplicitAnchorOrFocusNode(selection->anchorNode(),
+ selection->anchorOffset(), direction);
+ focusNode = getImplicitAnchorOrFocusNode(selection->focusNode(),
+ selection->focusOffset(), direction);
+ if (anchorNode && focusNode && anchorNode != focusNode) {
+ Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode,
+ direction);
+ if (inputControl) {
+ if (direction == DIRECTION_FORWARD) {
+ if (isDescendantOf(inputControl, anchorNode)) {
+ focusNode = inputControl;
+ } else {
+ focusNode = inputControl->traversePreviousSiblingPostOrder(
+ body);
+ if (!focusNode)
+ focusNode = inputControl;
}
- // catch if there is a link between the anchor and focus
- if (!selectionAdjusted) {
- currentNode = anchorNode;
- while (currentNode != focusNode) {
- if (isVisible(currentNode)
- && isInputControl(currentNode)) {
- focusNode = currentNode;
- if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) {
- focusNode =
- traverseVisibleNonEmptyNonWhitespaceTextNode(
- focusNode, commonAncestor,
- DIRECTION_BACKWARD);
- if (!focusNode)
- return String();
- }
- selection->extend(focusNode,
- caretMaxOffset(focusNode), ec);
- if (ec)
- return String();
- break;
- }
- currentNode = currentNode->traverseNextNode();
- }
+ // We prefer a text node contained in the input element.
+ if (!isContentTextNode(focusNode)) {
+ Node* textNode = traverseNextContentTextNode(focusNode,
+ anchorNode, DIRECTION_BACKWARD);
+ if (textNode)
+ focusNode = textNode;
}
- }
- } else {
- // catch if the anchor is in a link but the focus is not
- // NOTE: There is not such case in forward direction because
- // it is implicitly covered the second case. Also the
- // base position used for computing the the common
- // ancestor which is asymmteric.
- if (!commonAncestor->hasTagName(WebCore::HTMLNames::aTag)) {
- currentNode = anchorNode;
- while (currentNode != commonAncestor) {
- if (isVisible(currentNode) && isInputControl(currentNode)) {
- focusNode = currentNode->firstDescendant();
- if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) {
- focusNode =
- traverseVisibleNonEmptyNonWhitespaceTextNode(
- focusNode, commonAncestor,
- DIRECTION_FORWARD);
- if (!focusNode)
- return String();
- }
- selection->extend(focusNode, 0, ec);
- if (ec)
- return String();
- selectionAdjusted = true;
- break;
- }
- currentNode = currentNode->parentNode();
+ // If we found text in the input select it.
+ // Otherwise, select the input element itself.
+ if (isContentTextNode(focusNode)) {
+ selection->extend(focusNode, caretMaxOffset(focusNode), ec);
+ } else if (anchorNode != focusNode) {
+ // Note that the focusNode always has parent and that
+ // the offset can be one more that the index of the last
+ // element - this is how WebKit selects such elements.
+ selection->extend(focusNode->parentNode(),
+ focusNode->nodeIndex() + 1, ec);
}
- // catch if there is a link between the anchor and focus
- if (!selectionAdjusted) {
- currentNode = anchorNode;
- while (currentNode != focusNode) {
- if (isVisible(currentNode)
- && isInputControl(currentNode)) {
- focusNode = currentNode->traverseNextSibling();
- if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) {
- focusNode =
- traverseVisibleNonEmptyNonWhitespaceTextNode(
- focusNode, commonAncestor,
- DIRECTION_FORWARD);
- if (!focusNode)
- return String();
- }
- selection->extend(focusNode, 0, ec);
- if (ec)
- return String();
- selectionAdjusted = true;
- break;
- }
- currentNode = currentNode->traversePreviousNode();
- }
+ if (ec)
+ return String();
+ } else {
+ if (isDescendantOf(inputControl, anchorNode)) {
+ focusNode = inputControl;
+ } else {
+ focusNode = inputControl->traverseNextSibling();
+ if (!focusNode)
+ focusNode = inputControl;
}
- // catch if the focus is in a link but the anchor is not
- if (!selectionAdjusted) {
- currentNode = focusNode;
- while (currentNode != commonAncestor) {
- if (isVisible(currentNode)
- && isInputControl(currentNode)) {
- focusNode = currentNode->traverseNextSibling();
- if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) {
- focusNode =
- traverseVisibleNonEmptyNonWhitespaceTextNode(
- focusNode, commonAncestor,
- DIRECTION_FORWARD);
- if (!focusNode)
- return String();
- }
- selection->extend(focusNode, 0, ec);
- if (ec)
- return String();
- break;
- }
- currentNode = currentNode->parentNode();
- }
+ // We prefer a text node contained in the input element.
+ if (!isContentTextNode(focusNode)) {
+ Node* textNode = traverseNextContentTextNode(focusNode,
+ anchorNode, DIRECTION_FORWARD);
+ if (textNode)
+ focusNode = textNode;
+ }
+ // If we found text in the input select it.
+ // Otherwise, select the input element itself.
+ if (isContentTextNode(focusNode)) {
+ selection->extend(focusNode, caretMinOffset(focusNode), ec);
+ } else if (anchorNode != focusNode) {
+ // Note that the focusNode always has parent and that
+ // the offset can be one more that the index of the last
+ // element - this is how WebKit selects such elements.
+ selection->extend(focusNode->parentNode(),
+ focusNode->nodeIndex() + 1, ec);
}
+ if (ec)
+ return String();
}
}
}
@@ -2494,30 +2351,136 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i
return String();
IntRect bounds = range->boundingBox();
selectAt(bounds.center().x(), bounds.center().y());
- String markup = formatMarkup(selection).stripWhiteSpace();
+ markup = formatMarkup(selection);
LOGV("Selection markup: %s", markup.utf8().data());
return markup;
}
-bool WebViewCore::isInputControl(Node* node)
+Node* WebViewCore::getImplicitAnchorOrFocusNode(Node* node, unsigned offset, int direction)
{
- return (node->hasTagName(WebCore::HTMLNames::aTag)
- || node->hasTagName(WebCore::HTMLNames::inputTag)
- || node->hasTagName(WebCore::HTMLNames::buttonTag));
+ if (node->offsetInCharacters())
+ return node;
+ if (!node->hasChildNodes())
+ return node;
+ if (offset < node->childNodeCount())
+ return node->childNode(offset);
+ else
+ if (direction == DIRECTION_FORWARD)
+ return node->traverseNextSibling();
+ else
+ return node->traversePreviousNodePostOrder(
+ node->document()->body());
}
-int WebViewCore::rangeCompliantChildOffset(Node* parent, int offset)
+Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction)
{
- if (offset < 0)
- return 0;
- int lastChildIndex = parent->childNodes()->length() - 1;
- if (offset > lastChildIndex)
- return lastChildIndex;
- return offset;
+ Node* body = 0;
+ Node* currentNode = 0;
+ if (direction == DIRECTION_FORWARD) {
+ if (ignoreFirstNode)
+ currentNode = anchorNode->traverseNextNode(body);
+ else
+ currentNode = anchorNode;
+ } else {
+ body = anchorNode->document()->body();
+ if (ignoreFirstNode)
+ currentNode = anchorNode->traversePreviousSiblingPostOrder(body);
+ else
+ currentNode = anchorNode;
+ }
+ while (currentNode) {
+ if (isContentTextNode(currentNode)
+ || isContentInputElement(currentNode))
+ return currentNode;
+ if (direction == DIRECTION_FORWARD)
+ currentNode = currentNode->traverseNextNode();
+ else
+ currentNode = currentNode->traversePreviousNodePostOrder(body);
+ }
+ return 0;
+}
+
+void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction,
+ String& markup, bool ignoreFirstNode, ExceptionCode& ec)
+{
+ Node* anchorNode = getImplicitAnchorOrFocusNode(selection->anchorNode(),
+ selection->anchorOffset(), direction);
+ if (!anchorNode) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+ // If the anchor offset is invalid i.e. the anchor node has no
+ // child with that index getImplicitAnchorNode returns the next
+ // logical node in the current direction. In such a case our
+ // position in the DOM tree was has already been advanced,
+ // therefore we there is no need to do that again.
+ if (selection->anchorNode()->isElementNode()) {
+ unsigned anchorOffset = selection->anchorOffset();
+ unsigned childNodeCount = selection->anchorNode()->childNodeCount();
+ if (anchorOffset >= childNodeCount)
+ ignoreFirstNode = false;
+ }
+ // Find the next anchor node given our position in the DOM and
+ // whether we want the current node to be considered as well.
+ Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode,
+ direction);
+ if (!nextAnchorNode) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+ if (nextAnchorNode->isElementNode()) {
+ // If this is an input element tell the WebView thread
+ // to set the cursor to that control.
+ if (isContentInputElement(nextAnchorNode)) {
+ IntRect bounds = nextAnchorNode->getRect();
+ selectAt(bounds.center().x(), bounds.center().y());
+ }
+ Node* textNode = 0;
+ // Treat the text content of links as any other text but
+ // for the rest input elements select the control itself.
+ if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag))
+ textNode = traverseNextContentTextNode(nextAnchorNode,
+ nextAnchorNode, direction);
+ // We prefer to select the text content of the link if such,
+ // otherwise just select the element itself.
+ if (textNode) {
+ nextAnchorNode = textNode;
+ } else {
+ if (direction == DIRECTION_FORWARD) {
+ selection->setBaseAndExtent(nextAnchorNode,
+ caretMinOffset(nextAnchorNode), nextAnchorNode,
+ caretMaxOffset(nextAnchorNode), ec);
+ } else {
+ selection->setBaseAndExtent(nextAnchorNode,
+ caretMaxOffset(nextAnchorNode), nextAnchorNode,
+ caretMinOffset(nextAnchorNode), ec);
+ }
+ if (!ec)
+ markup = formatMarkup(selection);
+ // make sure the selection is visible
+ scrollNodeIntoView(selection->frame(), nextAnchorNode);
+ return;
+ }
+ }
+ if (direction == DIRECTION_FORWARD)
+ selection->setPosition(nextAnchorNode,
+ caretMinOffset(nextAnchorNode), ec);
+ else
+ selection->setPosition(nextAnchorNode,
+ caretMaxOffset(nextAnchorNode), ec);
+}
+
+bool WebViewCore::isContentInputElement(Node* node)
+{
+ return (isVisible(node)
+ && (node->hasTagName(WebCore::HTMLNames::selectTag)
+ || node->hasTagName(WebCore::HTMLNames::aTag)
+ || node->hasTagName(WebCore::HTMLNames::inputTag)
+ || node->hasTagName(WebCore::HTMLNames::buttonTag)));
}
-bool WebViewCore::isVisibleNonEmptyNonWhitespaceTextNode(Node* node)
+bool WebViewCore::isContentTextNode(Node* node)
{
if (!node || !node->isTextNode())
return false;
@@ -2526,21 +2489,66 @@ bool WebViewCore::isVisibleNonEmptyNonWhitespaceTextNode(Node* node)
&& !textNode->containsOnlyWhitespace());
}
-Text* WebViewCore::traverseVisibleNonEmptyNonWhitespaceTextNode(Node* fromNode, Node* toNode, int direction)
+Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction)
{
Node* currentNode = fromNode;
do {
if (direction == DIRECTION_FORWARD)
currentNode = currentNode->traverseNextNode(toNode);
else
- currentNode = currentNode->traversePreviousNode(toNode);
- } while (currentNode && !isVisibleNonEmptyNonWhitespaceTextNode(currentNode));
+ currentNode = currentNode->traversePreviousNodePostOrder(toNode);
+ } while (currentNode && !isContentTextNode(currentNode));
return static_cast<Text*>(currentNode);
}
+Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction)
+{
+ if (fromNode == toNode)
+ return 0;
+ if (direction == DIRECTION_FORWARD) {
+ Node* currentNode = fromNode;
+ while (currentNode && currentNode != toNode) {
+ if (isContentInputElement(currentNode))
+ return currentNode;
+ currentNode = currentNode->traverseNextNodePostOrder();
+ }
+ currentNode = fromNode;
+ while (currentNode && currentNode != toNode) {
+ if (isContentInputElement(currentNode))
+ return currentNode;
+ currentNode = currentNode->traverseNextNode();
+ }
+ } else {
+ Node* currentNode = fromNode->traversePreviousNode();
+ while (currentNode && currentNode != toNode) {
+ if (isContentInputElement(currentNode))
+ return currentNode;
+ currentNode = currentNode->traversePreviousNode();
+ }
+ currentNode = fromNode->traversePreviousNodePostOrder();
+ while (currentNode && currentNode != toNode) {
+ if (isContentInputElement(currentNode))
+ return currentNode;
+ currentNode = currentNode->traversePreviousNodePostOrder();
+ }
+ }
+ return 0;
+}
+
+bool WebViewCore::isDescendantOf(Node* parent, Node* node)
+{
+ Node* currentNode = node;
+ while (currentNode) {
+ if (currentNode == parent) {
+ return true;
+ }
+ currentNode = currentNode->parentNode();
+ }
+ return false;
+}
+
String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis)
{
- // TODO: Add support of IFrames.
HTMLElement* body = m_mainFrame->document()->body();
if (!m_currentNodeDomNavigationAxis && selection->focusNode()) {
m_currentNodeDomNavigationAxis = selection->focusNode();
@@ -2633,12 +2641,27 @@ bool WebViewCore::isHeading(Node* node)
bool WebViewCore::isVisible(Node* node)
{
- // TODO: Use DOMWindow#getComputedStyle instead.
+ // start off an element
+ Element* element = 0;
+ if (node->isElementNode())
+ element = static_cast<Element*>(node);
+ else
+ element = node->parentElement();
+ // check renderer
+ if (!element->renderer()) {
+ return false;
+ }
+ // check size
+ if (element->offsetHeight() == 0 || element->offsetWidth() == 0) {
+ return false;
+ }
+ // check style
Node* body = m_mainFrame->document()->body();
- Node* currentNode = node;
+ Node* currentNode = element;
while (currentNode && currentNode != body) {
RenderStyle* style = currentNode->computedStyle();
- if (style->display() == NONE || style->visibility() == HIDDEN) {
+ if (style &&
+ (style->display() == NONE || style->visibility() == HIDDEN)) {
return false;
}
currentNode = currentNode->parentNode();
@@ -2650,20 +2673,18 @@ String WebViewCore::formatMarkup(DOMSelection* selection)
{
ExceptionCode ec = 0;
String markup = String();
-
PassRefPtr<Range> wholeRange = selection->getRangeAt(0, ec);
if (ec)
- return markup;
-
+ return String();
if (!wholeRange->startContainer() || !wholeRange->startContainer())
- return markup;
-
+ return String();
// Since formatted markup contains invisible nodes it
// is created from the concatenation of the visible fragments.
Node* firstNode = wholeRange->firstNode();
Node* pastLastNode = wholeRange->pastLastNode();
Node* currentNode = firstNode;
PassRefPtr<Range> currentRange;
+
while (currentNode != pastLastNode) {
Node* nextNode = currentNode->traverseNextNode();
if (!isVisible(currentNode)) {
@@ -2676,24 +2697,24 @@ String WebViewCore::formatMarkup(DOMSelection* selection)
if (!currentRange) {
currentRange = selection->frame()->document()->createRange();
if (ec)
- return markup;
+ break;
if (currentNode == firstNode) {
currentRange->setStart(wholeRange->startContainer(),
wholeRange->startOffset(), ec);
if (ec)
- return markup;
+ break;
} else {
currentRange->setStart(currentNode->parentNode(),
currentNode->nodeIndex(), ec);
if (ec)
- return markup;
+ break;
}
}
if (nextNode == pastLastNode) {
currentRange->setEnd(wholeRange->endContainer(),
wholeRange->endOffset(), ec);
if (ec)
- return markup;
+ break;
markup = markup + stripAppleSpanFromMarkup(
currentRange->toHTML()).utf8().data();
} else {
@@ -2704,12 +2725,12 @@ String WebViewCore::formatMarkup(DOMSelection* selection)
currentRange->setEnd(currentNode->parentNode(),
currentNode->nodeIndex() + 1, ec);
if (ec)
- return markup;
+ break;
}
}
currentNode = nextNode;
}
- return markup;
+ return markup.stripWhiteSpace();
}
String WebViewCore::stripAppleSpanFromMarkup(String markup)
@@ -2732,32 +2753,6 @@ void WebViewCore::selectAt(int x, int y)
checkException(env);
}
-Node* WebViewCore::getFirstIntermediaryInputOrButton(Node* fromNode, Node* toNode)
-{
- // do bidirectional traversal to catch the case in which
- // the toNode is a descendant of a control but the fromNode
- // is not and the other way around
- Node* currentNode = fromNode->traverseNextNode();
- while (currentNode && currentNode != toNode) {
- if (isVisible(currentNode)
- && (currentNode->hasTagName(WebCore::HTMLNames::inputTag)
- || currentNode->hasTagName(WebCore::HTMLNames::buttonTag))) {
- return currentNode;
- }
- currentNode = currentNode->traverseNextNode();
- }
- currentNode = fromNode->traverseNextNodePostOrder();
- while (currentNode && currentNode != toNode) {
- if (isVisible(currentNode)
- && (currentNode->hasTagName(WebCore::HTMLNames::inputTag)
- || currentNode->hasTagName(WebCore::HTMLNames::buttonTag))) {
- return currentNode;
- }
- currentNode = currentNode->traverseNextNodePostOrder();
- }
- return 0;
-}
-
void WebViewCore::deleteSelection(int start, int end, int textGeneration)
{
setSelection(start, end);
@@ -2882,94 +2877,6 @@ void WebViewCore::saveDocumentState(WebCore::Frame* frame)
}
}
-// Convert a WTF::String into an array of characters where the first
-// character represents the length, for easy conversion to java.
-static uint16_t* stringConverter(const WTF::String& text)
-{
- size_t length = text.length();
- uint16_t* itemName = new uint16_t[length+1];
- itemName[0] = (uint16_t)length;
- uint16_t* firstChar = &(itemName[1]);
- memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length);
- return itemName;
-}
-
-// Response to dropdown created for a listbox.
-class ListBoxReply : public WebCoreReply {
-public:
- ListBoxReply(WebCore::HTMLSelectElement* select, WebCore::Frame* frame, WebViewCore* view)
- : m_select(select)
- , m_frame(frame)
- , m_viewImpl(view)
- {}
-
- // Response used for a multiple selection listbox if the user did not change
- // anything, in which case -2 is used.
- // Also used by a listbox which has single selection but a size is set.
- virtual void replyInt(int index)
- {
- if (-2 == index) {
- // Special value for cancel. Do nothing.
- return;
- }
- // If the select element no longer exists, due to a page change, etc,
- // silently return.
- if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
- m_frame, m_select))
- return;
- // Use a pointer to HTMLSelectElement's superclass, where
- // listToOptionIndex is public
- SelectElement* selectElement = m_select;
- int optionIndex = selectElement->listToOptionIndex(index);
- m_select->setSelectedIndex(optionIndex, true);
- m_select->dispatchFormControlChangeEvent();
- m_viewImpl->contentInvalidate(m_select->getRect());
- }
-
- // Response if the listbox allows multiple selection. array stores the listIndices
- // of selected positions.
- virtual void replyIntArray(const int* array, int count)
- {
- // If the select element no longer exists, due to a page change, etc,
- // silently return.
- if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
- m_frame, m_select))
- return;
-
- const WTF::Vector<Element*>& items = m_select->listItems();
- int totalItems = static_cast<int>(items.size());
- // Keep track of the position of the value we are comparing against.
- int arrayIndex = 0;
- // The value we are comparing against.
- int selection = array[arrayIndex];
- WebCore::HTMLOptionElement* option;
- for (int listIndex = 0; listIndex < totalItems; listIndex++) {
- if (items[listIndex]->hasLocalName(WebCore::HTMLNames::optionTag)) {
- option = static_cast<WebCore::HTMLOptionElement*>(
- items[listIndex]);
- if (listIndex == selection) {
- option->setSelectedState(true);
- arrayIndex++;
- if (arrayIndex == count)
- selection = -1;
- else
- selection = array[arrayIndex];
- } else
- option->setSelectedState(false);
- }
- }
- m_select->dispatchFormControlChangeEvent();
- m_viewImpl->contentInvalidate(m_select->getRect());
- }
-private:
- // The select element associated with this listbox.
- WebCore::HTMLSelectElement* m_select;
- // The frame of this select element, to verify that it is valid.
- WebCore::Frame* m_frame;
- // For calling invalidate and checking the select element's validity
- WebViewCore* m_viewImpl;
-};
-
// Create an array of java Strings.
static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
{
@@ -3284,46 +3191,7 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node
return true;
}
- WebCore::RenderObject* renderer = nodePtr->renderer();
- if (renderer && renderer->isListBox()) {
- WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr);
- const WTF::Vector<WebCore::Element*>& listItems = select->listItems();
- SkTDArray<const uint16_t*> names;
- // Possible values for enabledArray. Keep in Sync with values in
- // InvokeListBox.Container in WebView.java
- enum OptionStatus {
- OPTGROUP = -1,
- OPTION_DISABLED = 0,
- OPTION_ENABLED = 1,
- };
- SkTDArray<int> enabledArray;
- SkTDArray<int> selectedArray;
- int size = listItems.size();
- bool multiple = select->multiple();
- for (int i = 0; i < size; i++) {
- if (listItems[i]->hasTagName(WebCore::HTMLNames::optionTag)) {
- WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>(listItems[i]);
- *names.append() = stringConverter(option->textIndentedToRespectGroupLabel());
- *enabledArray.append() = option->disabled() ? OPTION_DISABLED : OPTION_ENABLED;
- if (multiple && option->selected())
- *selectedArray.append() = i;
- } else if (listItems[i]->hasTagName(WebCore::HTMLNames::optgroupTag)) {
- WebCore::HTMLOptGroupElement* optGroup = static_cast<WebCore::HTMLOptGroupElement*>(listItems[i]);
- *names.append() = stringConverter(optGroup->groupLabelText());
- *enabledArray.append() = OPTGROUP;
- }
- }
- WebCoreReply* reply = new ListBoxReply(select, select->document()->frame(), this);
- // Use a pointer to HTMLSelectElement's superclass, where
- // optionToListIndex is public.
- SelectElement* selectElement = select;
- listBoxRequest(reply, names.begin(), size, enabledArray.begin(), enabledArray.count(),
- multiple, selectedArray.begin(), multiple ? selectedArray.count() :
- selectElement->optionToListIndex(select->selectedIndex()));
- DBG_NAV_LOG("list box");
- return true;
- }
- scrollLayer(renderer, &m_mousePos);
+ scrollLayer(nodePtr->renderer(), &m_mousePos);
}
if (!valid || !framePtr)
framePtr = m_mainFrame;
@@ -3789,10 +3657,12 @@ void WebViewCore::notifyWebAppCanBeInstalled()
void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary)
{
+#if ENABLE(WEB_AUTOFILL)
JNIEnv* env = JSC::Bindings::getJNIEnv();
jstring preview = env->NewString(previewSummary.data(), previewSummary.length());
env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview);
env->DeleteLocalRef(preview);
+#endif
}
bool WebViewCore::drawIsPaused() const
@@ -3875,7 +3745,7 @@ static void SetSize(JNIEnv *env, jobject obj, jint width, jint height,
screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
}
-static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint userScrolled, jint x, jint y)
+static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jboolean sendScrollEvent, jint x, jint y)
{
#ifdef ANDROID_INSTRUMENT
TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
@@ -3883,7 +3753,7 @@ static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint userScrolle
WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
LOG_ASSERT(viewImpl, "need viewImpl");
- viewImpl->setScrollOffset(gen, userScrolled, x, y);
+ viewImpl->setScrollOffset(gen, sendScrollEvent, x, y);
}
static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h,
@@ -4535,7 +4405,7 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
(void*) SendListBoxChoice },
{ "nativeSetSize", "(IIIFIIIIZ)V",
(void*) SetSize },
- { "nativeSetScrollOffset", "(IIII)V",
+ { "nativeSetScrollOffset", "(IZII)V",
(void*) SetScrollOffset },
{ "nativeSetGlobalBounds", "(IIII)V",
(void*) SetGlobalBounds },
diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h
index 1457089..d38be79 100644
--- a/WebKit/android/jni/WebViewCore.h
+++ b/WebKit/android/jni/WebViewCore.h
@@ -149,14 +149,6 @@ namespace android {
void scrollTo(int x, int y, bool animate = false);
/**
- * Scroll to the point x,y relative to the current position.
- * @param x The relative x position.
- * @param y The relative y position.
- * @param animate If it is true, animate to the new scroll position
- */
- void scrollBy(int x, int y, bool animate);
-
- /**
* Record the invalid rectangle
*/
void contentInvalidate(const WebCore::IntRect &rect);
@@ -311,7 +303,7 @@ namespace android {
WebCore::Frame* frame, int x, int y);
// set the scroll amount that webview.java is currently showing
- void setScrollOffset(int moveGeneration, int userScrolled, int dx, int dy);
+ void setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy);
void setGlobalBounds(int x, int y, int h, int v);
@@ -579,10 +571,9 @@ namespace android {
bool isPaused() const { return m_isPaused; }
void setIsPaused(bool isPaused) { m_isPaused = isPaused; }
bool drawIsPaused() const;
- int visibleScreenWidth() const { return m_visibleScreenWidth; }
- int visibleScreenHeight() const { return m_visibleScreenHeight; }
- void setVisibleScreenWidth(int w) { m_visibleScreenWidth = w; }
- void setVisibleScreenHeight(int h) { m_visibleScreenHeight = h; }
+ // The actual content (without title bar) size in doc coordinate
+ int screenWidth() const { return m_screenWidth; }
+ int screenHeight() const { return m_screenHeight; }
#if USE(CHROME_NETWORK_STACK)
void setWebRequestContextUserAgent();
void setWebRequestContextCacheMode(int mode);
@@ -610,6 +601,9 @@ namespace android {
int m_blurringNodePointer;
int m_lastFocusedSelStart;
int m_lastFocusedSelEnd;
+ // Pass along with a scroll message to tell the UI thread to only
+ // scroll the page if the IME is showing.
+ bool m_onlyScrollIfImeIsShowing;
PictureSet m_content; // the set of pictures to draw
SkRegion m_addInval; // the accumulated inval region (not yet drawn)
SkRegion m_rebuildInval; // the accumulated region for rebuilt pictures
@@ -635,11 +629,6 @@ namespace android {
CachedHistory m_history;
int m_screenWidth; // width of the visible rect in document coordinates
int m_screenHeight;// height of the visible rect in document coordinates
- // The m_screenHeight is not equal to the visibleRect from WebView,
- // using m_visibleScreenHeight to store that info.
- // After we can fix the m_screenHeight in java side, we can merge them.
- int m_visibleScreenWidth;
- int m_visibleScreenHeight;
int m_textWrapWidth;
float m_scale;
unsigned m_domtree_version;
@@ -674,18 +663,21 @@ namespace android {
// below are members responsible for accessibility support
String modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int granularity);
String modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int granularity);
- Text* traverseVisibleNonEmptyNonWhitespaceTextNode(Node* fromNode, Node* toNode ,int direction);
+ Text* traverseNextContentTextNode(Node* fromNode, Node* toNode ,int direction);
bool isVisible(Node* node);
bool isHeading(Node* node);
String formatMarkup(DOMSelection* selection);
void selectAt(int x, int y);
Node* m_currentNodeDomNavigationAxis;
void scrollNodeIntoView(Frame* frame, Node* node);
- bool isVisibleNonEmptyNonWhitespaceTextNode(Node* node);
+ bool isContentTextNode(Node* node);
String stripAppleSpanFromMarkup(String markup);
- int rangeCompliantChildOffset(Node* parent, int offset);
- Node* getFirstIntermediaryInputOrButton(Node* fromNode, Node* toNode);
- bool isInputControl(Node* node);
+ Node* getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction);
+ bool isContentInputElement(Node* node);
+ bool isDescendantOf(Node* parent, Node* node);
+ void advanceAnchorNode(DOMSelection* selection, int direction, String& markup, bool ignoreFirstNode, ExceptionCode& ec);
+ Node* getNextAnchorNode(Node* anchorNode, bool skipFirstHack, int direction);
+ Node* getImplicitAnchorOrFocusNode(Node* node, unsigned offset, int direction);
#if ENABLE(TOUCH_EVENTS)
bool m_forwardingTouchEvents;
diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp
index 27eebd3..b25ad7d 100644
--- a/WebKit/android/nav/CachedFrame.cpp
+++ b/WebKit/android/nav/CachedFrame.cpp
@@ -50,13 +50,17 @@ WebCore::IntRect CachedFrame::adjustBounds(const CachedNode* node,
mRoot->mViewBounds.x(), mRoot->mViewBounds.y(),
mRoot->mViewBounds.width(), mRoot->mViewBounds.height());
#if USE(ACCELERATED_COMPOSITING)
- if (mRoot) {
- const CachedLayer* cachedLayer = layer(node);
- const WebCore::LayerAndroid* rootLayer = mRoot->rootLayer();
- const LayerAndroid* aLayer = cachedLayer->layer(rootLayer);
- if (aLayer)
- return cachedLayer->adjustBounds(rootLayer, rect);
- }
+ if (!mRoot)
+ return rect;
+
+ const CachedLayer* cachedLayer = layer(node);
+ if (!cachedLayer)
+ return rect;
+
+ const WebCore::LayerAndroid* rootLayer = mRoot->rootLayer();
+ const LayerAndroid* aLayer = cachedLayer->layer(rootLayer);
+ if (aLayer)
+ return cachedLayer->adjustBounds(rootLayer, rect);
#endif
return rect;
}
diff --git a/WebKit/android/nav/CachedLayer.cpp b/WebKit/android/nav/CachedLayer.cpp
index c8220b3..d5385bd 100644
--- a/WebKit/android/nav/CachedLayer.cpp
+++ b/WebKit/android/nav/CachedLayer.cpp
@@ -177,7 +177,6 @@ void CachedLayer::Debug::print() const
{
CachedLayer* b = base();
DUMP_NAV_LOGD(" // int mCachedNodeIndex=%d;\n", b->mCachedNodeIndex);
- DUMP_NAV_LOGD(" // LayerAndroid* mLayer=%p;\n", b->mLayer);
DUMP_NAV_LOGD(" // int mOffset=(%d, %d);\n",
b->mOffset.x(), b->mOffset.y());
DUMP_NAV_LOGD(" // int mUniqueId=%p;\n", b->mUniqueId);
diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp
index f84f8b0..948ea6b 100644
--- a/WebKit/android/nav/WebView.cpp
+++ b/WebKit/android/nav/WebView.cpp
@@ -206,7 +206,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) :
// We must remove the m_glWebViewState prior to deleting m_baseLayer. If we
// do not remove it here, we risk having BaseTiles trying to paint using a
// deallocated base layer.
- delete m_glWebViewState;
+ stopGL();
#endif
delete m_frameCacheUI;
delete m_navPictureUI;
@@ -214,6 +214,14 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) :
delete m_glDrawFunctor;
}
+void stopGL()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ delete m_glWebViewState;
+ m_glWebViewState = 0;
+#endif
+}
+
WebViewCore* getWebViewCore() const {
return m_viewImpl;
}
@@ -481,9 +489,7 @@ bool drawGL(WebCore::IntRect& viewRect, float scale, int extras)
SkRect visibleRect;
calcOurContentVisibleRect(&visibleRect);
- m_viewImpl->setVisibleScreenWidth(visibleRect.width());
- m_viewImpl->setVisibleScreenHeight(visibleRect.height());
- bool ret = m_baseLayer->drawGL(viewRect, visibleRect, scale);
+ bool ret = m_glWebViewState->drawGL(viewRect, visibleRect, scale);
if (ret || m_glWebViewState->currentPictureCounter() != pic)
return true;
#endif
@@ -545,8 +551,6 @@ PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split)
compositeLayer->setExtra(extra);
SkRect visible;
calcOurContentVisibleRect(&visible);
- m_viewImpl->setVisibleScreenWidth(visible.width());
- m_viewImpl->setVisibleScreenHeight(visible.height());
// call this to be sure we've adjusted for any scrolling or animations
// before we actually draw
compositeLayer->updateFixedLayersPositions(visible);
@@ -2207,6 +2211,11 @@ static void nativeDestroy(JNIEnv *env, jobject obj)
delete view;
}
+static void nativeStopGL(JNIEnv *env, jobject obj)
+{
+ GET_NATIVE_VIEW(env, obj)->stopGL();
+}
+
static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
{
WebView* view = GET_NATIVE_VIEW(env, obj);
@@ -2395,6 +2404,11 @@ static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x,
return false;
}
+static void nativeSetExpandedTileBounds(JNIEnv*, jobject, jboolean enabled)
+{
+ TilesManager::instance()->setExpandedTileBounds(enabled);
+}
+
/*
* JNI registration
*/
@@ -2559,6 +2573,8 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeShowCursorTimed },
{ "nativeStartSelection", "(II)Z",
(void*) nativeStartSelection },
+ { "nativeStopGL", "()V",
+ (void*) nativeStopGL },
{ "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
(void*) nativeSubtractLayers },
{ "nativeTextGeneration", "()I",
@@ -2573,6 +2589,8 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeScrollableLayer },
{ "nativeScrollLayer", "(III)Z",
(void*) nativeScrollLayer },
+ { "nativeSetExpandedTileBounds", "(Z)V",
+ (void*) nativeSetExpandedTileBounds },
};
int registerWebView(JNIEnv* env)
diff --git a/WebKit/android/plugins/ANPOpenGLInterface.cpp b/WebKit/android/plugins/ANPOpenGLInterface.cpp
index 8f5f9b4..015a04c 100644
--- a/WebKit/android/plugins/ANPOpenGLInterface.cpp
+++ b/WebKit/android/plugins/ANPOpenGLInterface.cpp
@@ -87,6 +87,9 @@ static void anp_releaseTexture(NPP instance, const ANPTextureInfo* textureInfo)
info->m_internalFormat = textureInfo->internalFormat;
texture->producerReleaseAndSwap();
+
+ // invalidate the java view so that this content is drawn
+ pluginWidget->viewInvalidate();
}
static void anp_invertPluginContent(NPP instance, bool isContentInverted) {
diff --git a/WebKit/android/plugins/PluginWidgetAndroid.cpp b/WebKit/android/plugins/PluginWidgetAndroid.cpp
index 4dc12a3..06506ba 100644
--- a/WebKit/android/plugins/PluginWidgetAndroid.cpp
+++ b/WebKit/android/plugins/PluginWidgetAndroid.cpp
@@ -132,7 +132,19 @@ void PluginWidgetAndroid::setWindow(NPWindow* window, bool isTransparent) {
m_pluginBounds.fRight, m_pluginBounds.fBottom);
const bool boundsChanged = m_pluginBounds != oldPluginBounds;
- sendSizeAndVisibilityEvents(boundsChanged);
+
+ //TODO hack to ensure that we grab the most recent screen dimensions and scale
+ ANPRectI screenCoords;
+ m_core->getVisibleScreen(screenCoords);
+ float scale = m_core->scale();
+ bool scaleChanged = m_cachedZoomLevel != scale;
+ setVisibleScreen(screenCoords, scale);
+
+ // if the scale changed then setVisibleScreen will call this function and
+ // this call will potentially fire a duplicate draw event
+ if (!scaleChanged) {
+ sendSizeAndVisibilityEvents(boundsChanged);
+ }
layoutSurface(boundsChanged);
if (m_drawingModel != kSurface_ANPDrawingModel) {
@@ -144,8 +156,14 @@ void PluginWidgetAndroid::setWindow(NPWindow* window, bool isTransparent) {
bool PluginWidgetAndroid::setDrawingModel(ANPDrawingModel model) {
- if (model == kOpenGL_ANPDrawingModel && m_layer == 0)
- m_layer = new WebCore::MediaLayer();
+ if (model == kOpenGL_ANPDrawingModel && m_layer == 0) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ jobject webview = m_core->getWebViewJavaObject();
+ jobject weakWebViewRef = 0;
+ if (webview)
+ weakWebViewRef = env->NewWeakGlobalRef(webview);
+ m_layer = new WebCore::MediaLayer(weakWebViewRef);
+ }
else if (model != kOpenGL_ANPDrawingModel && m_layer != 0)
m_layer->unref();
@@ -192,6 +210,12 @@ void PluginWidgetAndroid::inval(const WebCore::IntRect& rect,
}
}
+void PluginWidgetAndroid::viewInvalidate() {
+ WebCore::IntRect rect(m_pluginBounds.fLeft, m_pluginBounds.fTop,
+ m_pluginBounds.width(), m_pluginBounds.height());
+ m_core->viewInvalidate(rect);
+}
+
void PluginWidgetAndroid::draw(SkCanvas* canvas) {
if (NULL == m_flipPixelRef || !m_flipPixelRef->isDirty()) {
return;
@@ -563,7 +587,7 @@ void PluginWidgetAndroid::scrollToVisiblePluginRect() {
#if DEBUG_VISIBLE_RECTS
PLUGIN_LOG("%s call scrollBy (%d,%d)", __FUNCTION__, deltaX, deltaY);
#endif
- core->scrollBy(deltaX, deltaY, true);
+ core->scrollTo(rectCenterX, rectCenterY, true);
}
void PluginWidgetAndroid::requestFullScreen() {
diff --git a/WebKit/android/plugins/PluginWidgetAndroid.h b/WebKit/android/plugins/PluginWidgetAndroid.h
index 9726a22..5d586b1 100644
--- a/WebKit/android/plugins/PluginWidgetAndroid.h
+++ b/WebKit/android/plugins/PluginWidgetAndroid.h
@@ -177,6 +177,8 @@ struct PluginWidgetAndroid {
void setPowerState(ANPPowerState powerState);
+ void viewInvalidate();
+
private:
void computeVisiblePluginRect();
void scrollToVisiblePluginRect();