summaryrefslogtreecommitdiffstats
path: root/WebKit/android
diff options
context:
space:
mode:
Diffstat (limited to 'WebKit/android')
-rw-r--r--WebKit/android/RenderSkinAndroid.cpp4
-rw-r--r--WebKit/android/RenderSkinButton.cpp2
-rw-r--r--WebKit/android/RenderSkinCombo.cpp108
-rw-r--r--WebKit/android/RenderSkinCombo.h20
-rw-r--r--WebKit/android/RenderSkinMediaButton.cpp171
-rw-r--r--WebKit/android/RenderSkinMediaButton.h61
-rw-r--r--WebKit/android/RenderSkinRadio.cpp2
-rw-r--r--WebKit/android/TimeCounter.cpp9
-rw-r--r--WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp78
-rw-r--r--WebKit/android/WebCoreSupport/ChromeClientAndroid.h20
-rw-r--r--WebKit/android/WebCoreSupport/EditorClientAndroid.cpp2
-rw-r--r--WebKit/android/WebCoreSupport/FileSystemClient.h41
-rw-r--r--WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp86
-rw-r--r--WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h11
-rw-r--r--WebKit/android/WebCoreSupport/InspectorClientAndroid.h18
-rw-r--r--WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp544
-rw-r--r--WebKit/android/WebCoreSupport/PlatformBridge.cpp52
-rw-r--r--WebKit/android/WebCoreSupport/V8Counters.cpp2
-rw-r--r--WebKit/android/benchmark/Intercept.cpp2
-rw-r--r--WebKit/android/jni/JavaBridge.cpp19
-rw-r--r--WebKit/android/jni/JavaSharedClient.cpp12
-rw-r--r--WebKit/android/jni/JavaSharedClient.h4
-rw-r--r--WebKit/android/jni/MIMETypeRegistry.cpp5
-rwxr-xr-xWebKit/android/jni/MockGeolocation.cpp2
-rw-r--r--WebKit/android/jni/WebCoreFrameBridge.cpp193
-rw-r--r--WebKit/android/jni/WebCoreJniOnLoad.cpp9
-rw-r--r--WebKit/android/jni/WebCoreResourceLoader.cpp2
-rw-r--r--WebKit/android/jni/WebCoreViewBridge.h48
-rw-r--r--WebKit/android/jni/WebHistory.cpp12
-rw-r--r--WebKit/android/jni/WebHistory.h6
-rw-r--r--WebKit/android/jni/WebIconDatabase.cpp1
-rw-r--r--WebKit/android/jni/WebSettings.cpp20
-rw-r--r--WebKit/android/jni/WebViewCore.cpp681
-rw-r--r--WebKit/android/jni/WebViewCore.h55
-rw-r--r--WebKit/android/nav/CacheBuilder.cpp65
-rw-r--r--WebKit/android/nav/CacheBuilder.h2
-rw-r--r--WebKit/android/nav/CachedFrame.cpp1
-rw-r--r--WebKit/android/nav/CachedInput.cpp7
-rw-r--r--WebKit/android/nav/CachedInput.h5
-rw-r--r--WebKit/android/nav/CachedNode.cpp3
-rw-r--r--WebKit/android/nav/CachedNode.h4
-rw-r--r--WebKit/android/nav/CachedNodeType.h4
-rw-r--r--WebKit/android/nav/CachedPrefix.h7
-rw-r--r--WebKit/android/nav/FindCanvas.cpp3
-rw-r--r--WebKit/android/nav/FindCanvas.h1
-rw-r--r--WebKit/android/nav/SelectText.cpp1282
-rw-r--r--WebKit/android/nav/SelectText.h59
-rw-r--r--WebKit/android/nav/WebView.cpp361
-rw-r--r--WebKit/android/plugins/ANPSystemInterface.cpp5
-rw-r--r--WebKit/android/plugins/PluginDebugAndroid.cpp2
-rw-r--r--WebKit/android/plugins/PluginTimer.cpp12
-rw-r--r--WebKit/android/plugins/PluginTimer.h16
-rw-r--r--WebKit/android/plugins/PluginWidgetAndroid.cpp4
-rw-r--r--WebKit/android/plugins/PluginWidgetAndroid.h2
-rw-r--r--WebKit/android/smoke/MessageThread.cpp146
-rw-r--r--WebKit/android/smoke/MessageThread.h108
-rw-r--r--WebKit/android/smoke/MessageTypes.h159
-rw-r--r--WebKit/android/wds/Command.cpp2
58 files changed, 3524 insertions, 1038 deletions
diff --git a/WebKit/android/RenderSkinAndroid.cpp b/WebKit/android/RenderSkinAndroid.cpp
index d148262..00f2b96 100644
--- a/WebKit/android/RenderSkinAndroid.cpp
+++ b/WebKit/android/RenderSkinAndroid.cpp
@@ -29,6 +29,7 @@
#include "RenderSkinAndroid.h"
#include "RenderSkinButton.h"
#include "RenderSkinCombo.h"
+#include "RenderSkinMediaButton.h"
#include "RenderSkinRadio.h"
#include "SkImageDecoder.h"
@@ -45,7 +46,8 @@ RenderSkinAndroid::RenderSkinAndroid()
void RenderSkinAndroid::Init(android::AssetManager* am, String drawableDirectory)
{
RenderSkinButton::Init(am, drawableDirectory);
- RenderSkinCombo::Init(am);
+ RenderSkinCombo::Init(am, drawableDirectory);
+ RenderSkinMediaButton::Init(am, drawableDirectory);
RenderSkinRadio::Init(am, drawableDirectory);
}
diff --git a/WebKit/android/RenderSkinButton.cpp b/WebKit/android/RenderSkinButton.cpp
index 63f545a..ff739f6 100644
--- a/WebKit/android/RenderSkinButton.cpp
+++ b/WebKit/android/RenderSkinButton.cpp
@@ -26,7 +26,6 @@
#define LOG_TAG "WebCore"
#include "config.h"
-#include "CString.h"
#include "android_graphics.h"
#include "Document.h"
#include "IntRect.h"
@@ -37,6 +36,7 @@
#include "SkRect.h"
#include <utils/Debug.h>
#include <utils/Log.h>
+#include <wtf/text/CString.h>
struct PatchData {
const char* name;
diff --git a/WebKit/android/RenderSkinCombo.cpp b/WebKit/android/RenderSkinCombo.cpp
index 6f88ee3..b30dc29 100644
--- a/WebKit/android/RenderSkinCombo.cpp
+++ b/WebKit/android/RenderSkinCombo.cpp
@@ -33,67 +33,113 @@
#include "RenderStyle.h"
#include "SkCanvas.h"
#include "SkNinePatch.h"
+#include <wtf/text/CString.h>
namespace WebCore {
-static SkBitmap s_bitmap[2]; // Collection of assets for a combo box
-static bool s_decoded; // True if all assets were decoded
-static const int s_margin = 2;
-static const SkIRect s_mar = { s_margin, s_margin,
- RenderSkinCombo::extraWidth(), s_margin };
-static SkIRect s_subset;
+// Indicates if the entire asset is being drawn, or if the border is being
+// excluded and just the arrow drawn.
+enum BorderStyle {
+ FullAsset,
+ NoBorder
+};
+// There are 2.5 different concepts of a 'border' here, which results
+// in rather a lot of magic constants. In each case, there are 2
+// numbers, one for medium res and one for high-res. All sizes are in pixels.
-RenderSkinCombo::RenderSkinCombo()
-{
-}
+// Firstly, we have the extra padding that webkit needs to know about,
+// which defines how much bigger this element is made by the
+// asset. This is actually a bit broader than the actual border on the
+// asset, to make things look less cramped. The border is the same
+// width on all sides, except on the right when it's significantly
+// wider to allow for the arrow.
+const int RenderSkinCombo::arrowMargin[2] = {22, 34};
+const int RenderSkinCombo::padMargin[2] = {2, 5};
+
+// Then we have the borders used for the 9-patch stretch. The
+// rectangle at the centre of these borders is entirely below and to
+// the left of the arrow in the asset. Hence the border widths are the
+// same for the bottom and left, but are different for the top. The
+// right hand border width happens to be the same as arrowMargin
+// defined above.
+static const int stretchMargin[2] = {3, 5}; // border width for the bottom and left of the 9-patch
+static const int stretchTop[2] = {15, 23}; // border width for the top of the 9-patch
+
+// Finally, if the border is defined by the CSS, we only draw the
+// arrow and not the border. We do this by drawing the relevant subset
+// of the bitmap, which must now be precisely determined by what's in
+// the asset with no extra padding to make things look properly
+// spaced. The border to remove at the top, right and bottom of the
+// image is the same as stretchMargin above, but we need to know the width
+// of the arrow.
+static const int arrowWidth[2] = {22, 31};
+
+RenderSkinCombo::Resolution RenderSkinCombo::resolution = MedRes;
+
+const SkIRect RenderSkinCombo::margin[2][2] = {{{ stretchMargin[MedRes], stretchTop[MedRes],
+ RenderSkinCombo::arrowMargin[MedRes] + stretchMargin[MedRes], stretchMargin[MedRes] },
+ {0, stretchTop[MedRes], 0, stretchMargin[MedRes]}},
+ {{ stretchMargin[HighRes], stretchTop[HighRes],
+ RenderSkinCombo::arrowMargin[HighRes] + stretchMargin[HighRes], stretchMargin[HighRes] },
+ {0, stretchTop[HighRes], 0, stretchMargin[HighRes]}}};
+static SkBitmap bitmaps[2][2]; // Collection of assets for a combo box
+static bool isDecoded; // True if all assets were decoded
-void RenderSkinCombo::Init(android::AssetManager* am)
+void RenderSkinCombo::Init(android::AssetManager* am, String drawableDirectory)
{
- if (s_decoded)
+ if (isDecoded)
return;
- // Maybe short circuiting is fine, since I don't even draw if one state is not decoded properly
- // but is that necessary in the final version?
- s_decoded = RenderSkinAndroid::DecodeBitmap(am, "images/combobox-noHighlight.png", &s_bitmap[kNormal]);
- s_decoded = RenderSkinAndroid::DecodeBitmap(am, "images/combobox-disabled.png", &s_bitmap[kDisabled]) && s_decoded;
-
- int width = s_bitmap[kNormal].width();
- int height = s_bitmap[kNormal].height();
- s_subset.set(width - RenderSkinCombo::extraWidth() + s_margin, 0, width, height);
+
+ if (drawableDirectory[drawableDirectory.length() - 5] == 'h')
+ resolution = HighRes;
+
+ isDecoded = RenderSkinAndroid::DecodeBitmap(am, (drawableDirectory + "combobox_nohighlight.png").utf8().data(), &bitmaps[kNormal][FullAsset]);
+ isDecoded &= RenderSkinAndroid::DecodeBitmap(am, (drawableDirectory + "combobox_disabled.png").utf8().data(), &bitmaps[kDisabled][FullAsset]);
+
+ int width = bitmaps[kNormal][FullAsset].width();
+ int height = bitmaps[kNormal][FullAsset].height();
+ SkIRect subset;
+ subset.set(width - arrowWidth[resolution], 0, width, height);
+ bitmaps[kNormal][FullAsset].extractSubset(&bitmaps[kNormal][NoBorder], subset);
+ bitmaps[kDisabled][FullAsset].extractSubset(&bitmaps[kDisabled][NoBorder], subset);
}
bool RenderSkinCombo::Draw(SkCanvas* canvas, Node* element, int x, int y, int width, int height)
{
- if (!s_decoded)
+ if (!isDecoded)
return true;
State state = (element->isElementNode() && static_cast<Element*>(element)->isEnabledFormControl()) ? kNormal : kDisabled;
- if (height < (s_margin<<1) + 1) {
- height = (s_margin<<1) + 1;
- }
+ height = std::max(height, (stretchMargin[resolution]<<1) + 1);
+
SkRect bounds;
+ BorderStyle drawBorder = FullAsset;
bounds.set(SkIntToScalar(x+1), SkIntToScalar(y+1), SkIntToScalar(x + width-1), SkIntToScalar(y + height-1));
RenderStyle* style = element->renderStyle();
SkPaint paint;
- paint.setColor(style->backgroundColor().rgb());
+ paint.setColor(style->visitedDependentColor(CSSPropertyBackgroundColor).rgb());
canvas->drawRect(bounds, paint);
bounds.set(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + width), SkIntToScalar(y + height));
- if (style->borderLeftColor().isValid() ||
- style->borderRightColor().isValid() ||
- style->borderTopColor().isValid() ||
- style->borderBottomColor().isValid()) {
+ // If this is an appearance where RenderTheme::paint returns true
+ // without doing anything, this means that
+ // RenderBox::PaintBoxDecorationWithSize will end up painting the
+ // border, so we shouldn't paint a border here.
+ if (style->appearance() == MenulistButtonPart ||
+ style->appearance() == ListboxPart ||
+ style->appearance() == TextFieldPart ||
+ style->appearance() == TextAreaPart) {
bounds.fLeft += SkIntToScalar(width - RenderSkinCombo::extraWidth());
bounds.fRight -= SkIntToScalar(style->borderRightWidth());
bounds.fTop += SkIntToScalar(style->borderTopWidth());
bounds.fBottom -= SkIntToScalar(style->borderBottomWidth());
- canvas->drawBitmapRect(s_bitmap[state], &s_subset, bounds);
- } else {
- SkNinePatch::DrawNine(canvas, bounds, s_bitmap[state], s_mar);
+ drawBorder = NoBorder;
}
+ SkNinePatch::DrawNine(canvas, bounds, bitmaps[state][drawBorder], margin[resolution][drawBorder]);
return false;
}
diff --git a/WebKit/android/RenderSkinCombo.h b/WebKit/android/RenderSkinCombo.h
index 91c9367..38cd048 100644
--- a/WebKit/android/RenderSkinCombo.h
+++ b/WebKit/android/RenderSkinCombo.h
@@ -37,13 +37,10 @@ namespace WebCore {
class RenderSkinCombo : public RenderSkinAndroid
{
public:
- RenderSkinCombo();
- virtual ~RenderSkinCombo() {}
-
/**
* Initialize the class before use. Uses the AssetManager to initialize any bitmaps the class may use.
*/
- static void Init(android::AssetManager*);
+ static void Init(android::AssetManager*, String drawableDirectory);
/**
* Draw the provided Node on the SkCanvas, using the dimensions provided by
@@ -53,11 +50,18 @@ public:
static bool Draw(SkCanvas* , Node* , int x, int y, int w, int h);
// The image is wider than the RenderObject, so this accounts for that.
- static int extraWidth() { return arrowMargin; }
-
+ static int extraWidth() { return arrowMargin[resolution]; }
+ static int padding() { return padMargin[resolution]; }
+
+ enum Resolution {
+ MedRes,
+ HighRes
+ };
private:
-
- static const int arrowMargin = 22;
+ static Resolution resolution;
+ const static int arrowMargin[2];
+ const static int padMargin[2];
+ const static SkIRect margin[2][2];
};
} // WebCore
diff --git a/WebKit/android/RenderSkinMediaButton.cpp b/WebKit/android/RenderSkinMediaButton.cpp
new file mode 100644
index 0000000..9055e89
--- /dev/null
+++ b/WebKit/android/RenderSkinMediaButton.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "WebCore"
+
+#include "config.h"
+#include "android_graphics.h"
+#include "Document.h"
+#include "IntRect.h"
+#include "Node.h"
+#include "RenderSkinMediaButton.h"
+#include "SkCanvas.h"
+#include "SkNinePatch.h"
+#include "SkRect.h"
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <wtf/text/CString.h>
+
+struct PatchData {
+ const char* name;
+ int8_t outset, margin;
+};
+
+static const PatchData gFiles[] =
+ {
+ { "btn_media_player.9.png", 0, 0 }, // DEFAULT BGD BUTTON
+ { "ic_media_pause.png", 0, 0}, // PAUSE
+ { "ic_media_play.png", 0, 0 }, // PLAY
+ { "ic_media_pause.png", 0, 0 }, // MUTE
+ { "ic_media_rew.png", 0, 0 }, // REWIND
+ { "ic_media_ff.png", 0, 0 }, // FORWARD
+ { "btn_media_player_disabled.9.png", 0, 0 }, // BACKGROUND_SLIDER
+ { "btn_media_player_pressed.9.png", 0, 0 }, // SLIDER_TRACK
+ { "btn_media_player.9.png", 0, 0 } // SLIDER_THUMB
+ };
+
+static SkBitmap gButton[sizeof(gFiles)/sizeof(gFiles[0])];
+static bool gDecoded;
+static bool gHighRes;
+
+namespace WebCore {
+
+void RenderSkinMediaButton::Init(android::AssetManager* am, String drawableDirectory)
+{
+ static bool gInited;
+ if (gInited)
+ return;
+
+ gInited = true;
+ gDecoded = true;
+ gHighRes = drawableDirectory[drawableDirectory.length() - 5] == 'h';
+ for (size_t i = 0; i < sizeof(gFiles)/sizeof(gFiles[0]); i++) {
+ String path = drawableDirectory + gFiles[i].name;
+ if (!RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &gButton[i])) {
+ gDecoded = false;
+ LOGD("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw");
+ break;
+ }
+ }
+}
+
+void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonType)
+{
+ // If we failed to decode, do nothing. This way the browser still works,
+ // and webkit will still draw the label and layout space for us.
+ if (!gDecoded) {
+ return;
+ }
+
+ bool drawsNinePatch = true;
+ bool drawsImage = true;
+ bool drawsBackgroundColor = false;
+
+ int ninePatchIndex = 0;
+ int imageIndex = 0;
+
+ SkRect bounds(r);
+ SkScalar imageMargin = 8;
+ SkPaint paint;
+ SkColor backgroundColor = SkColorSetARGB(255, 200, 200, 200);
+ SkColor trackBackgroundColor = SkColorSetARGB(255, 100, 100, 100);
+
+ switch (buttonType) {
+ case PAUSE:
+ case PLAY:
+ case MUTE:
+ case REWIND:
+ case FORWARD:
+ {
+ imageIndex = buttonType + 1;
+ drawsBackgroundColor = true;
+ paint.setColor(backgroundColor);
+ break;
+ }
+ case BACKGROUND_SLIDER:
+ {
+ drawsImage = false;
+ drawsNinePatch = false;
+ drawsBackgroundColor = true;
+ paint.setColor(backgroundColor);
+ break;
+ }
+ case SLIDER_TRACK:
+ {
+ drawsImage = false;
+ drawsNinePatch = false;
+ drawsBackgroundColor = true;
+ paint.setColor(trackBackgroundColor);
+ bounds.fTop += 8;
+ bounds.fBottom -= 8;
+ break;
+ }
+ case SLIDER_THUMB:
+ {
+ drawsImage = false;
+ ninePatchIndex = buttonType + 1;
+ break;
+ }
+ default:
+ drawsImage = false;
+ drawsNinePatch = false;
+ }
+
+ if (drawsBackgroundColor) {
+ canvas->drawRect(r, paint);
+ }
+
+ if (drawsNinePatch) {
+ const PatchData& pd = gFiles[ninePatchIndex];
+ int marginValue = pd.margin + pd.outset;
+
+ SkIRect margin;
+ margin.set(marginValue, marginValue, marginValue, marginValue);
+ SkNinePatch::DrawNine(canvas, bounds, gButton[0], margin);
+ }
+
+ if (drawsImage) {
+ SkScalar SIZE = gButton[imageIndex].width();
+ SkScalar width = r.width();
+ SkScalar scale = SkScalarDiv(width - 2*imageMargin, SIZE);
+ int saveScaleCount = canvas->save();
+ canvas->translate(bounds.fLeft + imageMargin, bounds.fTop + imageMargin);
+ canvas->scale(scale, scale);
+ canvas->drawBitmap(gButton[imageIndex], 0, 0, &paint);
+ canvas->restoreToCount(saveScaleCount);
+ }
+}
+
+} //WebCore
diff --git a/WebKit/android/RenderSkinMediaButton.h b/WebKit/android/RenderSkinMediaButton.h
new file mode 100644
index 0000000..b4e99f4
--- /dev/null
+++ b/WebKit/android/RenderSkinMediaButton.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RenderSkinMediaButton_h
+#define RenderSkinMediaButton_h
+
+#include "RenderSkinAndroid.h"
+
+class SkCanvas;
+
+namespace WebCore {
+class IntRect;
+class RenderSkinMediaButton
+{
+public:
+ /**
+ * Initialize the class before use. Uses the AssetManager to initialize any
+ * bitmaps the class may use.
+ */
+ static void Init(android::AssetManager*, String drawableDirectory);
+ /**
+ * Draw the skin to the canvas, using the rectangle for its bounds and the
+ * State to determine which skin to use, i.e. focused or not focused.
+ */
+ static void Draw(SkCanvas* , const IntRect& , int buttonType);
+ /**
+ * Button types
+ */
+ enum { PAUSE, PLAY, MUTE, REWIND, FORWARD, BACKGROUND_SLIDER, SLIDER_TRACK, SLIDER_THUMB };
+ /**
+ * Slider dimensions
+ */
+ static int sliderThumbWidth() { return 10; }
+ static int sliderThumbHeight() { return 30; }
+
+};
+
+} // WebCore
+#endif // RenderSkinMediaButton_h
diff --git a/WebKit/android/RenderSkinRadio.cpp b/WebKit/android/RenderSkinRadio.cpp
index a1fc659..ef26f01 100644
--- a/WebKit/android/RenderSkinRadio.cpp
+++ b/WebKit/android/RenderSkinRadio.cpp
@@ -26,7 +26,6 @@
#include "config.h"
#include "RenderSkinRadio.h"
-#include "CString.h"
#include "android_graphics.h"
#include "Document.h"
#include "Element.h"
@@ -37,6 +36,7 @@
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkRect.h"
+#include <wtf/text/CString.h>
static const char* checks[] = { "btn_check_off.png",
"btn_check_on.png",
diff --git a/WebKit/android/TimeCounter.cpp b/WebKit/android/TimeCounter.cpp
index da09b07..4062bc2 100644
--- a/WebKit/android/TimeCounter.cpp
+++ b/WebKit/android/TimeCounter.cpp
@@ -28,17 +28,16 @@
#include "config.h"
#include "TimeCounter.h"
-#include "CString.h"
#include "Cache.h"
#include "KURL.h"
#include "Node.h"
#include "SystemTime.h"
#include "StyleBase.h"
-#include <utils/Log.h>
-#include <wtf/CurrentTime.h>
-
#include <sys/time.h>
#include <time.h>
+#include <utils/Log.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/text/CString.h>
#if USE(JSC)
#include "JSDOMWindow.h"
@@ -94,7 +93,7 @@ static const char* timeCounterNames[] = {
"javascript execution",
"calculate style",
"Java callback (frame bridge)",
- "parsing (may include calcStyle or Java callback)",
+ "parsing (may include calcStyle, Java callback or inline script execution)",
"layout",
"native 1 (frame bridge)",
"native 2 (resource load)",
diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
index c258d79..30ac36c 100644
--- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
@@ -29,7 +29,6 @@
#include "ApplicationCacheStorage.h"
#include "ChromeClientAndroid.h"
-#include "CString.h"
#include "DatabaseTracker.h"
#include "Document.h"
#include "PlatformString.h"
@@ -39,14 +38,15 @@
#include "FrameView.h"
#include "Geolocation.h"
#include "GraphicsLayerAndroid.h"
+#include "Icon.h"
#include "Page.h"
-#include "Screen.h"
#include "ScriptController.h"
#include "WebCoreFrameBridge.h"
#include "WebCoreViewBridge.h"
#include "WebViewCore.h"
#include "WindowFeatures.h"
#include "Settings.h"
+#include <wtf/text/CString.h>
namespace android {
@@ -56,28 +56,19 @@ static unsigned long long tryToReclaimDatabaseQuota(SecurityOrigin* originNeedin
#if USE(ACCELERATED_COMPOSITING)
-void ChromeClientAndroid::syncTimerFired(Timer<ChromeClientAndroid>* client)
+WebCore::GraphicsLayer* ChromeClientAndroid::layersSync()
{
- if (!m_rootGraphicsLayer)
- return;
-
- if (m_webFrame) {
- FrameView* frameView = m_webFrame->page()->mainFrame()->view();
- if (frameView && frameView->syncCompositingStateRecursive()) {
- GraphicsLayerAndroid* androidGraphicsLayer =
- static_cast<GraphicsLayerAndroid*>(m_rootGraphicsLayer);
- if (androidGraphicsLayer) {
- androidGraphicsLayer->sendImmediateRepaint();
- androidGraphicsLayer->notifyClientAnimationStarted();
- }
- }
+ if (m_rootGraphicsLayer && m_needsLayerSync && m_webFrame) {
+ if (FrameView* frameView = m_webFrame->page()->mainFrame()->view())
+ frameView->syncCompositingStateRecursive();
}
+ m_needsLayerSync = false;
+ return m_rootGraphicsLayer;
}
void ChromeClientAndroid::scheduleCompositingLayerSync()
{
- if (!m_syncTimer.isActive())
- m_syncTimer.startOneShot(0);
+ m_needsLayerSync = true;
}
void ChromeClientAndroid::setNeedsOneShotDrawingSynchronization()
@@ -85,15 +76,12 @@ void ChromeClientAndroid::setNeedsOneShotDrawingSynchronization()
// This should not be needed
}
-void ChromeClientAndroid::attachRootGraphicsLayer(WebCore::Frame* frame, WebCore::GraphicsLayer* layer)
+void ChromeClientAndroid::attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer* layer)
{
+ // frame is not used in Android as we should only get root graphics layer for the main frame
m_rootGraphicsLayer = layer;
- if (!layer) {
- WebViewCore::getWebViewCore(frame->view())->setUIRootLayer(0);
+ if (!layer)
return;
- }
- WebCore::GraphicsLayerAndroid* androidGraphicsLayer = static_cast<GraphicsLayerAndroid*>(layer);
- androidGraphicsLayer->setFrame(frame);
scheduleCompositingLayerSync();
}
@@ -166,10 +154,10 @@ Page* ChromeClientAndroid::createWindow(Frame* frame, const FrameLoadRequest&,
return frame->page();
#endif
- WTF::PassRefPtr<WebCore::Screen> screen = WebCore::Screen::create(frame);
+ const WebCoreViewBridge* bridge = frame->view()->platformWidget();
bool dialog = features.dialog || !features.resizable
- || (features.heightSet && features.height < screen.get()->height()
- && features.widthSet && features.width < screen.get()->width())
+ || (features.heightSet && features.height < bridge->height()
+ && features.widthSet && features.width < bridge->width())
|| (!features.menuBarVisible && !features.statusBarVisible
&& !features.toolBarVisible && !features.locationBarVisible
&& !features.scrollbarsVisible);
@@ -276,12 +264,19 @@ bool ChromeClientAndroid::tabsToLinks() const { return false; }
IntRect ChromeClientAndroid::windowResizerRect() const { return IntRect(0, 0, 0, 0); }
-// new to change 38068 (Nov 6, 2008)
-void ChromeClientAndroid::repaint(const IntRect& rect, bool contentChanged,
- bool immediate, bool repaintContentOnly) {
- notImplemented();
-// was in ScrollViewAndroid::update() : needs to be something like:
-// android::WebViewCore::getWebViewCore(this)->contentInvalidate(rect);
+void ChromeClientAndroid::invalidateWindow(const IntRect&, bool)
+{
+ notImplemented();
+}
+
+void ChromeClientAndroid::invalidateContentsAndWindow(const IntRect& updateRect, bool /*immediate*/)
+{
+ notImplemented();
+}
+
+void ChromeClientAndroid::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate)
+{
+ notImplemented();
}
// new to change 38068 (Nov 6, 2008)
@@ -461,7 +456,7 @@ void ChromeClientAndroid::requestGeolocationPermissionForFrame(Frame* frame, Geo
m_geolocationPermissions->queryPermissionState(frame);
}
-void ChromeClientAndroid::cancelGeolocationPermissionRequestForFrame(Frame* frame)
+void ChromeClientAndroid::cancelGeolocationPermissionRequestForFrame(Frame* frame, WebCore::Geolocation*)
{
if (m_geolocationPermissions)
m_geolocationPermissions->cancelPermissionStateQuery(frame);
@@ -492,6 +487,11 @@ void ChromeClientAndroid::runOpenPanel(Frame* frame,
core->openFileChooser(chooser);
}
+void ChromeClientAndroid::chooseIconForFiles(const Vector<WebCore::String>&, FileChooser*)
+{
+ notImplemented();
+}
+
bool ChromeClientAndroid::setCursor(PlatformCursorHandle)
{
notImplemented();
@@ -514,4 +514,14 @@ void ChromeClientAndroid::needTouchEvents(bool needTouchEvents)
}
#endif
+#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS)
+void ChromeClientAndroid::webAppCanBeInstalled()
+{
+ FrameView* frameView = m_webFrame->page()->mainFrame()->view();
+ android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView);
+ if (core)
+ core->notifyWebAppCanBeInstalled();
+}
+#endif
+
}
diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h
index 68cac24..a1f097c 100644
--- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h
+++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h
@@ -46,8 +46,7 @@ namespace android {
ChromeClientAndroid() : m_webFrame(0), m_geolocationPermissions(0)
#if USE(ACCELERATED_COMPOSITING)
, m_rootGraphicsLayer(0)
- , m_askToDrawAgain(false)
- , m_syncTimer(this, &ChromeClientAndroid::syncTimerFired)
+ , m_needsLayerSync(false)
#endif
, m_triedToReclaimDBQuota(false)
{ }
@@ -113,7 +112,9 @@ namespace android {
virtual IntRect windowResizerRect() const;
// Methods used by HostWindow.
- virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false);
+ virtual void invalidateWindow(const WebCore::IntRect&, bool);
+ virtual void invalidateContentsAndWindow(const WebCore::IntRect&, bool);
+ virtual void invalidateContentsForSlowScroll(const WebCore::IntRect&, bool);
virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect);
virtual IntPoint screenToWindow(const IntPoint&) const;
virtual IntRect windowToScreen(const IntRect&) const;
@@ -143,7 +144,7 @@ namespace android {
// Methods used to request and provide Geolocation permissions.
virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*);
- virtual void cancelGeolocationPermissionRequestForFrame(Frame*);
+ virtual void cancelGeolocationPermissionRequestForFrame(WebCore::Frame*, WebCore::Geolocation*);
// Android-specific
void provideGeolocationPermissions(const String &origin, bool allow, bool remember);
void storeGeolocationPermissions();
@@ -151,6 +152,7 @@ namespace android {
virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>);
virtual bool setCursor(PlatformCursorHandle);
+ virtual void chooseIconForFiles(const WTF::Vector<WebCore::String>&, FileChooser*);
// Notification that the given form element has changed. This function
// will be called frequently, so handling should be very fast.
@@ -160,13 +162,18 @@ namespace android {
// Android-specific
void setWebFrame(android::WebFrame* webframe);
+ android::WebFrame* webFrame() { return m_webFrame; }
void wakeUpMainThreadWithNewQuota(long newQuota);
#if USE(ACCELERATED_COMPOSITING)
virtual void attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer* g);
virtual void setNeedsOneShotDrawingSynchronization();
virtual void scheduleCompositingLayerSync();
- void syncTimerFired(Timer<ChromeClientAndroid>*);
+ WebCore::GraphicsLayer* layersSync();
+#endif
+
+#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS)
+ virtual void webAppCanBeInstalled();
#endif
private:
@@ -175,8 +182,7 @@ namespace android {
OwnPtr<GeolocationPermissions> m_geolocationPermissions;
#if USE(ACCELERATED_COMPOSITING)
WebCore::GraphicsLayer* m_rootGraphicsLayer;
- bool m_askToDrawAgain;
- Timer<ChromeClientAndroid> m_syncTimer;
+ bool m_needsLayerSync;
#endif
WTF::ThreadCondition m_quotaThreadCondition;
WTF::Mutex m_quotaThreadLock;
diff --git a/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp b/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
index c07ea71..718a30c 100644
--- a/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
@@ -32,12 +32,12 @@
#include "EventNames.h"
#include "FocusController.h"
#include "Frame.h"
-#include "KeyboardCodes.h"
#include "KeyboardEvent.h"
#include "NotImplemented.h"
#include "PlatformKeyboardEvent.h"
#include "PlatformString.h"
#include "WebViewCore.h"
+#include "WindowsKeyboardCodes.h"
namespace android {
diff --git a/WebKit/android/WebCoreSupport/FileSystemClient.h b/WebKit/android/WebCoreSupport/FileSystemClient.h
new file mode 100644
index 0000000..5bde18a
--- /dev/null
+++ b/WebKit/android/WebCoreSupport/FileSystemClient.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FILESYSTEM_CLIENT_H
+#define FILESYSTEM_CLIENT_H
+
+#include "PlatformString.h"
+
+using namespace WebCore;
+
+namespace android {
+
+class FileSystemClient {
+public:
+ virtual ~FileSystemClient() { }
+ virtual String resolveFilePathForContentUri(const String&) = 0;
+};
+}
+#endif
diff --git a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
index 9112afe..9278bf8 100644
--- a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
@@ -29,9 +29,10 @@
#include "FrameLoaderClientAndroid.h"
#include "BackForwardList.h"
-#include "CString.h"
#include "CachedFrame.h"
#include "CachedFramePlatformDataAndroid.h"
+#include "Chrome.h"
+#include "ChromeClientAndroid.h"
#include "DOMImplementation.h"
#include "Document.h"
#include "DocumentLoader.h"
@@ -75,6 +76,7 @@
#include "android_graphics.h"
#include <utils/AssetManager.h>
+#include <wtf/text/CString.h>
extern android::AssetManager* globalAssetManager();
@@ -393,7 +395,9 @@ void FrameLoaderClientAndroid::dispatchDidFinishLoad() {
void FrameLoaderClientAndroid::dispatchDidFirstLayout() {
ASSERT(m_frame);
- m_frame->document()->setExtraLayoutDelay(EXTRA_LAYOUT_DELAY);
+ // set EXTRA_LAYOUT_DELAY if the loader is not completed yet
+ if (!m_frame->loader()->isComplete())
+ m_frame->document()->setExtraLayoutDelay(EXTRA_LAYOUT_DELAY);
// we need to do this here instead of dispatchDidFirstVisuallyNonEmptyLayout
// so that about:blank will update the screen.
if (!m_frame->tree()->parent()) {
@@ -459,8 +463,11 @@ void FrameLoaderClientAndroid::dispatchDecidePolicyForMIMEType(FramePolicyFuncti
ASSERT(func);
if (!func)
return;
+
+ PolicyChecker* policy = m_frame->loader()->policyChecker();
+
if (request.isNull()) {
- (m_frame->loader()->policyChecker()->*func)(PolicyIgnore);
+ (policy->*func)(PolicyIgnore);
return;
}
// Default to Use (display internally).
@@ -468,30 +475,33 @@ void FrameLoaderClientAndroid::dispatchDecidePolicyForMIMEType(FramePolicyFuncti
// Check if we should Download instead.
const ResourceResponse& response = m_frame->loader()->activeDocumentLoader()->response();
const String& content_disposition = response.httpHeaderField("Content-Disposition");
- if (!content_disposition.isEmpty()) {
+ if (!content_disposition.isEmpty() &&
+ TreatAsAttachment(content_disposition)) {
// Server wants to override our normal policy.
- if (TreatAsAttachment(content_disposition)) {
- // Check to see if we are a sub frame (main frame has no owner element)
- if (m_frame->ownerElement() != 0)
- action = PolicyIgnore;
- else
- action = PolicyDownload;
- }
- } else {
- // Ask if it can be handled internally.
- if (!canShowMIMEType(MIMEType)) {
- // Check to see if we are a sub frame (main frame has no owner element)
- if (m_frame->ownerElement() != 0)
- action = PolicyIgnore;
- else
- action = PolicyDownload;
- }
+ // Check to see if we are a sub frame (main frame has no owner element)
+ if (m_frame->ownerElement() != 0)
+ action = PolicyIgnore;
+ else
+ action = PolicyDownload;
+ (policy->*func)(action);
+ return;
+ }
+
+ // Ask if it can be handled internally.
+ if (!canShowMIMEType(MIMEType)) {
+ // Check to see if we are a sub frame (main frame has no owner element)
+ if (m_frame->ownerElement() != 0)
+ action = PolicyIgnore;
+ else
+ action = PolicyDownload;
+ (policy->*func)(action);
+ return;
}
// A status code of 204 indicates no content change. Ignore the result.
WebCore::DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader();
if (docLoader->response().httpStatusCode() == 204)
action = PolicyIgnore;
- (m_frame->loader()->policyChecker()->*func)(action);
+ (policy->*func)(action);
}
void FrameLoaderClientAndroid::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction func,
@@ -693,7 +703,7 @@ void FrameLoaderClientAndroid::committedLoad(DocumentLoader* loader, const char*
bool userChosen = !encoding.isNull();
if (encoding.isNull())
encoding = loader->response().textEncodingName();
- loader->frameLoader()->setEncoding(encoding, userChosen);
+ loader->frameLoader()->writer()->setEncoding(encoding, userChosen);
Document *doc = m_frame->document();
if (doc)
loader->frameLoader()->addData(data, length);
@@ -800,7 +810,7 @@ void FrameLoaderClientAndroid::saveViewStateToItem(HistoryItem* item) {
if (!m_frame->tree()->parent()) {
WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view());
bridge->setScale((int)(webViewCore->scale() * 100));
- bridge->setScreenWidthScale((int)(webViewCore->screenWidthScale() * 100));
+ bridge->setTextWrapScale((int)(webViewCore->textWrapScale() * 100));
}
WebCore::notifyHistoryItemChanged(item);
@@ -812,11 +822,7 @@ void FrameLoaderClientAndroid::restoreViewState() {
AndroidWebHistoryBridge* bridge = item->bridge();
// restore the scale (only) for the top frame
if (!m_frame->tree()->parent()) {
- int scale = bridge->scale();
- webViewCore->restoreScale(scale);
- int screenWidthScale = bridge->screenWidthScale();
- if (screenWidthScale != scale)
- webViewCore->restoreScreenWidthScale(screenWidthScale);
+ webViewCore->restoreScale(bridge->scale(), bridge->textWrapScale());
}
}
@@ -899,14 +905,17 @@ void FrameLoaderClientAndroid::transitionToCommittedForNewPage() {
// Save the old WebFrameView's bounds and apply them to the new WebFrameView
WebFrameView* oldWebFrameView = static_cast<WebFrameView*> (m_frame->view()->platformWidget());
IntRect bounds = oldWebFrameView->getBounds();
+ IntRect visBounds = oldWebFrameView->getVisibleBounds();
IntRect windowBounds = oldWebFrameView->getWindowBounds();
WebCore::FrameView* oldFrameView = oldWebFrameView->view();
- m_frame->createView(bounds.size(), oldFrameView->baseBackgroundColor(), oldFrameView->isTransparent(), IntSize(), false);
+ m_frame->createView(bounds.size(), oldFrameView->baseBackgroundColor(), oldFrameView->isTransparent(),
+ oldFrameView->fixedLayoutSize(), oldFrameView->useFixedLayout());
// Create a new WebFrameView for the new FrameView
WebFrameView* newFrameView = new WebFrameView(m_frame->view(), webViewCore);
newFrameView->setLocation(bounds.x(), bounds.y());
newFrameView->setSize(bounds.width(), bounds.height());
+ newFrameView->setVisibleSize(visBounds.width(), visBounds.height());
newFrameView->setWindowBounds(windowBounds.x(), windowBounds.y(), windowBounds.width(), windowBounds.height());
// newFrameView attaches itself to FrameView which Retains the reference, so
// call Release for newFrameView
@@ -1215,6 +1224,21 @@ WTF::PassRefPtr<Widget> FrameLoaderClientAndroid::createJavaAppletWidget(const I
return 0;
}
+void FrameLoaderClientAndroid::didTransferChildFrameToNewDocument()
+{
+ ASSERT(m_frame);
+ // m_webFrame points to the WebFrame for the page that our frame previously
+ // belonged to. If the frame now belongs to a new page, we need to update
+ // m_webFrame to point to the WebFrame for the new page.
+ Page* newPage = m_frame->page();
+ if (newPage != m_webFrame->page()) {
+ ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(newPage->chrome()->client());
+ Release(m_webFrame);
+ m_webFrame = chromeClient->webFrame();
+ Retain(m_webFrame);
+ }
+}
+
// This function is used by the <OBJECT> element to determine the type of
// the contents and work out if it can render it.
ObjectContentType FrameLoaderClientAndroid::objectContentType(const KURL& url,
@@ -1281,4 +1305,8 @@ void FrameLoaderClientAndroid::didAddIconForPageUrl(const String& pageUrl) {
}
}
+void FrameLoaderClientAndroid::dispatchDidChangeIcons() {
+ notImplemented();
+}
+
}
diff --git a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h
index 3b754b8..ddbe196 100644
--- a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h
+++ b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h
@@ -176,11 +176,9 @@ namespace android {
virtual bool canCachePage() const;
virtual void download(ResourceHandle*, const ResourceRequest&, const ResourceRequest&, const ResourceResponse&);
- virtual WTF::PassRefPtr<Frame> createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement,
- const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight);
- virtual WTF::PassRefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&,
- const WTF::Vector<String>&, const WTF::Vector<String>&,
- const String&, bool loadManually);
+ virtual WTF::PassRefPtr<Frame> createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight);
+ virtual void didTransferChildFrameToNewDocument();
+ virtual WTF::PassRefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const WTF::Vector<String>&, const WTF::Vector<String>&, const String&, bool loadManually);
virtual void redirectDataToPlugin(Widget* pluginWidget);
virtual WTF::PassRefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL& baseURL, const WTF::Vector<String>& paramNames, const WTF::Vector<String>& paramValues);
@@ -210,6 +208,9 @@ namespace android {
CacheBuilder& getCacheBuilder() { return m_cacheBuilder; }
void enableOnDemandPlugins() { m_onDemandPluginsEnabled = true; }
+
+ void dispatchDidChangeIcons();
+ void dispatchWillSendSubmitEvent(HTMLFormElement*) { }
private:
CacheBuilder m_cacheBuilder;
Frame* m_frame;
diff --git a/WebKit/android/WebCoreSupport/InspectorClientAndroid.h b/WebKit/android/WebCoreSupport/InspectorClientAndroid.h
index 6feb2d7..e3d2e69 100644
--- a/WebKit/android/WebCoreSupport/InspectorClientAndroid.h
+++ b/WebKit/android/WebCoreSupport/InspectorClientAndroid.h
@@ -36,27 +36,15 @@ public:
virtual void inspectorDestroyed() { delete this; }
- virtual Page* createPage() { return NULL; }
-
- virtual String localizedStringsURL() { return String(); }
-
- virtual void showWindow() {}
- virtual void closeWindow() {}
-
- virtual void attachWindow() {}
- virtual void detachWindow() {}
-
- virtual void setAttachedWindowHeight(unsigned height) {}
+ virtual void openInspectorFrontend(WebCore::InspectorController*) {}
virtual void highlight(Node*) {}
virtual void hideHighlight() {}
- virtual void inspectedURLChanged(const String& newURL) {}
-
virtual void populateSetting(const String& key, String* value) {}
virtual void storeSetting(const String& key, const String& value) {}
- virtual String hiddenPanels() { return String(); }
- virtual void inspectorWindowObjectCleared() {}
+
+ virtual bool sendMessageToFrontend(const WebCore::String&) { return false; }
};
}
diff --git a/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp b/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp
index bfb5305..6224707 100644
--- a/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp
@@ -30,7 +30,6 @@
#include "GraphicsContext.h"
#include "SkiaUtils.h"
-#include "TimeRanges.h"
#include "WebCoreJni.h"
#include "WebViewCore.h"
@@ -44,16 +43,22 @@ using namespace android;
namespace WebCore {
static const char* g_ProxyJavaClass = "android/webkit/HTML5VideoViewProxy";
+static const char* g_ProxyJavaClassAudio = "android/webkit/HTML5Audio";
struct MediaPlayerPrivate::JavaGlue
{
jobject m_javaProxy;
- jmethodID m_getInstance;
jmethodID m_play;
jmethodID m_teardown;
- jmethodID m_loadPoster;
jmethodID m_seek;
jmethodID m_pause;
+ // Audio
+ jmethodID m_newInstance;
+ jmethodID m_setDataSource;
+ jmethodID m_getMaxTimeSeekable;
+ // Video
+ jmethodID m_getInstance;
+ jmethodID m_loadPoster;
};
MediaPlayerPrivate::~MediaPlayerPrivate()
@@ -65,7 +70,6 @@ MediaPlayerPrivate::~MediaPlayerPrivate()
env->DeleteGlobalRef(m_glue->m_javaProxy);
}
}
-
delete m_glue;
}
@@ -74,29 +78,6 @@ void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
registrar(create, getSupportedTypes, supportsType);
}
-void MediaPlayerPrivate::load(const String& url)
-{
- // Just save the URl.
- m_url = url;
-}
-
-void MediaPlayerPrivate::cancelLoad()
-{
-}
-
-void MediaPlayerPrivate::play()
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- if (!env || !m_glue->m_javaProxy || !m_url.length())
- return;
-
- m_paused = false;
- jstring jUrl = env->NewString((unsigned short *)m_url.characters(), m_url.length());
- env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play, jUrl);
- env->DeleteLocalRef(jUrl);
- checkException(env);
-}
-
void MediaPlayerPrivate::pause()
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
@@ -108,22 +89,6 @@ void MediaPlayerPrivate::pause()
checkException(env);
}
-IntSize MediaPlayerPrivate::naturalSize() const
-{
- return m_naturalSize;
-}
-
-bool MediaPlayerPrivate::hasAudio() const
-{
- // TODO
- return false;
-}
-
-bool MediaPlayerPrivate::hasVideo() const
-{
- return m_hasVideo;
-}
-
void MediaPlayerPrivate::setVisible(bool visible)
{
m_isVisible = visible;
@@ -131,99 +96,19 @@ void MediaPlayerPrivate::setVisible(bool visible)
createJavaPlayerIfNeeded();
}
-float MediaPlayerPrivate::duration() const
-{
- return m_duration;
-}
-
-float MediaPlayerPrivate::currentTime() const
-{
- return m_currentTime;
-}
-
void MediaPlayerPrivate::seek(float time)
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
- if (!env || !m_glue->m_javaProxy || !m_url.length())
+ if (!env || !m_url.length())
return;
- m_currentTime = time;
- env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_seek, static_cast<jint>(time * 1000.0f));
+ if (m_glue->m_javaProxy) {
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_seek, static_cast<jint>(time * 1000.0f));
+ m_currentTime = time;
+ }
checkException(env);
}
-bool MediaPlayerPrivate::seeking() const
-{
- return false;
-}
-
-void MediaPlayerPrivate::setEndTime(float)
-{
-}
-
-void MediaPlayerPrivate::setRate(float)
-{
-}
-
-bool MediaPlayerPrivate::paused() const
-{
- return m_paused;
-}
-
-void MediaPlayerPrivate::setVolume(float)
-{
-}
-
-MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
-{
- return m_networkState;
-}
-
-MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const
-{
- return m_readyState;
-}
-
-float MediaPlayerPrivate::maxTimeSeekable() const
-{
- return 0;
-}
-
-PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
-{
- return TimeRanges::create();
-}
-
-int MediaPlayerPrivate::dataRate() const
-{
- return 0;
-}
-
-unsigned MediaPlayerPrivate::totalBytes() const
-{
- return 0;
-}
-
-unsigned MediaPlayerPrivate::bytesLoaded() const
-{
- return 0;
-}
-
-void MediaPlayerPrivate::setSize(const IntSize&)
-{
-}
-
-void MediaPlayerPrivate::setPoster(const String& url)
-{
- m_posterUrl = url;
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- if (!env || !m_glue->m_javaProxy || !m_posterUrl.length())
- return;
- // Send the poster
- jstring jUrl = env->NewString((unsigned short *)m_posterUrl.characters(), m_posterUrl.length());
- env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
- env->DeleteLocalRef(jUrl);
-}
void MediaPlayerPrivate::prepareToPlay() {
// We are about to start playing. Since our Java VideoView cannot
@@ -237,45 +122,6 @@ void MediaPlayerPrivate::prepareToPlay() {
m_player->readyStateChanged();
}
-void MediaPlayerPrivate::paint(GraphicsContext* ctxt, const IntRect& r)
-{
- if (ctxt->paintingDisabled())
- return;
-
- if (!m_isVisible)
- return;
-
- if (!m_poster || (!m_poster->getPixels() && !m_poster->pixelRef()))
- return;
-
- SkCanvas* canvas = ctxt->platformContext()->mCanvas;
- // We paint with the following rules in mind:
- // - only downscale the poster, never upscale
- // - maintain the natural aspect ratio of the poster
- // - the poster should be centered in the target rect
- float originalRatio = static_cast<float>(m_poster->width()) / static_cast<float>(m_poster->height());
- int posterWidth = r.width() > m_poster->width() ? m_poster->width() : r.width();
- int posterHeight = posterWidth / originalRatio;
- int posterX = ((r.width() - posterWidth) / 2) + r.x();
- int posterY = ((r.height() - posterHeight) / 2) + r.y();
- IntRect targetRect(posterX, posterY, posterWidth, posterHeight);
- canvas->drawBitmapRect(*m_poster, 0, targetRect, 0);
-}
-
-MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
-{
- return new MediaPlayerPrivate(player);
-}
-
-void MediaPlayerPrivate::getSupportedTypes(HashSet<String>&)
-{
-}
-
-MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
-{
- return MediaPlayer::IsNotSupported;
-}
-
MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
: m_player(player),
m_glue(0),
@@ -290,72 +136,6 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
m_naturalSizeUnknown(true),
m_isVisible(false)
{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- if (!env)
- return;
-
- jclass clazz = env->FindClass(g_ProxyJavaClass);
- if (!clazz)
- return;
-
- m_glue = new JavaGlue;
- m_glue->m_getInstance = env->GetStaticMethodID(clazz, "getInstance", "(Landroid/webkit/WebViewCore;I)Landroid/webkit/HTML5VideoViewProxy;");
- m_glue->m_play = env->GetMethodID(clazz, "play", "(Ljava/lang/String;)V");
- m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V");
- m_glue->m_loadPoster = env->GetMethodID(clazz, "loadPoster", "(Ljava/lang/String;)V");
- m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V");
- m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V");
- m_glue->m_javaProxy = NULL;
- env->DeleteLocalRef(clazz);
- // An exception is raised if any of the above fails.
- checkException(env);
-}
-
-void MediaPlayerPrivate::createJavaPlayerIfNeeded()
-{
- // Check if we have been already created.
- if (m_glue->m_javaProxy)
- return;
-
- FrameView* frameView = m_player->frameView();
- if (!frameView)
- return;
-
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- if (!env)
- return;
-
- jclass clazz = env->FindClass(g_ProxyJavaClass);
- if (!clazz)
- return;
-
- WebViewCore* webViewCore = WebViewCore::getWebViewCore(frameView);
- ASSERT(webViewCore);
-
- // Get the HTML5VideoViewProxy instance
- jobject obj = env->CallStaticObjectMethod(clazz, m_glue->m_getInstance, webViewCore->getJavaObject().get(), this);
- m_glue->m_javaProxy = env->NewGlobalRef(obj);
- // Send the poster
- jstring jUrl = 0;
- if (m_posterUrl.length())
- jUrl = env->NewString((unsigned short *)m_posterUrl.characters(), m_posterUrl.length());
- // Sending a NULL jUrl allows the Java side to try to load the default poster.
- env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
- if (jUrl)
- env->DeleteLocalRef(jUrl);
- // Clean up.
- env->DeleteLocalRef(obj);
- env->DeleteLocalRef(clazz);
- checkException(env);
-}
-
-void MediaPlayerPrivate::onPrepared(int duration, int width, int height) {
- m_duration = duration / 1000.0f;
- m_naturalSize = IntSize(width, height);
- m_naturalSizeUnknown = false;
- m_hasVideo = true;
- m_player->durationChanged();
- m_player->sizeChanged();
}
void MediaPlayerPrivate::onEnded() {
@@ -368,25 +148,269 @@ void MediaPlayerPrivate::onEnded() {
m_readyState = MediaPlayer::HaveNothing;
}
-void MediaPlayerPrivate::onPosterFetched(SkBitmap* poster) {
- m_poster = poster;
- if (m_naturalSizeUnknown) {
- // We had to fake the size at startup, or else our paint
- // method would not be called. If we haven't yet received
- // the onPrepared event, update the intrinsic size to the size
- // of the poster. That will be overriden when onPrepare comes.
- // In case of an error, we should report the poster size, rather
- // than our initial fake value.
- m_naturalSize = IntSize(poster->width(), poster->height());
- m_player->sizeChanged();
- }
-}
-
void MediaPlayerPrivate::onTimeupdate(int position) {
m_currentTime = position / 1000.0f;
m_player->timeChanged();
}
+class MediaPlayerVideoPrivate : public MediaPlayerPrivate {
+public:
+ void load(const String& url) { m_url = url; }
+ void play() {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_url.length() || !m_glue->m_javaProxy)
+ return;
+
+ m_paused = false;
+ jstring jUrl = env->NewString((unsigned short *)m_url.characters(), m_url.length());
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play, jUrl);
+ env->DeleteLocalRef(jUrl);
+
+ checkException(env);
+ }
+ bool canLoadPoster() const { return true; }
+ void setPoster(const String& url) {
+ m_posterUrl = url;
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_glue->m_javaProxy || !m_posterUrl.length())
+ return;
+ // Send the poster
+ jstring jUrl = env->NewString((unsigned short *)m_posterUrl.characters(), m_posterUrl.length());
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
+ env->DeleteLocalRef(jUrl);
+ }
+ void paint(GraphicsContext* ctxt, const IntRect& r) {
+ if (ctxt->paintingDisabled())
+ return;
+
+ if (!m_isVisible)
+ return;
+
+ if (!m_poster || (!m_poster->getPixels() && !m_poster->pixelRef()))
+ return;
+
+ SkCanvas* canvas = ctxt->platformContext()->mCanvas;
+ // We paint with the following rules in mind:
+ // - only downscale the poster, never upscale
+ // - maintain the natural aspect ratio of the poster
+ // - the poster should be centered in the target rect
+ float originalRatio = static_cast<float>(m_poster->width()) / static_cast<float>(m_poster->height());
+ int posterWidth = r.width() > m_poster->width() ? m_poster->width() : r.width();
+ int posterHeight = posterWidth / originalRatio;
+ int posterX = ((r.width() - posterWidth) / 2) + r.x();
+ int posterY = ((r.height() - posterHeight) / 2) + r.y();
+ IntRect targetRect(posterX, posterY, posterWidth, posterHeight);
+ canvas->drawBitmapRect(*m_poster, 0, targetRect, 0);
+ }
+
+ void onPosterFetched(SkBitmap* poster) {
+ m_poster = poster;
+ if (m_naturalSizeUnknown) {
+ // We had to fake the size at startup, or else our paint
+ // method would not be called. If we haven't yet received
+ // the onPrepared event, update the intrinsic size to the size
+ // of the poster. That will be overriden when onPrepare comes.
+ // In case of an error, we should report the poster size, rather
+ // than our initial fake value.
+ m_naturalSize = IntSize(poster->width(), poster->height());
+ m_player->sizeChanged();
+ }
+ }
+
+ void onPrepared(int duration, int width, int height) {
+ m_duration = duration / 1000.0f;
+ m_naturalSize = IntSize(width, height);
+ m_naturalSizeUnknown = false;
+ m_hasVideo = true;
+ m_player->durationChanged();
+ m_player->sizeChanged();
+ }
+
+ bool hasAudio() { return false; } // do not display the audio UI
+ bool hasVideo() { return m_hasVideo; }
+
+ MediaPlayerVideoPrivate(MediaPlayer* player) : MediaPlayerPrivate(player) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env)
+ return;
+
+ jclass clazz = env->FindClass(g_ProxyJavaClass);
+
+ if (!clazz)
+ return;
+
+ m_glue = new JavaGlue;
+ m_glue->m_getInstance = env->GetStaticMethodID(clazz, "getInstance", "(Landroid/webkit/WebViewCore;I)Landroid/webkit/HTML5VideoViewProxy;");
+ m_glue->m_loadPoster = env->GetMethodID(clazz, "loadPoster", "(Ljava/lang/String;)V");
+ m_glue->m_play = env->GetMethodID(clazz, "play", "(Ljava/lang/String;)V");
+
+ m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V");
+ m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V");
+ m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V");
+ m_glue->m_javaProxy = NULL;
+ env->DeleteLocalRef(clazz);
+ // An exception is raised if any of the above fails.
+ checkException(env);
+ }
+
+ void createJavaPlayerIfNeeded() {
+ // Check if we have been already created.
+ if (m_glue->m_javaProxy)
+ return;
+
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env)
+ return;
+
+ jclass clazz = env->FindClass(g_ProxyJavaClass);
+
+ if (!clazz)
+ return;
+
+ jobject obj = NULL;
+
+ FrameView* frameView = m_player->frameView();
+ if (!frameView)
+ return;
+ WebViewCore* webViewCore = WebViewCore::getWebViewCore(frameView);
+ ASSERT(webViewCore);
+
+ // Get the HTML5VideoViewProxy instance
+ obj = env->CallStaticObjectMethod(clazz, m_glue->m_getInstance, webViewCore->getJavaObject().get(), this);
+ m_glue->m_javaProxy = env->NewGlobalRef(obj);
+ // Send the poster
+ jstring jUrl = 0;
+ if (m_posterUrl.length())
+ jUrl = env->NewString((unsigned short *)m_posterUrl.characters(), m_posterUrl.length());
+ // Sending a NULL jUrl allows the Java side to try to load the default poster.
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
+ if (jUrl)
+ env->DeleteLocalRef(jUrl);
+
+ // Clean up.
+ if (obj)
+ env->DeleteLocalRef(obj);
+ env->DeleteLocalRef(clazz);
+ checkException(env);
+ }
+};
+
+class MediaPlayerAudioPrivate : public MediaPlayerPrivate {
+public:
+ void load(const String& url) {
+ m_url = url;
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_url.length())
+ return;
+
+ createJavaPlayerIfNeeded();
+
+ if (!m_glue->m_javaProxy)
+ return;
+
+ jstring jUrl = env->NewString((unsigned short *)m_url.characters(), m_url.length());
+ // start loading the data asynchronously
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_setDataSource, jUrl);
+ env->DeleteLocalRef(jUrl);
+ checkException(env);
+ }
+
+ void play() {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_url.length())
+ return;
+
+ createJavaPlayerIfNeeded();
+
+ if (!m_glue->m_javaProxy)
+ return;
+
+ m_paused = false;
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play);
+ checkException(env);
+ }
+
+ bool hasAudio() { return true; }
+
+ float maxTimeSeekable() const {
+ if (m_glue->m_javaProxy) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (env) {
+ float maxTime = env->CallFloatMethod(m_glue->m_javaProxy,
+ m_glue->m_getMaxTimeSeekable);
+ checkException(env);
+ return maxTime;
+ }
+ }
+ return 0;
+ }
+
+ MediaPlayerAudioPrivate(MediaPlayer* player) : MediaPlayerPrivate(player) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env)
+ return;
+
+ jclass clazz = env->FindClass(g_ProxyJavaClassAudio);
+
+ if (!clazz)
+ return;
+
+ m_glue = new JavaGlue;
+ m_glue->m_newInstance = env->GetMethodID(clazz, "<init>", "(I)V");
+ m_glue->m_setDataSource = env->GetMethodID(clazz, "setDataSource", "(Ljava/lang/String;)V");
+ m_glue->m_play = env->GetMethodID(clazz, "play", "()V");
+ m_glue->m_getMaxTimeSeekable = env->GetMethodID(clazz, "getMaxTimeSeekable", "()F");
+ m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V");
+ m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V");
+ m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V");
+ m_glue->m_javaProxy = NULL;
+ env->DeleteLocalRef(clazz);
+ // An exception is raised if any of the above fails.
+ checkException(env);
+ }
+
+ void createJavaPlayerIfNeeded() {
+ // Check if we have been already created.
+ if (m_glue->m_javaProxy)
+ return;
+
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env)
+ return;
+
+ jclass clazz = env->FindClass(g_ProxyJavaClassAudio);
+
+ if (!clazz)
+ return;
+
+ jobject obj = NULL;
+
+ // Get the HTML5Audio instance
+ obj = env->NewObject(clazz, m_glue->m_newInstance, this);
+ m_glue->m_javaProxy = env->NewGlobalRef(obj);
+
+ // Clean up.
+ if (obj)
+ env->DeleteLocalRef(obj);
+ env->DeleteLocalRef(clazz);
+ checkException(env);
+ }
+
+ void onPrepared(int duration, int width, int height) {
+ m_duration = duration / 1000.0f;
+ m_player->durationChanged();
+ m_player->sizeChanged();
+ m_player->prepareToPlay();
+ }
+};
+
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ if (player->mediaElementType() == MediaPlayer::Video)
+ return new MediaPlayerVideoPrivate(player);
+ return new MediaPlayerAudioPrivate(player);
+}
+
}
namespace android {
@@ -416,6 +440,13 @@ static void OnPosterFetched(JNIEnv* env, jobject obj, jobject poster, int pointe
player->onPosterFetched(posterNative);
}
+static void OnBuffering(JNIEnv* env, jobject obj, int percent, int pointer) {
+ if (pointer) {
+ WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
+ //TODO: player->onBuffering(percent);
+ }
+}
+
static void OnTimeupdate(JNIEnv* env, jobject obj, int position, int pointer) {
if (pointer) {
WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
@@ -437,11 +468,28 @@ static JNINativeMethod g_MediaPlayerMethods[] = {
(void*) OnTimeupdate },
};
-int register_mediaplayer(JNIEnv* env)
+static JNINativeMethod g_MediaAudioPlayerMethods[] = {
+ { "nativeOnBuffering", "(II)V",
+ (void*) OnBuffering },
+ { "nativeOnEnded", "(I)V",
+ (void*) OnEnded },
+ { "nativeOnPrepared", "(IIII)V",
+ (void*) OnPrepared },
+ { "nativeOnTimeupdate", "(II)V",
+ (void*) OnTimeupdate },
+};
+
+int register_mediaplayer_video(JNIEnv* env)
{
return jniRegisterNativeMethods(env, g_ProxyJavaClass,
g_MediaPlayerMethods, NELEM(g_MediaPlayerMethods));
}
+int register_mediaplayer_audio(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, g_ProxyJavaClassAudio,
+ g_MediaAudioPlayerMethods, NELEM(g_MediaAudioPlayerMethods));
+}
+
}
#endif // VIDEO
diff --git a/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/WebKit/android/WebCoreSupport/PlatformBridge.cpp
index 05aa42b..833deb5 100644
--- a/WebKit/android/WebCoreSupport/PlatformBridge.cpp
+++ b/WebKit/android/WebCoreSupport/PlatformBridge.cpp
@@ -27,50 +27,21 @@
#include <PlatformBridge.h>
#include "CookieClient.h"
+#include "FileSystemClient.h"
+#include "FrameView.h"
#include "JavaSharedClient.h"
#include "KeyGeneratorClient.h"
#include "PluginView.h"
+#include "WebCoreFrameBridge.h"
#include "WebViewCore.h"
#include "npruntime.h"
#include <wtf/android/AndroidThreading.h>
#include <wtf/MainThread.h>
-#if USE(ACCELERATED_COMPOSITING)
-#include "LayerAndroid.h"
-#endif
-
using namespace android;
namespace WebCore {
-#if USE(ACCELERATED_COMPOSITING)
-
-void PlatformBridge::setUIRootLayer(const WebCore::FrameView* view, const LayerAndroid* layer)
-{
- android::WebViewCore* core = android::WebViewCore::getWebViewCore(view);
- core->setUIRootLayer(layer);
-}
-
-void PlatformBridge::immediateRepaint(const WebCore::FrameView* view)
-{
- android::WebViewCore* core = android::WebViewCore::getWebViewCore(view);
- core->immediateRepaint();
-}
-
-#endif // USE(ACCELERATED_COMPOSITING)
-
-int PlatformBridge::screenWidth(const WebCore::FrameView* view)
-{
- android::WebViewCore* core = android::WebViewCore::getWebViewCore(view);
- return static_cast<int>((core->screenWidthScale() * core->screenWidth()) / core->scale());
-}
-
-int PlatformBridge::screenHeight(const WebCore::FrameView* view)
-{
- android::WebViewCore* core = android::WebViewCore::getWebViewCore(view);
- return core->screenHeight();
-}
-
WTF::Vector<String> PlatformBridge::getSupportedKeyStrengthList()
{
KeyGeneratorClient* client = JavaSharedClient::GetKeyGeneratorClient();
@@ -135,11 +106,28 @@ bool PlatformBridge::isWebViewPaused(const WebCore::FrameView* frameView)
return webViewCore->isPaused();
}
+bool PlatformBridge::canScroll(const WebCore::FrameView* frameView)
+{
+ // We want to ignore requests to scroll that were not initiated by the
+ // user. An example of this is when text is inserted into a
+ // textfield/area, which results in a scroll. We ignore this because
+ // we know how to do this ourselves in the UI thread.
+ // An example of it being initiated by the user is if the user clicks
+ // an anchor element which simply scrolls the page.
+ return android::WebFrame::getWebFrame(frameView->frame())->userInitiatedClick();
+}
+
bool PlatformBridge::popupsAllowed(NPP)
{
return false;
}
+String PlatformBridge::resolveFilePathForContentUri(const String& contentUri)
+{
+ FileSystemClient* client = JavaSharedClient::GetFileSystemClient();
+ return client->resolveFilePathForContentUri(contentUri);
+}
+
} // namespace WebCore
diff --git a/WebKit/android/WebCoreSupport/V8Counters.cpp b/WebKit/android/WebCoreSupport/V8Counters.cpp
index 7f3f3ad..7472447 100644
--- a/WebKit/android/WebCoreSupport/V8Counters.cpp
+++ b/WebKit/android/WebCoreSupport/V8Counters.cpp
@@ -33,9 +33,9 @@
#include "V8Counters.h"
#include "NotImplemented.h"
-#include <CString.h>
#include <StringHash.h>
#include <utils/Log.h>
+#include <wtf/text/CString.h>
namespace WebCore {
diff --git a/WebKit/android/benchmark/Intercept.cpp b/WebKit/android/benchmark/Intercept.cpp
index fe8e7bb..e5a98f1 100644
--- a/WebKit/android/benchmark/Intercept.cpp
+++ b/WebKit/android/benchmark/Intercept.cpp
@@ -27,7 +27,6 @@
#include "config.h"
#include "Base64.h"
-#include "CString.h"
#include "HTTPParsers.h"
#include "Intercept.h"
#include "ResourceHandle.h"
@@ -38,6 +37,7 @@
#include "TextEncoding.h"
#include <utils/Log.h>
#include <wtf/HashMap.h>
+#include <wtf/text/CString.h>
PassRefPtr<WebCore::ResourceLoaderAndroid> MyResourceLoader::create(
ResourceHandle* handle, String url)
diff --git a/WebKit/android/jni/JavaBridge.cpp b/WebKit/android/jni/JavaBridge.cpp
index 0e65e1c..6aceb1c 100644
--- a/WebKit/android/jni/JavaBridge.cpp
+++ b/WebKit/android/jni/JavaBridge.cpp
@@ -31,6 +31,7 @@
#include "Cache.h"
#include "Connection.h"
#include "CookieClient.h"
+#include "FileSystemClient.h"
#include "JavaSharedClient.h"
#include "KeyGeneratorClient.h"
#include "KURL.h"
@@ -62,7 +63,7 @@ static jfieldID gJavaBridge_ObjectID;
// ----------------------------------------------------------------------------
-class JavaBridge : public TimerClient, public CookieClient, public PluginClient, public KeyGeneratorClient
+class JavaBridge : public TimerClient, public CookieClient, public PluginClient, public KeyGeneratorClient, public FileSystemClient
{
public:
JavaBridge(JNIEnv* env, jobject obj);
@@ -84,6 +85,7 @@ public:
virtual WTF::Vector<String> getSupportedKeyStrengthList();
virtual WebCore::String getSignedPublicKeyAndChallengeString(unsigned index,
const WebCore::String& challenge, const WebCore::KURL& url);
+ virtual WebCore::String resolveFilePathForContentUri(const WebCore::String& uri);
////////////////////////////////////////////
@@ -120,6 +122,7 @@ private:
jmethodID mSignalFuncPtrQueue;
jmethodID mGetKeyStrengthList;
jmethodID mGetSignedPublicKey;
+ jmethodID mResolveFilePathForContentUri;
};
static void (*sSharedTimerFiredCallback)();
@@ -139,6 +142,7 @@ JavaBridge::JavaBridge(JNIEnv* env, jobject obj)
mSignalFuncPtrQueue = env->GetMethodID(clazz, "signalServiceFuncPtrQueue", "()V");
mGetKeyStrengthList = env->GetMethodID(clazz, "getKeyStrengthList", "()[Ljava/lang/String;");
mGetSignedPublicKey = env->GetMethodID(clazz, "getSignedPublicKey", "(ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+ mResolveFilePathForContentUri = env->GetMethodID(clazz, "resolveFilePathForContentUri", "(Ljava/lang/String;)Ljava/lang/String;");
LOG_ASSERT(mSetSharedTimer, "Could not find method setSharedTimer");
LOG_ASSERT(mStopSharedTimer, "Could not find method stopSharedTimer");
@@ -154,6 +158,7 @@ JavaBridge::JavaBridge(JNIEnv* env, jobject obj)
JavaSharedClient::SetCookieClient(this);
JavaSharedClient::SetPluginClient(this);
JavaSharedClient::SetKeyGeneratorClient(this);
+ JavaSharedClient::SetFileSystemClient(this);
}
JavaBridge::~JavaBridge()
@@ -168,6 +173,7 @@ JavaBridge::~JavaBridge()
JavaSharedClient::SetCookieClient(NULL);
JavaSharedClient::SetPluginClient(NULL);
JavaSharedClient::SetKeyGeneratorClient(NULL);
+ JavaSharedClient::SetFileSystemClient(NULL);
}
void
@@ -308,6 +314,17 @@ WebCore::String JavaBridge::getSignedPublicKeyAndChallengeString(unsigned index,
return ret;
}
+WebCore::String JavaBridge::resolveFilePathForContentUri(const WebCore::String& uri) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ jstring jUri = env->NewString(uri.characters(), uri.length());
+ AutoJObject obj = getRealObject(env, mJavaObject);
+ jstring path = static_cast<jstring>(env->CallObjectMethod(obj.get(), mResolveFilePathForContentUri, jUri));
+ WebCore::String ret = to_string(env, path);
+ env->DeleteLocalRef(jUri);
+ env->DeleteLocalRef(path);
+ return ret;
+}
+
// ----------------------------------------------------------------------------
void JavaBridge::Constructor(JNIEnv* env, jobject obj)
diff --git a/WebKit/android/jni/JavaSharedClient.cpp b/WebKit/android/jni/JavaSharedClient.cpp
index ce46570..e884c99 100644
--- a/WebKit/android/jni/JavaSharedClient.cpp
+++ b/WebKit/android/jni/JavaSharedClient.cpp
@@ -24,6 +24,7 @@
*/
#include "config.h"
+#include "FileSystemClient.h"
#include "JavaSharedClient.h"
#include "TimerClient.h"
#include "SkDeque.h"
@@ -50,6 +51,11 @@ namespace android {
return gKeyGeneratorClient;
}
+ FileSystemClient* JavaSharedClient::GetFileSystemClient()
+ {
+ return gFileSystemClient;
+ }
+
void JavaSharedClient::SetTimerClient(TimerClient* client)
{
gTimerClient = client;
@@ -70,10 +76,16 @@ namespace android {
gKeyGeneratorClient = client;
}
+ void JavaSharedClient::SetFileSystemClient(FileSystemClient* client)
+ {
+ gFileSystemClient = client;
+ }
+
TimerClient* JavaSharedClient::gTimerClient = NULL;
CookieClient* JavaSharedClient::gCookieClient = NULL;
PluginClient* JavaSharedClient::gPluginClient = NULL;
KeyGeneratorClient* JavaSharedClient::gKeyGeneratorClient = NULL;
+ FileSystemClient* JavaSharedClient::gFileSystemClient = NULL;
///////////////////////////////////////////////////////////////////////////
diff --git a/WebKit/android/jni/JavaSharedClient.h b/WebKit/android/jni/JavaSharedClient.h
index d33df67..9a09280 100644
--- a/WebKit/android/jni/JavaSharedClient.h
+++ b/WebKit/android/jni/JavaSharedClient.h
@@ -32,6 +32,7 @@ namespace android {
class CookieClient;
class PluginClient;
class KeyGeneratorClient;
+ class FileSystemClient;
class JavaSharedClient
{
@@ -40,11 +41,13 @@ namespace android {
static CookieClient* GetCookieClient();
static PluginClient* GetPluginClient();
static KeyGeneratorClient* GetKeyGeneratorClient();
+ static FileSystemClient* GetFileSystemClient();
static void SetTimerClient(TimerClient* client);
static void SetCookieClient(CookieClient* client);
static void SetPluginClient(PluginClient* client);
static void SetKeyGeneratorClient(KeyGeneratorClient* client);
+ static void SetFileSystemClient(FileSystemClient* client);
// can be called from any thread, to be executed in webkit thread
static void EnqueueFunctionPtr(void (*proc)(void*), void* payload);
@@ -56,6 +59,7 @@ namespace android {
static CookieClient* gCookieClient;
static PluginClient* gPluginClient;
static KeyGeneratorClient* gKeyGeneratorClient;
+ static FileSystemClient* gFileSystemClient;
};
}
#endif
diff --git a/WebKit/android/jni/MIMETypeRegistry.cpp b/WebKit/android/jni/MIMETypeRegistry.cpp
index 32f387d..5fe9ccd 100644
--- a/WebKit/android/jni/MIMETypeRegistry.cpp
+++ b/WebKit/android/jni/MIMETypeRegistry.cpp
@@ -58,4 +58,9 @@ String MIMETypeRegistry::getMIMETypeForExtension(const String& ext)
return result;
}
+bool MIMETypeRegistry::isApplicationPluginMIMEType(const String&)
+{
+ return false;
+}
+
}
diff --git a/WebKit/android/jni/MockGeolocation.cpp b/WebKit/android/jni/MockGeolocation.cpp
index df580c3..1c236c3 100755
--- a/WebKit/android/jni/MockGeolocation.cpp
+++ b/WebKit/android/jni/MockGeolocation.cpp
@@ -53,7 +53,7 @@ static void setPosition(JNIEnv* env, jobject, double latitude, double longitude,
false, 0.0, // altitudeAccuracy,
false, 0.0, // heading
false, 0.0); // speed
- RefPtr<Geoposition> position = Geoposition::create(coordinates.release(), WTF::currentTime());
+ RefPtr<Geoposition> position = Geoposition::create(coordinates.release(), WTF::currentTimeMS());
GeolocationServiceMock::setPosition(position.release());
}
diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp
index 250ffc9..bfd4b62 100644
--- a/WebKit/android/jni/WebCoreFrameBridge.cpp
+++ b/WebKit/android/jni/WebCoreFrameBridge.cpp
@@ -32,7 +32,6 @@
#include "AtomicString.h"
#include "BackForwardList.h"
#include "Cache.h"
-#include "CString.h"
#include "Chrome.h"
#include "ChromeClientAndroid.h"
#include "ContextMenuClientAndroid.h"
@@ -74,6 +73,7 @@
#include "SecurityOrigin.h"
#include "SelectionController.h"
#include "Settings.h"
+#include "StringBuilder.h"
#include "SubstituteData.h"
#include "WebCoreJni.h"
#include "WebCoreResourceLoader.h"
@@ -93,6 +93,7 @@
#include <utils/AssetManager.h>
#include <wtf/CurrentTime.h>
#include <wtf/Platform.h>
+#include <wtf/text/CString.h>
#if USE(JSC)
#include "GCController.h"
@@ -111,11 +112,16 @@
#include "TimeCounter.h"
#endif
+#if ENABLE(ARCHIVE)
+#include "WebArchiveAndroid.h"
+#endif
+
using namespace JSC::Bindings;
static String* gUploadFileLabel;
static String* gResetLabel;
static String* gSubmitLabel;
+static String* gNoFileChosenLabel;
String* WebCore::PlatformBridge::globalLocalizedName(
WebCore::PlatformBridge::rawResId resId)
@@ -127,6 +133,9 @@ String* WebCore::PlatformBridge::globalLocalizedName(
return gResetLabel;
case WebCore::PlatformBridge::SubmitLabel:
return gSubmitLabel;
+ case WebCore::PlatformBridge::FileUploadNoFileChosenLabel:
+ return gNoFileChosenLabel;
+
default:
return 0;
}
@@ -148,6 +157,9 @@ void initGlobalLocalizedName(WebCore::PlatformBridge::rawResId resId,
case WebCore::PlatformBridge::SubmitLabel:
pointer = &gSubmitLabel;
break;
+ case WebCore::PlatformBridge::FileUploadNoFileChosenLabel:
+ pointer = &gNoFileChosenLabel;
+ break;
default:
return;
}
@@ -310,9 +322,9 @@ static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHead
jstring val = env->NewString((unsigned short *)i->second.characters(), i->second.length());
if (key && val) {
env->CallObjectMethod(hashMap, put, key, val);
- env->DeleteLocalRef(key);
- env->DeleteLocalRef(val);
}
+ env->DeleteLocalRef(key);
+ env->DeleteLocalRef(val);
}
env->DeleteLocalRef(mapClass);
@@ -320,19 +332,6 @@ static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHead
return hashMap;
}
-// In WebViewCore.java, we artificially append the filename to the URI so that
-// webkit treats the actual display name of the file as the filename, rather
-// than the last segment of the URI (which will simply be a number). When we
-// pass the URI up to BrowserFrame, we no longer need the appended name (in fact
-// it causes problems), so remove it here.
-// FIXME: If we rewrite pathGetFileName (the current version is in
-// FileSystemPOSIX), we can get the filename that way rather than appending it.
-static jstring uriFromUriFileName(JNIEnv* env, const WebCore::String& name)
-{
- const WebCore::String fileName = name.left(name.reverseFind('/'));
- return env->NewString(fileName.characters(), fileName.length());
-}
-
// This class stores the URI and the size of each file for upload. The URI is
// stored so we do not have to create it again. The size is stored so we can
// compare the actual size of the file with the stated size. If the actual size
@@ -341,7 +340,7 @@ static jstring uriFromUriFileName(JNIEnv* env, const WebCore::String& name)
class FileInfo {
public:
FileInfo(JNIEnv* env, const WebCore::String& name) {
- m_uri = uriFromUriFileName(env, name);
+ m_uri = env->NewString(name.characters(), name.length());
checkException(env);
m_size = 0;
m_env = env;
@@ -722,6 +721,7 @@ WebFrame::didReceiveTouchIconURL(const WebCore::String& url, bool precomposed)
env->CallVoidMethod(mJavaFrame->frame(env).get(),
mJavaFrame->mDidReceiveTouchIconUrl, jUrlStr, precomposed);
+ env->DeleteLocalRef(jUrlStr);
checkException(env);
}
@@ -736,6 +736,7 @@ WebFrame::updateVisitedHistory(const WebCore::KURL& url, bool reload)
jstring jUrlStr = env->NewString((unsigned short*)urlStr.characters(), urlStr.length());
env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mUpdateVisitedHistory, jUrlStr, reload);
+ env->DeleteLocalRef(jUrlStr);
checkException(env);
}
@@ -765,6 +766,7 @@ WebFrame::canHandleRequest(const WebCore::ResourceRequest& request)
// if browser app handles the url, we will return false to bail out WebCore loading
jboolean ret = env->CallBooleanMethod(mJavaFrame->frame(env).get(), mJavaFrame->mHandleUrl, jUrlStr);
checkException(env);
+ env->DeleteLocalRef(jUrlStr);
return (ret == 0);
}
@@ -882,7 +884,8 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss
dragC,
inspectorC,
0, // PluginHalterClient
- 0); // GeolocationControllerClient
+ 0, // GeolocationControllerClient
+ 0); // DeviceOrientationClient
// css files without explicit MIMETYPE is treated as generic text files in
// the Java side. So we can't enforce CSS MIMETYPE.
page->settings()->setEnforceCSSMIMETypeInStrictMode(false);
@@ -940,7 +943,7 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss
WebCore::RenderSkinAndroid::Init(am, directory);
}
for (int i = WebCore::PlatformBridge::FileUploadLabel;
- i <= WebCore::PlatformBridge::SubmitLabel; i++)
+ i <= WebCore::PlatformBridge::FileUploadNoFileChosenLabel; i++)
initGlobalLocalizedName(
static_cast<WebCore::PlatformBridge::rawResId>(i), webFrame);
}
@@ -1096,6 +1099,91 @@ static void StopLoading(JNIEnv *env, jobject obj)
pFrame->loader()->stopForUserCancel();
}
+#if ENABLE(ARCHIVE)
+static String saveArchiveAutoname(String basename, String name, String extension) {
+ if (name.isNull() || name.isEmpty()) {
+ name = String("index");
+ }
+
+ String testname = basename;
+ testname.append(name);
+ testname.append(extension);
+
+ errno = 0;
+ struct stat permissions;
+ if (stat(testname.utf8().data(), &permissions) < 0) {
+ if (errno == ENOENT)
+ return testname;
+ return String();
+ }
+
+ const int maxAttempts = 100;
+ for (int i = 1; i < maxAttempts; i++) {
+ String testname = basename;
+ testname.append(name);
+ testname.append("-");
+ testname.append(String::number(i));
+ testname.append(extension);
+
+ errno = 0;
+ if (stat(testname.utf8().data(), &permissions) < 0) {
+ if (errno == ENOENT)
+ return testname;
+ return String();
+ }
+ }
+
+ return String();
+}
+#endif
+
+static jobject SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboolean autoname)
+{
+#if ENABLE(ARCHIVE)
+ WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "nativeSaveWebArchive must take a valid frame pointer!");
+
+ const char* basenameNative = getCharactersFromJStringInEnv(env, basename);
+ String basenameString = String::fromUTF8(basenameNative);
+ String filename;
+
+ if (autoname) {
+ String name = pFrame->loader()->documentLoader()->originalURL().lastPathComponent();
+ String extension = String(".webarchivexml");
+ filename = saveArchiveAutoname(basenameString, name, extension);
+ } else {
+ filename = basenameString;
+ }
+
+ if (filename.isNull() || filename.isEmpty()) {
+ LOGD("saveWebArchive: Failed to select a filename to save.");
+ releaseCharactersForJStringInEnv(env, basename, basenameNative);
+ return JNI_FALSE;
+ }
+
+ const int noCompression = 0;
+ xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.utf8().data(), noCompression);
+ if (writer == NULL) {
+ LOGD("saveWebArchive: Failed to initialize xml writer.");
+ releaseCharactersForJStringInEnv(env, basename, basenameNative);
+ return JNI_FALSE;
+ }
+
+ RefPtr<WebArchiveAndroid> archive = WebCore::WebArchiveAndroid::create(pFrame);
+
+ bool result = archive->saveWebArchive(writer);
+
+ releaseCharactersForJStringInEnv(env, basename, basenameNative);
+ xmlFreeTextWriter(writer);
+
+ if (result) {
+ return env->NewStringUTF(filename.utf8().data());
+ }
+
+ return NULL;
+#endif
+}
+
static jstring ExternalRepresentation(JNIEnv *env, jobject obj)
{
#ifdef ANDROID_INSTRUMENT
@@ -1112,6 +1200,28 @@ static jstring ExternalRepresentation(JNIEnv *env, jobject obj)
return env->NewString(renderDump.characters(), len);
}
+static WebCore::StringBuilder FrameAsText(WebCore::Frame *pFrame, jboolean dumpChildFrames) {
+ WebCore::StringBuilder renderDump;
+ if (!pFrame)
+ return renderDump;
+ WebCore::Element *documentElement = pFrame->document()->documentElement();
+ if (!documentElement)
+ return renderDump;
+ if (pFrame->tree()->parent()) {
+ renderDump.append("\n--------\nFrame: '");
+ renderDump.append(pFrame->tree()->name());
+ renderDump.append("'\n--------\n");
+ }
+ renderDump.append(((WebCore::HTMLElement*)documentElement)->innerText());
+ renderDump.append("\n");
+ if (dumpChildFrames) {
+ for (unsigned i = 0; i < pFrame->tree()->childCount(); ++i) {
+ renderDump.append(FrameAsText(pFrame->tree()->child(i), dumpChildFrames).toString());
+ }
+ }
+ return renderDump;
+}
+
static jstring DocumentAsText(JNIEnv *env, jobject obj)
{
#ifdef ANDROID_INSTRUMENT
@@ -1120,11 +1230,26 @@ static jstring DocumentAsText(JNIEnv *env, jobject obj)
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
LOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!");
- WebCore::Element *documentElement = pFrame->document()->documentElement();
- if (!documentElement)
+ WebCore::String renderDump = FrameAsText(pFrame, false /* dumpChildFrames */).toString();
+ unsigned len = renderDump.length();
+ if (!len)
return NULL;
- WebCore::String renderDump = ((WebCore::HTMLElement*)documentElement)->innerText();
- renderDump.append("\n");
+ return env->NewString((unsigned short*)renderDump.characters(), len);
+}
+
+static jstring ChildFramesAsText(JNIEnv *env, jobject obj)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
+#endif
+ WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!");
+
+ WebCore::StringBuilder renderDumpBuilder;
+ for (unsigned i = 0; i < pFrame->tree()->childCount(); ++i) {
+ renderDumpBuilder.append(FrameAsText(pFrame->tree()->child(i), true /* dumpChildFrames */).toString());
+ }
+ WebCore::String renderDump = renderDumpBuilder.toString();
unsigned len = renderDump.length();
if (!len)
return NULL;
@@ -1413,8 +1538,8 @@ static jboolean HasPasswordField(JNIEnv *env, jobject obj)
// class, but just normal Element class.
while (node && !found && !node->namespaceURI().isNull() &&
!node->namespaceURI().isEmpty()) {
- WTF::Vector<WebCore::HTMLFormControlElement*>& elements =
- ((WebCore::HTMLFormElement*)node)->formElements;
+ const WTF::Vector<WebCore::HTMLFormControlElement*>& elements =
+ ((WebCore::HTMLFormElement*)node)->associatedElements();
size_t size = elements.size();
for (size_t i = 0; i< size && !found; i++) {
WebCore::HTMLFormControlElement* e = elements[i];
@@ -1444,8 +1569,8 @@ static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj)
WebCore::Node* node = form->firstItem();
while (node && !found && !node->namespaceURI().isNull() &&
!node->namespaceURI().isEmpty()) {
- WTF::Vector<WebCore::HTMLFormControlElement*>& elements =
- ((WebCore::HTMLFormElement*)node)->formElements;
+ const WTF::Vector<WebCore::HTMLFormControlElement*>& elements =
+ ((WebCore::HTMLFormElement*)node)->associatedElements();
size_t size = elements.size();
for (size_t i = 0; i< size && !found; i++) {
WebCore::HTMLFormControlElement* e = elements[i];
@@ -1455,7 +1580,7 @@ static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj)
continue;
if (input->inputType() == WebCore::HTMLInputElement::PASSWORD)
password = input->value();
- else if (input->inputType() == WebCore::HTMLInputElement::TEXT)
+ else if (input->inputType() == WebCore::HTMLInputElement::TEXT || input->inputType() == WebCore::HTMLInputElement::EMAIL)
username = input->value();
if (!username.isNull() && !password.isNull())
found = true;
@@ -1490,8 +1615,8 @@ static void SetUsernamePassword(JNIEnv *env, jobject obj,
WebCore::Node* node = form->firstItem();
while (node && !found && !node->namespaceURI().isNull() &&
!node->namespaceURI().isEmpty()) {
- WTF::Vector<WebCore::HTMLFormControlElement*>& elements =
- ((WebCore::HTMLFormElement*)node)->formElements;
+ const WTF::Vector<WebCore::HTMLFormControlElement*>& elements =
+ ((WebCore::HTMLFormElement*)node)->associatedElements();
size_t size = elements.size();
for (size_t i = 0; i< size && !found; i++) {
WebCore::HTMLFormControlElement* e = elements[i];
@@ -1501,7 +1626,7 @@ static void SetUsernamePassword(JNIEnv *env, jobject obj,
continue;
if (input->inputType() == WebCore::HTMLInputElement::PASSWORD)
passwordEle = input;
- else if (input->inputType() == WebCore::HTMLInputElement::TEXT)
+ else if (input->inputType() == WebCore::HTMLInputElement::TEXT || input->inputType() == WebCore::HTMLInputElement::EMAIL)
usernameEle = input;
if (usernameEle != NULL && passwordEle != NULL)
found = true;
@@ -1543,7 +1668,7 @@ static jobject GetFormTextData(JNIEnv *env, jobject obj)
node = collection->nextItem()) {
form = static_cast<WebCore::HTMLFormElement*>(node);
if (form->autoComplete()) {
- WTF::Vector<WebCore::HTMLFormControlElement*> elements = form->formElements;
+ 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];
@@ -1604,10 +1729,14 @@ static JNINativeMethod gBrowserFrameNativeMethods[] = {
(void*) PostUrl },
{ "nativeLoadData", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
(void*) LoadData },
+ { "nativeSaveWebArchive", "(Ljava/lang/String;Z)Ljava/lang/String;",
+ (void*) SaveWebArchive },
{ "externalRepresentation", "()Ljava/lang/String;",
(void*) ExternalRepresentation },
{ "documentAsText", "()Ljava/lang/String;",
(void*) DocumentAsText },
+ { "childFramesAsText", "()Ljava/lang/String;",
+ (void*) ChildFramesAsText },
{ "reload", "(Z)V",
(void*) Reload },
{ "nativeGoBackOrForward", "(I)V",
diff --git a/WebKit/android/jni/WebCoreJniOnLoad.cpp b/WebKit/android/jni/WebCoreJniOnLoad.cpp
index b5bf9dd..1a3c676 100644
--- a/WebKit/android/jni/WebCoreJniOnLoad.cpp
+++ b/WebKit/android/jni/WebCoreJniOnLoad.cpp
@@ -82,7 +82,8 @@ extern int register_webstorage(JNIEnv*);
extern int register_geolocation_permissions(JNIEnv*);
extern int register_mock_geolocation(JNIEnv*);
#if ENABLE(VIDEO)
-extern int register_mediaplayer(JNIEnv*);
+extern int register_mediaplayer_audio(JNIEnv*);
+extern int register_mediaplayer_video(JNIEnv*);
#endif
}
@@ -107,7 +108,8 @@ static RegistrationMethod gWebCoreRegMethods[] = {
{ "GeolocationPermissions", android::register_geolocation_permissions },
{ "MockGeolocation", android::register_mock_geolocation },
#if ENABLE(VIDEO)
- { "HTML5VideoViewProxy", android::register_mediaplayer },
+ { "HTML5Audio", android::register_mediaplayer_audio },
+ { "HTML5VideoViewProxy", android::register_mediaplayer_video },
#endif
};
@@ -192,7 +194,8 @@ EXPORT void benchmark(const char* url, int reloadCount, int width, int height) {
new DragClientAndroid,
new InspectorClientAndroid,
0, // PluginHalterClient
- 0); // GeolocationControllerClient
+ 0, // GeolocationControllerClient
+ 0); // DeviceOrientationClient
editor->setPage(page);
// Create MyWebFrame that intercepts network requests
diff --git a/WebKit/android/jni/WebCoreResourceLoader.cpp b/WebKit/android/jni/WebCoreResourceLoader.cpp
index 297ecb0..32e8cd8 100644
--- a/WebKit/android/jni/WebCoreResourceLoader.cpp
+++ b/WebKit/android/jni/WebCoreResourceLoader.cpp
@@ -28,7 +28,6 @@
#include "config.h"
#include "WebCoreResourceLoader.h"
-#include "CString.h"
#include "ResourceError.h"
#include "ResourceHandle.h"
#include "ResourceHandleClient.h"
@@ -46,6 +45,7 @@
#include <stdlib.h>
#include <utils/misc.h>
#include <wtf/Platform.h>
+#include <wtf/text/CString.h>
namespace android {
diff --git a/WebKit/android/jni/WebCoreViewBridge.h b/WebKit/android/jni/WebCoreViewBridge.h
index 61990af..59e1c9a 100644
--- a/WebKit/android/jni/WebCoreViewBridge.h
+++ b/WebKit/android/jni/WebCoreViewBridge.h
@@ -38,20 +38,22 @@ namespace WebCore
class WebCoreViewBridge : public WebCoreRefObject {
public:
- WebCoreViewBridge() :
- mBounds(0,0,0,0),
- m_windowBounds(0,0,0,0)
- {}
- virtual ~WebCoreViewBridge() {}
+ WebCoreViewBridge() { }
+ virtual ~WebCoreViewBridge() { }
virtual void draw(WebCore::GraphicsContext* ctx,
const WebCore::IntRect& rect) = 0;
const WebCore::IntRect& getBounds() const
{
- return mBounds;
+ return m_bounds;
}
-
+
+ const WebCore::IntRect& getVisibleBounds() const
+ {
+ return m_visibleBounds;
+ }
+
const WebCore::IntRect& getWindowBounds() const
{
return m_windowBounds;
@@ -59,14 +61,22 @@ public:
void setSize(int w, int h)
{
- mBounds.setWidth(w);
- mBounds.setHeight(h);
+ m_bounds.setWidth(w);
+ m_bounds.setHeight(h);
+ }
+
+ void setVisibleSize(int w, int h)
+ {
+ m_visibleBounds.setWidth(w);
+ m_visibleBounds.setHeight(h);
}
void setLocation(int x, int y)
{
- mBounds.setX(x);
- mBounds.setY(y);
+ m_bounds.setX(x);
+ m_bounds.setY(y);
+ m_visibleBounds.setX(x);
+ m_visibleBounds.setY(y);
}
void setWindowBounds(int x, int y, int h, int v)
@@ -74,17 +84,23 @@ public:
m_windowBounds = WebCore::IntRect(x, y, h, v);
}
- int width() const { return mBounds.width(); }
- int height() const { return mBounds.height(); }
- int locX() const { return mBounds.x(); }
- int locY() const { return mBounds.y(); }
+ int width() const { return m_bounds.width(); }
+ int height() const { return m_bounds.height(); }
+ int locX() const { return m_bounds.x(); }
+ int locY() const { return m_bounds.y(); }
+
+ int visibleWidth() const { return m_visibleBounds.width(); }
+ int visibleHeight() const { return m_visibleBounds.height(); }
+ int visibleX() const { return m_visibleBounds.x(); }
+ int visibleY() const { return m_visibleBounds.y(); }
virtual bool forFrameView() const { return false; }
virtual bool forPluginView() const { return false; }
private:
- WebCore::IntRect mBounds;
+ WebCore::IntRect m_bounds;
WebCore::IntRect m_windowBounds;
+ WebCore::IntRect m_visibleBounds;
};
#endif // WEBCORE_VIEW_BRIDGE_H
diff --git a/WebKit/android/jni/WebHistory.cpp b/WebKit/android/jni/WebHistory.cpp
index d518ba8..37a4d1d 100644
--- a/WebKit/android/jni/WebHistory.cpp
+++ b/WebKit/android/jni/WebHistory.cpp
@@ -29,7 +29,6 @@
#include "WebHistory.h"
#include "BackForwardList.h"
-#include "CString.h"
#include "DocumentLoader.h"
#include "Frame.h"
#include "FrameLoader.h"
@@ -49,6 +48,7 @@
#include <utils/misc.h>
#include <wtf/OwnPtr.h>
#include <wtf/Platform.h>
+#include <wtf/text/CString.h>
namespace android {
@@ -419,9 +419,9 @@ static void write_item(WTF::Vector<char>& v, WebCore::HistoryItem* item)
const int scale = bridge->scale();
LOGV("Writing scale %d", scale);
v.append((char*)&scale, sizeof(int));
- const int screenWidthScale = bridge->screenWidthScale();
- LOGV("Writing screen width scale %d", screenWidthScale);
- v.append((char*)&screenWidthScale, sizeof(int));
+ const int textWrapScale = bridge->textWrapScale();
+ LOGV("Writing text wrap scale %d", textWrapScale);
+ v.append((char*)&textWrapScale, sizeof(int));
// Document state
const WTF::Vector<WebCore::String>& docState = item->documentState();
@@ -603,8 +603,8 @@ static bool read_item_recursive(WebCore::HistoryItem* newItem,
bridge->setScale(l);
data += sizeofUnsigned;
memcpy(&l, data, sizeofUnsigned);
- LOGV("Screen width scale %d", l);
- bridge->setScreenWidthScale(l);
+ LOGV("Text wrap scale %d", l);
+ bridge->setTextWrapScale(l);
data += sizeofUnsigned;
if (end - data < sizeofUnsigned)
diff --git a/WebKit/android/jni/WebHistory.h b/WebKit/android/jni/WebHistory.h
index 12bf00a..2d86aa4 100644
--- a/WebKit/android/jni/WebHistory.h
+++ b/WebKit/android/jni/WebHistory.h
@@ -44,9 +44,9 @@ public:
static void UpdateHistoryIndex(const AutoJObject&, int);
};
-// there are two scale factors saved with each history item. mScale reflects the
-// viewport scale factor, default to 100 means 100%. mScreenWidthScale records
-// the scale factor for the screen width used to wrap the text paragraph.
+// there are two scale factors saved with each history item. m_scale reflects the
+// viewport scale factor, default to 100 means 100%. m_textWrapScale records
+// the scale factor for wrapping the text paragraph.
class WebHistoryItem : public WebCore::AndroidWebHistoryBridge {
public:
WebHistoryItem(WebHistoryItem* parent)
diff --git a/WebKit/android/jni/WebIconDatabase.cpp b/WebKit/android/jni/WebIconDatabase.cpp
index 840d161..6a20f6f 100644
--- a/WebKit/android/jni/WebIconDatabase.cpp
+++ b/WebKit/android/jni/WebIconDatabase.cpp
@@ -38,6 +38,7 @@
#include <JNIHelp.h>
#include <JNIUtility.h>
+#include <SharedBuffer.h>
#include <SkBitmap.h>
#include <SkImageDecoder.h>
#include <SkTemplates.h>
diff --git a/WebKit/android/jni/WebSettings.cpp b/WebKit/android/jni/WebSettings.cpp
index 70ecded..d9a7cf0 100644
--- a/WebKit/android/jni/WebSettings.cpp
+++ b/WebKit/android/jni/WebSettings.cpp
@@ -29,7 +29,9 @@
#include <wtf/Platform.h>
#include "ApplicationCacheStorage.h"
+#include "BitmapAllocatorAndroid.h"
#include "DatabaseTracker.h"
+#include "Database.h"
#include "DocLoader.h"
#include "Document.h"
#include "Frame.h"
@@ -107,11 +109,13 @@ struct FieldIds {
#endif
mGeolocationEnabled = env->GetFieldID(clazz, "mGeolocationEnabled", "Z");
mGeolocationDatabasePath = env->GetFieldID(clazz, "mGeolocationDatabasePath", "Ljava/lang/String;");
+ mXSSAuditorEnabled = env->GetFieldID(clazz, "mXSSAuditorEnabled", "Z");
mJavaScriptCanOpenWindowsAutomatically = env->GetFieldID(clazz,
"mJavaScriptCanOpenWindowsAutomatically", "Z");
mUseWideViewport = env->GetFieldID(clazz, "mUseWideViewport", "Z");
mSupportMultipleWindows = env->GetFieldID(clazz, "mSupportMultipleWindows", "Z");
mShrinksStandaloneImagesToFit = env->GetFieldID(clazz, "mShrinksStandaloneImagesToFit", "Z");
+ mMaximumDecodedImageSize = env->GetFieldID(clazz, "mMaximumDecodedImageSize", "J");
mUseDoubleTree = env->GetFieldID(clazz, "mUseDoubleTree", "Z");
mPageCacheCapacity = env->GetFieldID(clazz, "mPageCacheCapacity", "I");
@@ -148,6 +152,7 @@ struct FieldIds {
LOG_ASSERT(mUseWideViewport, "Could not find field mUseWideViewport");
LOG_ASSERT(mSupportMultipleWindows, "Could not find field mSupportMultipleWindows");
LOG_ASSERT(mShrinksStandaloneImagesToFit, "Could not find field mShrinksStandaloneImagesToFit");
+ LOG_ASSERT(mMaximumDecodedImageSize, "Could not find field mMaximumDecodedImageSize");
LOG_ASSERT(mUseDoubleTree, "Could not find field mUseDoubleTree");
LOG_ASSERT(mPageCacheCapacity, "Could not find field mPageCacheCapacity");
@@ -193,6 +198,7 @@ struct FieldIds {
jfieldID mUseWideViewport;
jfieldID mSupportMultipleWindows;
jfieldID mShrinksStandaloneImagesToFit;
+ jfieldID mMaximumDecodedImageSize;
jfieldID mUseDoubleTree;
jfieldID mPageCacheCapacity;
// Ordinal() method and value field for enums
@@ -207,6 +213,7 @@ struct FieldIds {
#endif
jfieldID mGeolocationEnabled;
jfieldID mGeolocationDatabasePath;
+ jfieldID mXSSAuditorEnabled;
#if ENABLE(DATABASE) || ENABLE(DOM_STORAGE)
jfieldID mDatabasePath;
jfieldID mDatabasePathHasBeenSet;
@@ -260,8 +267,8 @@ public:
#endif
jobject textSize = env->GetObjectField(obj, gFieldIds->mTextSize);
float zoomFactor = env->GetIntField(textSize, gFieldIds->mTextSizeValue) / 100.0f;
- if (pFrame->zoomFactor() != zoomFactor)
- pFrame->setZoomFactor(zoomFactor, /*isTextOnly*/true);
+ if (pFrame->view()->zoomFactor() != zoomFactor)
+ pFrame->view()->setZoomFactor(zoomFactor, WebCore::ZoomTextOnly);
jstring str = (jstring)env->GetObjectField(obj, gFieldIds->mStandardFontFamily);
s->setStandardFontFamily(to_string(env, str));
@@ -352,9 +359,13 @@ public:
#endif
flag = env->GetBooleanField(obj, gFieldIds->mShrinksStandaloneImagesToFit);
s->setShrinksStandaloneImagesToFit(flag);
+ jlong maxImage = env->GetIntField(obj, gFieldIds->mMaximumDecodedImageSize);
+ if (maxImage == 0)
+ maxImage = computeMaxBitmapSizeForCache();
+ s->setMaximumDecodedImageSize(maxImage);
#if ENABLE(DATABASE)
flag = env->GetBooleanField(obj, gFieldIds->mDatabaseEnabled);
- s->setDatabasesEnabled(flag);
+ WebCore::Database::setIsAvailable(flag);
flag = env->GetBooleanField(obj, gFieldIds->mDatabasePathHasBeenSet);
if (flag) {
@@ -384,6 +395,9 @@ public:
WebCore::GeolocationPositionCache::setDatabasePath(to_string(env,str));
}
+ flag = env->GetBooleanField(obj, gFieldIds->mXSSAuditorEnabled);
+ s->setXSSAuditorEnabled(flag);
+
size = env->GetIntField(obj, gFieldIds->mPageCacheCapacity);
if (size > 0) {
s->setUsesPageCache(true);
diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp
index 1562775..d3e32d3 100644
--- a/WebKit/android/jni/WebViewCore.cpp
+++ b/WebKit/android/jni/WebViewCore.cpp
@@ -29,6 +29,7 @@
#include "WebViewCore.h"
#include "AtomicString.h"
+#include "BaseLayerAndroid.h"
#include "CachedNode.h"
#include "CachedRoot.h"
#include "Chrome.h"
@@ -37,6 +38,7 @@
#include "DatabaseTracker.h"
#include "Document.h"
#include "DOMWindow.h"
+#include "DOMSelection.h"
#include "Element.h"
#include "Editor.h"
#include "EditorClientAndroid.h"
@@ -65,9 +67,9 @@
#include "HTMLSelectElement.h"
#include "HTMLTextAreaElement.h"
#include "HistoryItem.h"
+#include "HitTestRequest.h"
#include "HitTestResult.h"
#include "InlineTextBox.h"
-#include "KeyboardCodes.h"
#include "Navigator.h"
#include "Node.h"
#include "NodeList.h"
@@ -79,7 +81,9 @@
#include "PluginView.h"
#include "Position.h"
#include "ProgressTracker.h"
+#include "Range.h"
#include "RenderBox.h"
+#include "RenderInline.h"
#include "RenderLayer.h"
#include "RenderPart.h"
#include "RenderText.h"
@@ -101,6 +105,7 @@
#include "TypingCommand.h"
#include "WebCoreFrameBridge.h"
#include "WebFrameView.h"
+#include "WindowsKeyboardCodes.h"
#include "android_graphics.h"
#include <JNIHelp.h>
@@ -109,9 +114,9 @@
#include <wtf/CurrentTime.h>
#if USE(V8)
-#include "CString.h"
#include "ScriptController.h"
#include "V8Counters.h"
+#include <wtf/text/CString.h>
#endif
#if DEBUG_NAV_UI
@@ -125,7 +130,7 @@
#ifdef ANDROID_DOM_LOGGING
#include "AndroidLog.h"
#include "RenderTreeAsText.h"
-#include "CString.h"
+#include <wtf/text/CString.h>
FILE* gDomTreeFile = 0;
FILE* gRenderTreeFile = 0;
@@ -226,13 +231,10 @@ struct WebViewCore::JavaGlue {
jmethodID m_updateViewport;
jmethodID m_sendNotifyProgressFinished;
jmethodID m_sendViewInvalidate;
- jmethodID m_sendImmediateRepaint;
- jmethodID m_setRootLayer;
jmethodID m_updateTextfield;
jmethodID m_updateTextSelection;
jmethodID m_clearTextEntry;
jmethodID m_restoreScale;
- jmethodID m_restoreScreenWidthScale;
jmethodID m_needTouchEvents;
jmethodID m_requestKeyboard;
jmethodID m_requestKeyboardWithSelection;
@@ -253,6 +255,7 @@ struct WebViewCore::JavaGlue {
jmethodID m_showRect;
jmethodID m_centerFitRect;
jmethodID m_setScrollbarModes;
+ jmethodID m_setInstallableWebApp;
AutoJObject object(JNIEnv* env) {
return getRealObject(env, m_obj);
}
@@ -272,7 +275,6 @@ static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const
Mutex WebViewCore::gFrameCacheMutex;
Mutex WebViewCore::gButtonMutex;
Mutex WebViewCore::gCursorBoundsMutex;
-Mutex WebViewCore::m_contentMutex;
WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe)
: m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired)
@@ -289,8 +291,8 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
m_maxYScroll = 240/4;
m_textGeneration = 0;
m_screenWidth = 320;
+ m_textWrapWidth = 320;
m_scale = 1;
- m_screenWidthScale = 1;
#if ENABLE(TOUCH_EVENTS)
m_forwardingTouchEvents = false;
#endif
@@ -306,7 +308,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V");
m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V");
m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V");
- m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "()Ljava/lang/String;");
+ m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;)Ljava/lang/String;");
m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V");
m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V");
m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z");
@@ -317,13 +319,10 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V");
m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
- m_javaGlue->m_sendImmediateRepaint = GetJMethod(env, clazz, "sendImmediateRepaint", "()V");
- m_javaGlue->m_setRootLayer = GetJMethod(env, clazz, "setRootLayer", "(I)V");
m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V");
m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
- m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(I)V");
- m_javaGlue->m_restoreScreenWidthScale = GetJMethod(env, clazz, "restoreScreenWidthScale", "(I)V");
+ m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(II)V");
m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V");
m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V");
m_javaGlue->m_requestKeyboardWithSelection = GetJMethod(env, clazz, "requestKeyboardWithSelection", "(IIII)V");
@@ -344,6 +343,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V");
m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V");
m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V");
+ m_javaGlue->m_setInstallableWebApp = GetJMethod(env, clazz, "setInstallableWebApp", "()V");
env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this);
@@ -485,7 +485,8 @@ void WebViewCore::recordPicture(SkPicture* picture)
WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons);
WebCore::GraphicsContext gc(&pgc);
- view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0, INT_MAX, INT_MAX));
+ view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0,
+ view->contentsWidth(), view->contentsHeight()));
gButtonMutex.lock();
updateButtonList(&buttons);
@@ -589,6 +590,9 @@ void WebViewCore::recordPictureSet(PictureSet* content)
height = view->contentsHeight();
}
+ if (cacheBuilder().pictureSetDisabled())
+ content->clear();
+
content->checkDimensions(width, height, &m_addInval);
// The inval region may replace existing pictures. The existing pictures
@@ -741,50 +745,11 @@ void WebViewCore::updateCursorBounds(const CachedRoot* root,
void WebViewCore::clearContent()
{
DBG_SET_LOG("");
- m_contentMutex.lock();
m_content.clear();
- m_contentMutex.unlock();
m_addInval.setEmpty();
m_rebuildInval.setEmpty();
}
-void WebViewCore::copyContentToPicture(SkPicture* picture)
-{
- DBG_SET_LOG("start");
- m_contentMutex.lock();
- PictureSet copyContent = PictureSet(m_content);
- m_contentMutex.unlock();
-
- int w = copyContent.width();
- int h = copyContent.height();
- copyContent.draw(picture->beginRecording(w, h, PICT_RECORD_FLAGS));
- picture->endRecording();
- DBG_SET_LOG("end");
-}
-
-bool WebViewCore::drawContent(SkCanvas* canvas, SkColor color)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewUIDrawTimeCounter);
-#endif
- DBG_SET_LOG("start");
- m_contentMutex.lock();
- PictureSet copyContent = PictureSet(m_content);
- m_contentMutex.unlock();
- int sc = canvas->save(SkCanvas::kClip_SaveFlag);
- SkRect clip;
- clip.set(0, 0, copyContent.width(), copyContent.height());
- canvas->clipRect(clip, SkRegion::kDifference_Op);
- canvas->drawColor(color);
- canvas->restoreToCount(sc);
- bool tookTooLong = copyContent.draw(canvas);
- m_contentMutex.lock();
- m_content.setDrawTimes(copyContent);
- m_contentMutex.unlock();
- DBG_SET_LOG("end");
- return tookTooLong;
-}
-
bool WebViewCore::focusBoundsChanged()
{
bool result = m_focusBoundsChanged;
@@ -792,18 +757,6 @@ bool WebViewCore::focusBoundsChanged()
return result;
}
-bool WebViewCore::pictureReady()
-{
- bool done;
- m_contentMutex.lock();
- PictureSet copyContent = PictureSet(m_content);
- done = m_progressDone;
- m_contentMutex.unlock();
- DBG_NAV_LOGD("done=%s empty=%s", done ? "true" : "false",
- copyContent.isEmpty() ? "true" : "false");
- return done || !copyContent.isEmpty();
-}
-
SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
{
WebCore::FrameView* view = m_mainFrame->view();
@@ -851,48 +804,52 @@ void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
pictureSet->validate(__FUNCTION__);
}
-bool WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
+BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
{
DBG_SET_LOG("start");
float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
- m_contentMutex.lock();
- PictureSet contentCopy(m_content);
m_progressDone = progress <= 0.0f || progress >= 1.0f;
- m_contentMutex.unlock();
- recordPictureSet(&contentCopy);
- if (!m_progressDone && contentCopy.isEmpty()) {
+ recordPictureSet(&m_content);
+ if (!m_progressDone && m_content.isEmpty()) {
DBG_SET_LOGD("empty (progress=%g)", progress);
- return false;
+ return 0;
}
region->set(m_addInval);
m_addInval.setEmpty();
region->op(m_rebuildInval, SkRegion::kUnion_Op);
m_rebuildInval.setEmpty();
- m_contentMutex.lock();
- contentCopy.setDrawTimes(m_content);
- m_content.set(contentCopy);
point->fX = m_content.width();
point->fY = m_content.height();
- m_contentMutex.unlock();
DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft,
region->getBounds().fTop, region->getBounds().fRight,
region->getBounds().fBottom);
DBG_SET_LOG("end");
- return true;
+
+ BaseLayerAndroid* base = new BaseLayerAndroid();
+ base->setContent(m_content);
+
+#if USE(ACCELERATED_COMPOSITING)
+ // We update the layers
+ ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
+ GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
+ if (root) {
+ root->notifyClientAnimationStarted();
+ LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer());
+ base->addChild(copyLayer);
+ copyLayer->unref();
+ }
+#endif
+
+ return base;
}
-void WebViewCore::splitContent()
+void WebViewCore::splitContent(PictureSet* content)
{
bool layoutSuceeded = layoutIfNeededRecursive(m_mainFrame);
LOG_ASSERT(layoutSuceeded, "Can never be called recursively");
- PictureSet tempPictureSet;
- m_contentMutex.lock();
- m_content.split(&tempPictureSet);
- m_contentMutex.unlock();
- rebuildPictureSet(&tempPictureSet);
- m_contentMutex.lock();
- m_content.set(tempPictureSet);
- m_contentMutex.unlock();
+ content->split(&m_content);
+ rebuildPictureSet(&m_content);
+ content->set(m_content);
}
void WebViewCore::scrollTo(int x, int y, bool animate)
@@ -936,28 +893,6 @@ void WebViewCore::scrollBy(int dx, int dy, bool animate)
checkException(env);
}
-#if USE(ACCELERATED_COMPOSITING)
-
-void WebViewCore::immediateRepaint()
-{
- LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue->object(env).get(),
- m_javaGlue->m_sendImmediateRepaint);
- checkException(env);
-}
-
-void WebViewCore::setUIRootLayer(const LayerAndroid* layer)
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue->object(env).get(),
- m_javaGlue->m_setRootLayer,
- reinterpret_cast<jint>(layer));
- checkException(env);
-}
-
-#endif // USE(ACCELERATED_COMPOSITING)
-
void WebViewCore::contentDraw()
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
@@ -1034,24 +969,13 @@ void WebViewCore::updateViewport()
checkException(env);
}
-void WebViewCore::restoreScale(int scale)
+void WebViewCore::restoreScale(int scale, int textWrapScale)
{
DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale);
- checkException(env);
-}
-
-void WebViewCore::restoreScreenWidthScale(int scale)
-{
- DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
- LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
-
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue->object(env).get(),
- m_javaGlue->m_restoreScreenWidthScale, scale);
+ env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale, textWrapScale);
checkException(env);
}
@@ -1162,42 +1086,45 @@ void WebViewCore::setGlobalBounds(int x, int y, int h, int v)
}
void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
- int screenWidth, float scale, int realScreenWidth, int screenHeight,
+ int textWrapWidth, float scale, int screenWidth, int screenHeight,
int anchorX, int anchorY, bool ignoreHeight)
{
WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
int ow = window->width();
int oh = window->height();
window->setSize(width, height);
+ window->setVisibleSize(screenWidth, screenHeight);
+ if (width != screenWidth) {
+ m_mainFrame->view()->setUseFixedLayout(true);
+ m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height));
+ } else {
+ m_mainFrame->view()->setUseFixedLayout(false);
+ }
int osw = m_screenWidth;
- int orsw = m_screenWidth * m_screenWidthScale / m_scale;
int osh = m_screenHeight;
+ int otw = m_textWrapWidth;
DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)",
ow, oh, osw, m_scale, width, height, screenWidth, scale);
m_screenWidth = screenWidth;
m_screenHeight = screenHeight;
- if (scale >= 0) { // negative means ignore
+ m_textWrapWidth = textWrapWidth;
+ if (scale >= 0) // negative means keep the current scale
m_scale = scale;
- if (screenWidth != realScreenWidth)
- m_screenWidthScale = realScreenWidth * scale / screenWidth;
- else
- m_screenWidthScale = m_scale;
- }
m_maxXScroll = screenWidth >> 2;
- m_maxYScroll = (screenWidth * height / width) >> 2;
- if (ow != width || (!ignoreHeight && oh != height) || osw != screenWidth) {
+ m_maxYScroll = m_maxXScroll * height / width;
+ if (ow != width || (!ignoreHeight && oh != height) || otw != textWrapWidth) {
WebCore::RenderObject *r = m_mainFrame->contentRenderer();
DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r,
- realScreenWidth, screenHeight);
+ screenWidth, screenHeight);
if (r) {
WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY);
DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY);
- WebCore::Node* node = 0;
+ RefPtr<WebCore::Node> node;
WebCore::IntRect bounds;
WebCore::IntPoint offset;
- // If the screen width changed, it is probably zoom change or
+ // If the text wrap changed, it is probably zoom change or
// orientation change. Try to keep the anchor at the same place.
- if (osw && screenWidth && osw != screenWidth) {
+ if (otw && textWrapWidth && otw != textWrapWidth) {
WebCore::HitTestResult hitTestResult =
m_mainFrame->eventHandler()-> hitTestResultAtPoint(
anchorPoint, false);
@@ -1227,19 +1154,19 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d,"
"h=%d)", newBounds.x(), newBounds.y(),
newBounds.width(), newBounds.height());
- if ((orsw && osh && bounds.width() && bounds.height())
+ if ((osw && osh && bounds.width() && bounds.height())
&& (bounds != newBounds)) {
WebCore::FrameView* view = m_mainFrame->view();
// force left align if width is not changed while height changed.
// the anchorPoint is probably at some white space in the node
// which is affected by text wrap around the screen width.
- const bool leftAlign = (osw != m_screenWidth)
+ const bool leftAlign = (otw != textWrapWidth)
&& (bounds.width() == newBounds.width())
&& (bounds.height() != newBounds.height());
const float xPercentInDoc =
leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width();
const float xPercentInView =
- leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / orsw;
+ leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / osw;
const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height();
const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh;
showRect(newBounds.x(), newBounds.y(), newBounds.width(),
@@ -1272,7 +1199,7 @@ void WebViewCore::dumpDomTree(bool useFile)
void WebViewCore::dumpRenderTree(bool useFile)
{
#ifdef ANDROID_DOM_LOGGING
- WebCore::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8();
+ WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8();
const char* data = renderDump.data();
if (useFile) {
gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w");
@@ -1331,7 +1258,7 @@ WebCore::String WebViewCore::requestLabel(WebCore::Frame* frame,
for (unsigned i = 0; i < length; i++) {
WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>(
list->item(i));
- if (label->correspondingControl() == node) {
+ if (label->control() == node) {
Node* node = label;
String result;
while ((node = node->traverseNextNode(label))) {
@@ -1437,6 +1364,252 @@ void WebViewCore::updateFrameCacheIfLoading()
updateFrameCache();
}
+struct TouchNodeData {
+ Node* mNode;
+ IntRect mBounds;
+};
+
+// get the bounding box of the Node
+static IntRect getAbsoluteBoundingBox(Node* node) {
+ IntRect rect;
+ RenderObject* render = node->renderer();
+ if (render->isRenderInline())
+ rect = toRenderInline(render)->linesVisibleOverflowBoundingBox();
+ else if (render->isBox())
+ rect = toRenderBox(render)->visualOverflowRect();
+ else if (render->isText())
+ rect = toRenderText(render)->linesBoundingBox();
+ else
+ LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName());
+ FloatPoint absPos = render->localToAbsolute();
+ rect.move(absPos.x(), absPos.y());
+ return rect;
+}
+
+// get the highlight rectangles for the touch point (x, y) with the slop
+Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop)
+{
+ Vector<IntRect> rects;
+ m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
+#ifdef ANDROID_HITTEST_WITHSIZE
+ HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
+ false, false, DontHitTestScrollbars, IntSize(slop, slop));
+ if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
+ LOGE("Should not happen: no in document Node found");
+ return rects;
+ }
+ const Vector<RefPtr<Node> >& list = hitTestResult.rawNodeList();
+ if (list.isEmpty()) {
+ LOGE("Should not happen: no raw node found");
+ return rects;
+ }
+ Frame* frame = hitTestResult.innerNode()->document()->frame();
+ Vector<TouchNodeData> nodeDataList;
+ Vector<RefPtr<Node> >::const_iterator last = list.end();
+ for (Vector<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) {
+ // TODO: it seems reasonable to not search across the frame. Isn't it?
+ // if the node is not in the same frame as the innerNode, skip it
+ if (it->get()->document()->frame() != frame)
+ continue;
+ // traverse up the tree to find the first node that needs highlight
+ bool found = false;
+ Node* eventNode = it->get();
+ while (eventNode) {
+ RenderObject* render = eventNode->renderer();
+ if (render->isBody() || render->isRenderView())
+ break;
+ if (eventNode->supportsFocus()
+ || eventNode->hasEventListeners(eventNames().clickEvent)
+ || eventNode->hasEventListeners(eventNames().mousedownEvent)
+ || eventNode->hasEventListeners(eventNames().mouseupEvent)) {
+ found = true;
+ break;
+ }
+ // the nodes in the rawNodeList() are ordered based on z-index during hit testing.
+ // so do not search for the eventNode across explicit z-index border.
+ // TODO: this is a hard one to call. z-index is quite complicated as its value only
+ // matters when you compare two RenderLayer in the same hierarchy level. e.g. in
+ // the following example, "b" is on the top as its z level is the highest. even "c"
+ // has 100 as z-index, it is still below "d" as its parent has the same z-index as
+ // "d" and logically before "d". Of course "a" is the lowest in the z level.
+ //
+ // z-index:auto "a"
+ // z-index:2 "b"
+ // z-index:1
+ // z-index:100 "c"
+ // z-index:1 "d"
+ //
+ // If the fat point touches everyone, the order in the list should be "b", "d", "c"
+ // and "a". When we search for the event node for "b", we really don't want "a" as
+ // in the z-order it is behind everything else.
+ if (!render->style()->hasAutoZIndex())
+ break;
+ eventNode = eventNode->parentNode();
+ }
+ // didn't find any eventNode, skip it
+ if (!found)
+ continue;
+ // first quick check whether it is a duplicated node before computing bounding box
+ Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
+ for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
+ // found the same node, skip it
+ if (eventNode == n->mNode) {
+ found = false;
+ break;
+ }
+ }
+ if (!found)
+ continue;
+ // next check whether the node is fully covered by or fully covering another node.
+ found = false;
+ IntRect rect = getAbsoluteBoundingBox(eventNode);
+ if (rect.isEmpty()) {
+ // if the node's bounds is empty and it is not a ContainerNode, skip it.
+ if (!eventNode->isContainerNode())
+ continue;
+ // if the node's children are all positioned objects, its bounds can be empty.
+ // Walk through the children to find the bounding box.
+ Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild();
+ while (child) {
+ IntRect childrect;
+ if (child->renderer())
+ childrect = getAbsoluteBoundingBox(child);
+ if (!childrect.isEmpty()) {
+ rect.unite(childrect);
+ child = child->traverseNextSibling(eventNode);
+ } else
+ child = child->traverseNextNode(eventNode);
+ }
+ }
+ for (int i = nodeDataList.size() - 1; i >= 0; i--) {
+ TouchNodeData n = nodeDataList.at(i);
+ // the new node is enclosing an existing node, skip it
+ if (rect.contains(n.mBounds)) {
+ found = true;
+ break;
+ }
+ // the new node is fully inside an existing node, remove the existing node
+ if (n.mBounds.contains(rect))
+ nodeDataList.remove(i);
+ }
+ if (!found) {
+ TouchNodeData newNode;
+ newNode.mNode = eventNode;
+ newNode.mBounds = rect;
+ nodeDataList.append(newNode);
+ }
+ }
+ if (!nodeDataList.size())
+ return rects;
+ // finally select the node with the largest overlap with the fat point
+ TouchNodeData final;
+ final.mNode = 0;
+ IntPoint docPos = frame->view()->windowToContents(m_mousePos);
+ IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1);
+ int area = 0;
+ Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
+ for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
+ IntRect rect = n->mBounds;
+ rect.intersect(testRect);
+ int a = rect.width() * rect.height();
+ if (a > area) {
+ final = *n;
+ area = a;
+ }
+ }
+ // now get the node's highlight rectangles in the page coordinate system
+ if (final.mNode) {
+ IntPoint frameAdjust;
+ if (frame != m_mainFrame) {
+ frameAdjust = frame->view()->contentsToWindow(IntPoint());
+ frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY);
+ }
+ if (final.mNode->isLink()) {
+ // most of the links are inline instead of box style. So the bounding box is not
+ // a good representation for the highlights. Get the list of rectangles instead.
+ RenderObject* render = final.mNode->renderer();
+ IntPoint offset = roundedIntPoint(render->localToAbsolute());
+ render->absoluteRects(rects, offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y());
+ bool inside = false;
+ int distance = INT_MAX;
+ int newx = x, newy = y;
+ int i = rects.size();
+ while (i--) {
+ if (rects[i].isEmpty()) {
+ rects.remove(i);
+ continue;
+ }
+ // check whether the point (x, y) is inside one of the rectangles.
+ if (inside)
+ continue;
+ if (rects[i].contains(x, y)) {
+ inside = true;
+ continue;
+ }
+ if (x >= rects[i].x() && x < rects[i].right()) {
+ if (y < rects[i].y()) {
+ if (rects[i].y() - y < distance) {
+ newx = x;
+ newy = rects[i].y();
+ distance = rects[i].y() - y;
+ }
+ } else if (y >= rects[i].bottom()) {
+ if (y - rects[i].bottom() + 1 < distance) {
+ newx = x;
+ newy = rects[i].bottom() - 1;
+ distance = y - rects[i].bottom() + 1;
+ }
+ }
+ } else if (y >= rects[i].y() && y < rects[i].bottom()) {
+ if (x < rects[i].x()) {
+ if (rects[i].x() - x < distance) {
+ newx = rects[i].x();
+ newy = y;
+ distance = rects[i].x() - x;
+ }
+ } else if (x >= rects[i].right()) {
+ if (x - rects[i].right() + 1 < distance) {
+ newx = rects[i].right() - 1;
+ newy = y;
+ distance = x - rects[i].right() + 1;
+ }
+ }
+ }
+ }
+ if (!rects.isEmpty()) {
+ if (!inside) {
+ // if neither x nor y has overlap, just pick the top/left of the first rectangle
+ if (newx == x && newy == y) {
+ newx = rects[0].x();
+ newy = rects[0].y();
+ }
+ m_mousePos.setX(newx - m_scrollOffsetX);
+ m_mousePos.setY(newy - m_scrollOffsetY);
+ DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
+ x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
+ m_scrollOffsetX, m_scrollOffsetY);
+ }
+ return rects;
+ }
+ }
+ IntRect rect = final.mBounds;
+ rect.move(frameAdjust.x(), frameAdjust.y());
+ rects.append(rect);
+ // adjust m_mousePos if it is not inside the returned highlight rectangle
+ testRect.move(frameAdjust.x(), frameAdjust.y());
+ testRect.intersect(rect);
+ if (!testRect.contains(x, y)) {
+ m_mousePos = testRect.center();
+ m_mousePos.move(-m_scrollOffsetX, -m_scrollOffsetY);
+ DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
+ x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
+ m_scrollOffsetX, m_scrollOffsetY);
+ }
+ }
+#endif
+ return rects;
+}
+
///////////////////////////////////////////////////////////////////////////////
void WebViewCore::addPlugin(PluginWidgetAndroid* w)
@@ -1675,6 +1848,51 @@ void WebViewCore::setSelection(int start, int end)
setFocusControllerActive(focusedFrame, true);
}
+String WebViewCore::modifySelection(const String& alter, const String& direction, const String& granularity)
+{
+ DOMSelection* selection = m_mainFrame->domWindow()->getSelection();
+
+ if (selection->rangeCount() == 0) {
+ Document* document = m_mainFrame->document();
+ HTMLElement* body = document->body();
+ ExceptionCode ec;
+
+ PassRefPtr<Range> rangeRef = document->createRange();
+ rangeRef->setStart(PassRefPtr<Node>(body), 0, ec);
+ if (ec) {
+ LOGE("Error setting range start. Error code: %d", ec);
+ return String();
+ }
+
+ rangeRef->setEnd(PassRefPtr<Node>(body), 0, ec);
+ if (ec) {
+ LOGE("Error setting range end. Error code: %d", ec);
+ return String();
+ }
+
+ selection->addRange(rangeRef.get());
+ }
+
+ if (equalIgnoringCase(direction, "forward")) {
+ selection->collapseToEnd();
+ } else if (equalIgnoringCase(direction, "backward")) {
+ selection->collapseToStart();
+ } else {
+ LOGE("Invalid direction: %s", direction.utf8().data());
+ return String();
+ }
+
+ // NOTE: The selection of WebKit misbehaves and I need to add some
+ // voodoo here to force it behave well. Rachel did something similar
+ // in JS and I want to make sure it is optimal before adding it here.
+
+ selection->modify(alter, direction, granularity);
+ String selection_string = selection->toString();
+ LOGD("Selection string: %s", selection_string.utf8().data());
+
+ return selection_string;
+}
+
void WebViewCore::deleteSelection(int start, int end, int textGeneration)
{
setSelection(start, end);
@@ -1918,15 +2136,24 @@ void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) {
if (!chooser)
return;
JNIEnv* env = JSC::Bindings::getJNIEnv();
+
+ WebCore::String acceptType = chooser->acceptTypes();
+ jstring jAcceptType = env->NewString(const_cast<unsigned short*>(acceptType.characters()), acceptType.length());
jstring jName = (jstring) env->CallObjectMethod(
- m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser);
+ m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser, jAcceptType);
checkException(env);
- const UChar* string = (const UChar*) env->GetStringChars(jName, NULL);
+ env->DeleteLocalRef(jAcceptType);
+
+ const UChar* string = static_cast<const UChar*>(env->GetStringChars(jName, NULL));
+
if (!string)
return;
+
WebCore::String webcoreString = to_string(env, jName);
env->ReleaseStringChars(jName, string);
- chooser->chooseFile(webcoreString);
+
+ if (webcoreString.length())
+ chooser->chooseFile(webcoreString);
}
void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
@@ -1985,12 +2212,25 @@ void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, s
bool WebViewCore::key(const PlatformKeyboardEvent& event)
{
- WebCore::EventHandler* eventHandler = m_mainFrame->eventHandler();
+ WebCore::EventHandler* eventHandler;
WebCore::Node* focusNode = currentFocus();
- if (focusNode)
- eventHandler = focusNode->document()->frame()->eventHandler();
DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p",
event.keyIdentifier().utf8().data(), event.unichar(), focusNode);
+ if (focusNode) {
+ WebCore::Frame* frame = focusNode->document()->frame();
+ eventHandler = frame->eventHandler();
+ if (focusNode->isContentEditable()) {
+ // keyEvent will return true even if the contentEditable did not
+ // change its selection. In the case that it does not, we want to
+ // return false so that the key will be sent back to our navigation
+ // system.
+ VisibleSelection old = frame->selection()->selection();
+ eventHandler->keyEvent(event);
+ return frame->selection()->selection() != old;
+ }
+ } else {
+ eventHandler = m_mainFrame->eventHandler();
+ }
return eventHandler->keyEvent(event);
}
@@ -2075,14 +2315,6 @@ bool WebViewCore::handleTouchEvent(int action, int x, int y, int metaState)
// Track previous touch and if stationary set the state.
WebCore::IntPoint pt(x - m_scrollOffsetX, y - m_scrollOffsetY);
-// handleTouchEvent() in EventHandler.cpp doesn't handle TouchStationary, which
-// causes preventDefault be false when it returns. As our Java side may continue
-// process the events if WebKit doesn't, it can cause unexpected result.
-// if (type == WebCore::TouchMove && pt == m_lastTouchPoint)
-// touchState = WebCore::PlatformTouchPoint::TouchStationary;
-
- m_lastTouchPoint = pt;
-
WebCore::PlatformTouchEvent te(pt, type, touchState, metaState);
preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
#endif
@@ -2097,6 +2329,16 @@ bool WebViewCore::handleTouchEvent(int action, int x, int y, int metaState)
void WebViewCore::touchUp(int touchGeneration,
WebCore::Frame* frame, WebCore::Node* node, int x, int y)
{
+ if (touchGeneration == 0) {
+ // m_mousePos should be set in getTouchHighlightRects()
+ WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false);
+ node = hitTestResult.innerNode();
+ if (node)
+ frame = node->document()->frame();
+ else
+ frame = 0;
+ DBG_NAV_LOGD("touch up on (%d, %d), scrollOffset is (%d, %d), node:%p, frame:%p", m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, m_scrollOffsetX, m_scrollOffsetY, node, frame);
+ } else {
if (m_touchGeneration > touchGeneration) {
DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d"
" x=%d y=%d", m_touchGeneration, touchGeneration, x, y);
@@ -2106,6 +2348,7 @@ void WebViewCore::touchUp(int touchGeneration,
// m_mousePos to determine where the click happens.
moveMouse(frame, x, y);
m_lastGeneration = touchGeneration;
+ }
if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
frame->loader()->resetMultipleFormSubmissionProtection();
}
@@ -2203,6 +2446,9 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node
} else {
requestKeyboard(false);
}
+ } else if (focusNode->isContentEditable()) {
+ setFocusControllerActive(framePtr, true);
+ requestKeyboard(true);
}
}
return handled;
@@ -2542,6 +2788,13 @@ void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode
checkException(env);
}
+void WebViewCore::notifyWebAppCanBeInstalled()
+{
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setInstallableWebApp);
+ checkException(env);
+}
+
//----------------------------------------------------------------------
// Native JNI methods
//----------------------------------------------------------------------
@@ -2568,7 +2821,7 @@ static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj)
}
static void SetSize(JNIEnv *env, jobject obj, jint width, jint height,
- jint screenWidth, jfloat scale, jint realScreenWidth, jint screenHeight,
+ jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight,
jint anchorX, jint anchorY, jboolean ignoreHeight)
{
#ifdef ANDROID_INSTRUMENT
@@ -2577,8 +2830,8 @@ static void SetSize(JNIEnv *env, jobject obj, jint width, jint height,
WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
- viewImpl->setSizeScreenWidthAndScale(width, height, screenWidth, scale,
- realScreenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
+ viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
+ screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
}
static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint x, jint y)
@@ -2646,6 +2899,22 @@ static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end)
viewImpl->setSelection(start, end);
}
+static jstring ModifySelection(JNIEnv *env, jobject obj, jstring alter, jstring direction, jstring granularity)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
+#endif
+ String alterString = to_string(env, alter);
+ String directionString = to_string(env, direction);
+ String granularityString = to_string(env, granularity);
+
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ String selection_string = viewImpl->modifySelection(alterString,
+ directionString,
+ granularityString);
+
+ return WebCoreStringToJString(env, selection_string);
+}
static void ReplaceTextfieldText(JNIEnv *env, jobject obj,
jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
@@ -2710,7 +2979,7 @@ void WebViewCore::addVisitedLink(const UChar* string, int length)
m_groupForVisitedLinks->addVisitedLink(string, length);
}
-static bool RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
+static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
{
#ifdef ANDROID_INSTRUMENT
TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
@@ -2718,18 +2987,18 @@ static bool RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
SkIPoint nativePt;
- bool result = viewImpl->recordContent(nativeRegion, &nativePt);
+ BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt);
GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
- return result;
+ return reinterpret_cast<jint>(result);
}
-static void SplitContent(JNIEnv *env, jobject obj)
+static void SplitContent(JNIEnv *env, jobject obj, jint content)
{
#ifdef ANDROID_INSTRUMENT
TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
#endif
WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- viewImpl->splitContent();
+ viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
}
static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice)
@@ -2981,7 +3250,7 @@ static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags)
{
#if USE(V8)
WebCore::String flagsString = to_string(env, flags);
- WebCore::CString utf8String = flagsString.utf8();
+ WTF::CString utf8String = flagsString.utf8();
WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
#endif
}
@@ -3018,45 +3287,11 @@ static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) {
WebCore::SecurityOrigin::registerURLSchemeAsLocal(to_string(env, scheme));
}
-static void ClearContent(JNIEnv *env, jobject obj)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- viewImpl->clearContent();
-}
-
-static void CopyContentToPicture(JNIEnv *env, jobject obj, jobject pict)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- if (!viewImpl)
- return;
- SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
- viewImpl->copyContentToPicture(picture);
-}
-
-static bool DrawContent(JNIEnv *env, jobject obj, jobject canv, jint color)
-{
- // Note: this is called from UI thread, don't count it for WebViewCoreTimeCounter
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
- return viewImpl->drawContent(canvas, color);
-}
-
static bool FocusBoundsChanged(JNIEnv* env, jobject obj)
{
return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged();
}
-static bool PictureReady(JNIEnv* env, jobject obj)
-{
- return GET_NATIVE_VIEW(env, obj)->pictureReady();
-}
-
static void Pause(JNIEnv* env, jobject obj)
{
// This is called for the foreground tab when the browser is put to the
@@ -3151,26 +3386,54 @@ static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node,
reinterpret_cast<Node*>(node), nativeRect);
}
+static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop)
+{
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ if (!viewImpl)
+ return NULL;
+ Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop);
+ if (rects.isEmpty())
+ return NULL;
+
+ jclass arrayClass = env->FindClass("java/util/ArrayList");
+ LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList");
+ jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V");
+ LOG_ASSERT(init, "Could not find constructor for ArrayList");
+ jobject array = env->NewObject(arrayClass, init, rects.size());
+ LOG_ASSERT(vector, "Could not create a new ArrayList");
+ jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z");
+ LOG_ASSERT(add, "Could not find add method on ArrayList");
+ jclass rectClass = env->FindClass("android/graphics/Rect");
+ LOG_ASSERT(rectClass, "Could not find android/graphics/Rect");
+ jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V");
+ LOG_ASSERT(rectinit, "Could not find init method on Rect");
+
+ for (size_t i = 0; i < rects.size(); i++) {
+ jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(),
+ rects[i].y(), rects[i].right(), rects[i].bottom());
+ if (rect) {
+ env->CallBooleanMethod(array, add, rect);
+ env->DeleteLocalRef(rect);
+ }
+ }
+
+ env->DeleteLocalRef(rectClass);
+ env->DeleteLocalRef(arrayClass);
+ return array;
+}
+
// ----------------------------------------------------------------------------
/*
* JNI registration.
*/
static JNINativeMethod gJavaWebViewCoreMethods[] = {
- { "nativeClearContent", "()V",
- (void*) ClearContent },
- { "nativeCopyContentToPicture", "(Landroid/graphics/Picture;)V",
- (void*) CopyContentToPicture },
- { "nativeDrawContent", "(Landroid/graphics/Canvas;I)Z",
- (void*) DrawContent } ,
{ "nativeFocusBoundsChanged", "()Z",
(void*) FocusBoundsChanged } ,
{ "nativeKey", "(IIIZZZZ)Z",
(void*) Key },
{ "nativeClick", "(II)V",
(void*) Click },
- { "nativePictureReady", "()Z",
- (void*) PictureReady } ,
{ "nativeSendListBoxChoices", "([ZI)V",
(void*) SendListBoxChoices },
{ "nativeSendListBoxChoice", "(I)V",
@@ -3183,6 +3446,8 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
(void*) SetGlobalBounds },
{ "nativeSetSelection", "(II)V",
(void*) SetSelection } ,
+ { "nativeModifySelection", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+ (void*) ModifySelection },
{ "nativeDeleteSelection", "(III)V",
(void*) DeleteSelection } ,
{ "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V",
@@ -3215,11 +3480,11 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
(void*) UpdateFrameCache },
{ "nativeGetContentMinPrefWidth", "()I",
(void*) GetContentMinPrefWidth },
- { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)Z",
+ { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I",
(void*) RecordContent },
{ "setViewportSettingsFromNative", "()V",
(void*) SetViewportSettingsFromNative },
- { "nativeSplitContent", "()V",
+ { "nativeSplitContent", "(I)V",
(void*) SplitContent },
{ "nativeSetBackgroundColor", "(I)V",
(void*) SetBackgroundColor },
@@ -3251,6 +3516,8 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
(void*) FullScreenPluginHidden },
{ "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z",
(void*) ValidNodeAndBounds },
+ { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;",
+ (void*) GetTouchHighlightRects },
};
int register_webviewcore(JNIEnv* env)
diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h
index 056dba1..99f02e9 100644
--- a/WebKit/android/jni/WebViewCore.h
+++ b/WebKit/android/jni/WebViewCore.h
@@ -61,10 +61,13 @@ namespace WebCore {
#if USE(ACCELERATED_COMPOSITING)
namespace WebCore {
class GraphicsLayerAndroid;
- class LayerAndroid;
}
#endif
+namespace WebCore {
+ class BaseLayerAndroid;
+}
+
struct PluginWidgetAndroid;
class SkPicture;
class SkIRect;
@@ -137,8 +140,6 @@ namespace android {
#if USE(ACCELERATED_COMPOSITING)
GraphicsLayerAndroid* graphicsRootLayer() const;
- void immediateRepaint();
- void setUIRootLayer(const LayerAndroid* layer);
#endif
/** Invalidate the view/screen, NOT the content/DOM, but expressed in
@@ -170,15 +171,9 @@ namespace android {
/**
* Notify the view to restore the screen width, which in turn restores
- * the scale.
- */
- void restoreScale(int);
-
- /**
- * Notify the view to restore the scale used to calculate the screen
- * width for wrapping the text
+ * the scale. Also restore the scale for the text wrap.
*/
- void restoreScreenWidthScale(int);
+ void restoreScale(int scale, int textWrapScale);
/**
* Tell the java side to update the focused textfield
@@ -325,6 +320,18 @@ namespace android {
* If start and end are out of order, swap them.
*/
void setSelection(int start, int end);
+
+ /**
+ * Modifies the current selection.
+ *
+ * alter - Specifies how to alter the selection.
+ * direction - The direction in which to alter the selection.
+ * granularity - The granularity of the selection modification.
+ *
+ * returns - The selection as string.
+ */
+ String modifySelection(const String& alter, const String& direction, const String& granularity);
+
/**
* In the currently focused textfield, replace the characters from oldStart to oldEnd
* (if oldStart == oldEnd, this will be an insert at that position) with replace,
@@ -432,6 +439,9 @@ namespace android {
// in the current view.
void centerFitRect(int x, int y, int width, int height);
+ // return a list of rects matching the touch point (x, y) with the slop
+ Vector<IntRect> getTouchHighlightRects(int x, int y, int slop);
+
// other public functions
public:
// Open a file chooser for selecting a file to upload
@@ -440,27 +450,22 @@ namespace android {
// reset the picture set to empty
void clearContent();
- // flatten the picture set to a picture
- void copyContentToPicture(SkPicture* );
-
- // draw the picture set with the specified background color
- bool drawContent(SkCanvas* , SkColor );
bool focusBoundsChanged();
- bool pictureReady();
// record the inval area, and the picture size
- bool recordContent(SkRegion* , SkIPoint* );
- int screenWidth() const { return m_screenWidth; }
- int screenHeight() const { return m_screenHeight; }
+ BaseLayerAndroid* recordContent(SkRegion* , SkIPoint* );
+ int textWrapWidth() const { return m_textWrapWidth; }
float scale() const { return m_scale; }
- float screenWidthScale() const { return m_screenWidthScale; }
+ float textWrapScale() const { return m_screenWidth * m_scale / m_textWrapWidth; }
WebCore::Frame* mainFrame() const { return m_mainFrame; }
void updateCursorBounds(const CachedRoot* root,
const CachedFrame* cachedFrame, const CachedNode* cachedNode);
void updateFrameCacheIfLoading();
// utility to split slow parts of the picture set
- void splitContent();
+ void splitContent(PictureSet*);
+
+ void notifyWebAppCanBeInstalled();
// these members are shared with webview.cpp
static Mutex gFrameCacheMutex;
@@ -510,8 +515,7 @@ namespace android {
WebCore::IntRect m_lastFocusedBounds;
int m_lastFocusedSelStart;
int m_lastFocusedSelEnd;
- static Mutex m_contentMutex; // protects ui/core thread pictureset access
- PictureSet m_content; // the set of pictures to draw (accessed by UI too)
+ 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
// Used in passToJS to avoid updating the UI text field until after the
@@ -536,8 +540,8 @@ 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
+ int m_textWrapWidth;
float m_scale;
- float m_screenWidthScale;
unsigned m_domtree_version;
bool m_check_domtree_version;
PageGroup* m_groupForVisitedLinks;
@@ -558,7 +562,6 @@ namespace android {
#if ENABLE(TOUCH_EVENTS)
bool m_forwardingTouchEvents;
- IntPoint m_lastTouchPoint;
#endif
#if DEBUG_NAV_UI
diff --git a/WebKit/android/nav/CacheBuilder.cpp b/WebKit/android/nav/CacheBuilder.cpp
index 7ee2a16..1c8af5e 100644
--- a/WebKit/android/nav/CacheBuilder.cpp
+++ b/WebKit/android/nav/CacheBuilder.cpp
@@ -412,7 +412,7 @@ void CacheBuilder::Debug::groups() {
comma(scratch);
Element* element = static_cast<Element*>(node);
if (node->isElementNode() && element->hasID())
- wideString(element->getIDAttribute());
+ wideString(element->getIdAttribute());
else if (node->isTextNode()) {
#if 01 // set to one to abbreviate text that can be omitted from the address detection code
if (rect.isEmpty() && node->textContent().length() > 100) {
@@ -469,22 +469,48 @@ void CacheBuilder::Debug::groups() {
}
}
}
- count++;
- newLine();
-#if USE(ACCELERATED_COMPOSITING)
- if (renderer && layer) {
+ if (renderer) {
+ RenderStyle* style = renderer->style();
+ snprintf(scratch, sizeof(scratch), "// renderStyle:"
+ " visibility=%s hasBackGround=%d"
+ " tapHighlightColor().alpha()=0x%02x",
+ style->visibility() == HIDDEN ? "HIDDEN" : "VISIBLE",
+ renderer->hasBackground(), style->tapHighlightColor().alpha());
+ newLine();
+ print(scratch);
+ RenderBlock* renderBlock = static_cast<RenderBlock*>(renderer);
+ if (renderer->isRenderBlock() && renderBlock->hasColumns()) {
+ const RenderBox* box = static_cast<RenderBox*>(renderer);
+ const IntRect& oRect = box->visibleOverflowRect();
+ snprintf(scratch, sizeof(scratch), "// renderBlock:"
+ " columnRects=%d columnGap=%d direction=%d"
+ " hasOverflowClip=%d overflow=(%d,%d,w=%d,h=%d)",
+ renderBlock->columnRects(), renderBlock->columnGap(),
+ renderBlock->style()->direction(), renderer->hasOverflowClip(),
+ oRect.x(), oRect.y(), oRect.width(), oRect.height());
+ newLine();
+ print(scratch);
+ }
+ }
+ #if USE(ACCELERATED_COMPOSITING)
+ if (renderer && renderer->hasLayer()) {
+ RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
RenderLayerBacking* back = layer->backing();
GraphicsLayerAndroid* grLayer = static_cast
<GraphicsLayerAndroid*>(back ? back->graphicsLayer() : 0);
LayerAndroid* aLayer = grLayer ? grLayer->contentLayer() : 0;
const SkPicture* pict = aLayer ? aLayer->picture() : 0;
+ const IntRect& r = renderer->absoluteBoundingBoxRect();
snprintf(scratch, sizeof(scratch), "// layer:%p back:%p"
- " gLayer:%p aLayer:%p pict:%p", layer, back, grLayer,
- aLayer, pict);
- print(scratch);
+ " gLayer:%p aLayer:%p pict:%p r:(%d,%d,w=%d,h=%d)",
+ layer, back, grLayer, aLayer, pict, r.x(), r.y(),
+ r.width(), r.height());
newLine();
- }
-#endif
+ print(scratch);
+ }
+ #endif
+ count++;
+ newLine();
} while ((node = node->traverseNextNode()) != NULL);
DUMP_NAV_LOGD("}; // focusables = %d\n", count - 1);
DUMP_NAV_LOGD("\n");
@@ -841,6 +867,7 @@ bool CacheBuilder::AnyIsClick(Node* node)
void CacheBuilder::buildCache(CachedRoot* root)
{
Frame* frame = FrameAnd(this);
+ mPictureSetDisabled = false;
BuildFrame(frame, frame, root, (CachedFrame*) root);
root->finishInit(); // set up frame parent pointers, child pointers
setData((CachedFrame*) root);
@@ -1028,7 +1055,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
RenderStyle* style = nodeRenderer->style();
if (style->visibility() == HIDDEN)
continue;
- isTransparent = style->hasBackground() == false;
+ isTransparent = nodeRenderer->hasBackground() == false;
#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
hasCursorRing = style->tapHighlightColor().alpha() > 0;
#endif
@@ -1105,6 +1132,8 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
if (node->hasTagName(HTMLNames::bodyTag))
bodyPos = originalAbsBounds.location();
+ else if (node->hasTagName(HTMLNames::canvasTag))
+ mPictureSetDisabled = true;
if (checkForPluginViewThatWantsFocus(nodeRenderer)) {
bounds = absBounds;
isUnclipped = true;
@@ -1112,13 +1141,18 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
type = PLUGIN_CACHEDNODETYPE;
goto keepNode;
}
+ // Only use the root contentEditable element
+ if (node->isContentEditable() && !node->parent()->isContentEditable()) {
+ bounds = absBounds;
+ takesFocus = true;
+ type = CONTENT_EDITABLE_CACHEDNODETYPE;
+ goto keepNode;
+ }
if (nodeRenderer->isRenderBlock()) {
RenderBlock* renderBlock = (RenderBlock*) nodeRenderer;
if (renderBlock->hasColumns()) {
columns = renderBlock->columnRects();
-#ifdef ANDROID_EXPOSE_COLUMN_GAP
columnGap = renderBlock->columnGap();
-#endif
direction = renderBlock->style()->direction();
}
}
@@ -1216,6 +1250,8 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
if (!href.isEmpty() && !WebCore::protocolIsJavaScript(href.string()))
// Set the exported string for all non-javascript anchors.
exported = href.string().threadsafeCopy();
+ } else if (node->hasTagName(HTMLNames::selectTag)) {
+ type = SELECT_CACHEDNODETYPE;
}
if (type == TEXT_INPUT_CACHEDNODETYPE) {
RenderTextControl* renderText =
@@ -2673,7 +2709,8 @@ bool CacheBuilder::isFocusableText(NodeWalk* walk, bool more, Node* node,
do {
do {
do {
- node = node->traverseNextNode();
+ if (node)
+ node = node->traverseNextNode();
if (node == NULL || node->hasTagName(HTMLNames::aTag)
|| node->hasTagName(HTMLNames::inputTag)
|| node->hasTagName(HTMLNames::textareaTag)) {
diff --git a/WebKit/android/nav/CacheBuilder.h b/WebKit/android/nav/CacheBuilder.h
index 4ded58d..8183954 100644
--- a/WebKit/android/nav/CacheBuilder.h
+++ b/WebKit/android/nav/CacheBuilder.h
@@ -94,6 +94,7 @@ public:
static IntRect getAreaRect(const HTMLAreaElement* area);
static void GetGlobalOffset(Frame* , int* x, int * y);
static void GetGlobalOffset(Node* , int* x, int * y);
+ bool pictureSetDisabled() { return mPictureSetDisabled; }
static bool validNode(Frame* startFrame, void* framePtr, void* nodePtr);
private:
enum AddressProgress {
@@ -249,6 +250,7 @@ private:
Node* tryFocus(Direction direction);
Node* trySegment(Direction direction, int mainStart, int mainEnd);
CachedNodeBits mAllowableTypes;
+ bool mPictureSetDisabled;
#if DUMP_NAV_CACHE
public:
class Debug {
diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp
index ce5600b..ff13508 100644
--- a/WebKit/android/nav/CachedFrame.cpp
+++ b/WebKit/android/nav/CachedFrame.cpp
@@ -1390,6 +1390,7 @@ void CachedFrame::Debug::print() const
const CachedInput* input = b->textInput(node);
if (input)
input->mDebug.print();
+ DUMP_NAV_LOGD("\n");
}
DUMP_NAV_LOGD("// }; // end of nodes\n");
#if USE(ACCELERATED_COMPOSITING)
diff --git a/WebKit/android/nav/CachedInput.cpp b/WebKit/android/nav/CachedInput.cpp
index 924bbca..608c41b 100644
--- a/WebKit/android/nav/CachedInput.cpp
+++ b/WebKit/android/nav/CachedInput.cpp
@@ -28,6 +28,11 @@
namespace android {
+void CachedInput::init() {
+ bzero(this, sizeof(CachedInput));
+ mName = WebCore::String();
+}
+
#if DUMP_NAV_CACHE
#define DEBUG_PRINT_BOOL(field) \
@@ -55,7 +60,7 @@ void CachedInput::Debug::print() const
{
CachedInput* b = base();
printWebCoreString("// char* mName=\"", b->mName);
- DUMP_NAV_LOGD("// void* mForm=%p;", b->mForm);
+ DUMP_NAV_LOGD("// void* mForm=%p;\n", b->mForm);
DUMP_NAV_LOGD("// int mMaxLength=%d;\n", b->mMaxLength);
DUMP_NAV_LOGD("// int mTextSize=%d;\n", b->mTextSize);
DUMP_NAV_LOGD("// int mInputType=%d;\n", b->mInputType);
diff --git a/WebKit/android/nav/CachedInput.h b/WebKit/android/nav/CachedInput.h
index 42cadf1..a3d6b10 100644
--- a/WebKit/android/nav/CachedInput.h
+++ b/WebKit/android/nav/CachedInput.h
@@ -39,10 +39,7 @@ public:
// constructor
}
void* formPointer() const { return mForm; }
- void init() {
- bzero(this, sizeof(CachedInput));
- mName = WebCore::String();
- }
+ void init();
WebCore::HTMLInputElement::InputType inputType() const { return mInputType; }
bool isRtlText() const { return mIsRtlText; }
bool isTextField() const { return mIsTextField; }
diff --git a/WebKit/android/nav/CachedNode.cpp b/WebKit/android/nav/CachedNode.cpp
index 0c9d541..8fc5f5b 100644
--- a/WebKit/android/nav/CachedNode.cpp
+++ b/WebKit/android/nav/CachedNode.cpp
@@ -367,6 +367,8 @@ const char* CachedNode::Debug::type(android::CachedNodeType t) const
case FRAME_CACHEDNODETYPE: return "FRAME"; break;
case PLUGIN_CACHEDNODETYPE: return "PLUGIN"; break;
case TEXT_INPUT_CACHEDNODETYPE: return "INPUT"; break;
+ case SELECT_CACHEDNODETYPE: return "SELECT"; break;
+ case CONTENT_EDITABLE_CACHEDNODETYPE: return "CONTENT_EDITABLE"; break;
default: return "???";
}
}
@@ -419,7 +421,6 @@ void CachedNode::Debug::print() const
DEBUG_PRINT_BOOL(mLast);
DEBUG_PRINT_BOOL(mUseBounds);
DEBUG_PRINT_BOOL(mUseHitBounds);
- DUMP_NAV_LOGD("\n");
}
#endif
diff --git a/WebKit/android/nav/CachedNode.h b/WebKit/android/nav/CachedNode.h
index f3cfd98..09f53c3 100644
--- a/WebKit/android/nav/CachedNode.h
+++ b/WebKit/android/nav/CachedNode.h
@@ -108,6 +108,7 @@ public:
int index() const { return mIndex; }
void init(WebCore::Node* node);
bool isAnchor() const { return mType == ANCHOR_CACHEDNODETYPE; }
+ bool isContentEditable() const { return mType == CONTENT_EDITABLE_CACHEDNODETYPE; }
bool isCursor() const { return mIsCursor; }
bool isArea() const { return mType == AREA_CACHEDNODETYPE; }
bool isFocus() const { return mIsFocus; }
@@ -118,6 +119,7 @@ public:
return clip.intersects(bounds(frame));
}
bool isPlugin() const { return mType == PLUGIN_CACHEDNODETYPE; }
+ bool isSelect() const { return mType == SELECT_CACHEDNODETYPE; }
bool isSyntheticLink() const {
return mType >= ADDRESS_CACHEDNODETYPE && mType <= PHONE_CACHEDNODETYPE;
}
@@ -173,7 +175,7 @@ public:
const CachedNode* traverseNextNode() const { return mLast ? NULL : &this[1]; }
bool useBounds() const { return mUseBounds; }
bool useHitBounds() const { return mUseHitBounds; }
- bool wantsKeyEvents() const { return isTextInput() || isPlugin(); }
+ bool wantsKeyEvents() const { return isTextInput() || isPlugin() || isContentEditable(); }
private:
friend class CacheBuilder;
WebCore::String mExport;
diff --git a/WebKit/android/nav/CachedNodeType.h b/WebKit/android/nav/CachedNodeType.h
index 21e2d40..8bc9328 100644
--- a/WebKit/android/nav/CachedNodeType.h
+++ b/WebKit/android/nav/CachedNodeType.h
@@ -37,7 +37,9 @@ enum CachedNodeType {
AREA_CACHEDNODETYPE,
FRAME_CACHEDNODETYPE,
PLUGIN_CACHEDNODETYPE,
- TEXT_INPUT_CACHEDNODETYPE
+ TEXT_INPUT_CACHEDNODETYPE,
+ SELECT_CACHEDNODETYPE,
+ CONTENT_EDITABLE_CACHEDNODETYPE
};
enum CachedNodeBits {
diff --git a/WebKit/android/nav/CachedPrefix.h b/WebKit/android/nav/CachedPrefix.h
index b682288..73a5c2c 100644
--- a/WebKit/android/nav/CachedPrefix.h
+++ b/WebKit/android/nav/CachedPrefix.h
@@ -43,4 +43,11 @@
#define OFFSETOF(type, field) ((char*)&(((type*)1)->field) - (char*)1) // avoids gnu warning
+#ifndef BZERO_DEFINED
+#define BZERO_DEFINED
+// http://www.opengroup.org/onlinepubs/000095399/functions/bzero.html
+// For maximum portability, it is recommended to replace the function call to bzero() as follows:
+#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
+#endif
+
#endif
diff --git a/WebKit/android/nav/FindCanvas.cpp b/WebKit/android/nav/FindCanvas.cpp
index d8e908b..8eaaaef 100644
--- a/WebKit/android/nav/FindCanvas.cpp
+++ b/WebKit/android/nav/FindCanvas.cpp
@@ -98,7 +98,7 @@ GlyphSet::~GlyphSet() {
// part of mLowerGlyphs
}
-GlyphSet::GlyphSet& GlyphSet::operator=(GlyphSet& src) {
+GlyphSet& GlyphSet::operator=(GlyphSet& src) {
mTypeface = src.mTypeface;
mCount = src.mCount;
if (mCount > MAX_STORAGE_COUNT) {
@@ -675,4 +675,3 @@ void FindOnPage::setMatches(WTF::Vector<MatchInfo>* matches)
}
}
-
diff --git a/WebKit/android/nav/FindCanvas.h b/WebKit/android/nav/FindCanvas.h
index b9dbeea..34929ec 100644
--- a/WebKit/android/nav/FindCanvas.h
+++ b/WebKit/android/nav/FindCanvas.h
@@ -220,6 +220,7 @@ public:
virtual ~FindOnPage() { delete m_matches; }
void clearCurrentLocation() { m_hasCurrentLocation = false; }
IntRect currentMatchBounds() const;
+ int currentMatchIndex() const { return m_findIndex; }
bool currentMatchIsInLayer() const;
virtual void draw(SkCanvas* , LayerAndroid* );
void findNext(bool forward);
diff --git a/WebKit/android/nav/SelectText.cpp b/WebKit/android/nav/SelectText.cpp
index e471307..9df6ef5 100644
--- a/WebKit/android/nav/SelectText.cpp
+++ b/WebKit/android/nav/SelectText.cpp
@@ -23,9 +23,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define LOG_TAG "webcoreglue"
+#define LOG_TAG "webviewglue"
#include "CachedPrefix.h"
+#include "BidiResolver.h"
#include "CachedRoot.h"
#include "LayerAndroid.h"
#include "SelectText.h"
@@ -39,26 +40,156 @@
#include "SkRect.h"
#include "SkRegion.h"
#include "SkUtils.h"
+#include "TextRun.h"
#ifdef DEBUG_NAV_UI
-#include "CString.h"
+#include <wtf/text/CString.h>
#endif
+#define VERBOSE_LOGGING 0
+// #define EXTRA_NOISY_LOGGING 1
+
+// TextRunIterator has been copied verbatim from GraphicsContext.cpp
+namespace WebCore {
+
+class TextRunIterator {
+public:
+ TextRunIterator()
+ : m_textRun(0)
+ , m_offset(0)
+ {
+ }
+
+ TextRunIterator(const TextRun* textRun, unsigned offset)
+ : m_textRun(textRun)
+ , m_offset(offset)
+ {
+ }
+
+ TextRunIterator(const TextRunIterator& other)
+ : m_textRun(other.m_textRun)
+ , m_offset(other.m_offset)
+ {
+ }
+
+ unsigned offset() const { return m_offset; }
+ void increment() { m_offset++; }
+ bool atEnd() const { return !m_textRun || m_offset >= m_textRun->length(); }
+ UChar current() const { return (*m_textRun)[m_offset]; }
+ WTF::Unicode::Direction direction() const { return atEnd() ? WTF::Unicode::OtherNeutral : WTF::Unicode::direction(current()); }
+
+ bool operator==(const TextRunIterator& other)
+ {
+ return m_offset == other.m_offset && m_textRun == other.m_textRun;
+ }
+
+ bool operator!=(const TextRunIterator& other) { return !operator==(other); }
+
+private:
+ const TextRun* m_textRun;
+ int m_offset;
+};
+
+// ReverseBidi is a trimmed-down version of GraphicsContext::drawBidiText()
+void ReverseBidi(UChar* chars, int len) {
+ using namespace WTF::Unicode;
+ WTF::Vector<UChar> result;
+ result.reserveCapacity(len);
+ TextRun run(chars, len);
+ BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
+ bidiResolver.setStatus(BidiStatus(LeftToRight, LeftToRight, LeftToRight,
+ BidiContext::create(0, LeftToRight, false)));
+ bidiResolver.setPosition(TextRunIterator(&run, 0));
+ bidiResolver.createBidiRunsForLine(TextRunIterator(&run, len));
+ if (!bidiResolver.runCount())
+ return;
+ BidiCharacterRun* bidiRun = bidiResolver.firstRun();
+ while (bidiRun) {
+ int bidiStart = bidiRun->start();
+ int bidiStop = bidiRun->stop();
+ int size = result.size();
+ int bidiCount = bidiStop - bidiStart;
+ result.append(chars + bidiStart, bidiCount);
+ if (bidiRun->level() % 2) {
+ UChar* start = &result[size];
+ UChar* end = start + bidiCount;
+ // reverse the order of any RTL substrings
+ while (start < end) {
+ UChar temp = *start;
+ *start++ = *--end;
+ *end = temp;
+ }
+ start = &result[size];
+ end = start + bidiCount - 1;
+ // if the RTL substring had a surrogate pair, restore its order
+ while (start < end) {
+ UChar trail = *start++;
+ if (!U16_IS_SURROGATE(trail))
+ continue;
+ start[-1] = *start; // lead
+ *start++ = trail;
+ }
+ }
+ bidiRun = bidiRun->next();
+ }
+ bidiResolver.deleteRuns();
+ memcpy(chars, &result[0], len * sizeof(UChar));
+}
+
+}
+
namespace android {
+/* SpaceBounds and SpaceCanvas are used to measure the left and right side
+ * bearings of two consecutive glyphs to help determine if the glyphs were
+ * originally laid out with a space character between the glyphs.
+ */
+class SpaceBounds : public SkBounder {
+public:
+ virtual bool onIRectGlyph(const SkIRect& , const SkBounder::GlyphRec& rec)
+ {
+ mFirstGlyph = mLastGlyph;
+ mLastGlyph = rec;
+ return false;
+ }
+
+ SkBounder::GlyphRec mFirstGlyph;
+ SkBounder::GlyphRec mLastGlyph;
+};
+
+class SpaceCanvas : public SkCanvas {
+public:
+ SpaceCanvas(const SkIRect& area)
+ {
+ setBounder(&mBounder);
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, area.width(),
+ area.height());
+ setBitmapDevice(bitmap);
+ translate(SkIntToScalar(-area.fLeft), SkIntToScalar(-area.fTop));
+ }
+
+ SpaceBounds mBounder;
+};
+
+#define HYPHEN_MINUS 0x2D // ASCII hyphen
+#define HYPHEN 0x2010 // unicode hyphen, first in range of dashes
+#define HORZ_BAR 0x2015 // unicode horizontal bar, last in range of dashes
+#define TOUCH_SLOP 10 // additional distance from character rect when hit
+
class CommonCheck : public SkBounder {
public:
- CommonCheck() : mMatrix(NULL), mPaint(NULL) {}
-
- virtual void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y,
- const void* text) {
- mMatrix = &matrix;
- mPaint = &paint;
- mText = static_cast<const uint16_t*>(text);
- mY = y;
- mBase = mBottom = mTop = INT_MAX;
+ CommonCheck(int width, int height)
+ : mHeight(height)
+ , mLastUni(0)
+ , mMatrix(0)
+ , mPaint(0)
+ , mWidth(width)
+ {
+ mLastGlyph.fGlyphID = static_cast<uint16_t>(-1);
+ reset();
}
-
+
int base() {
if (mBase == INT_MAX) {
SkPoint result;
@@ -78,7 +209,148 @@ public:
}
return mBottom;
}
-
+
+#if DEBUG_NAV_UI
+ // make current (possibily uncomputed) value visible for debugging
+ int bottomDebug() const
+ {
+ return mBottom;
+ }
+#endif
+
+ bool addNewLine(const SkBounder::GlyphRec& rec)
+ {
+ SkFixed lineSpacing = SkFixedAbs(mLastGlyph.fLSB.fY - rec.fLSB.fY);
+ SkFixed lineHeight = SkIntToFixed(bottom() - top());
+ return lineSpacing >= lineHeight + (lineHeight >> 1); // 1.5
+ }
+
+ bool addSpace(const SkBounder::GlyphRec& rec)
+ {
+ bool newBaseLine = mLastGlyph.fLSB.fY != rec.fLSB.fY;
+ if (((mLastUni >= HYPHEN && mLastUni <= HORZ_BAR)
+ || mLastUni == HYPHEN_MINUS) && newBaseLine)
+ {
+ return false;
+ }
+ return isSpace(rec);
+ }
+
+ void finishGlyph()
+ {
+ mLastGlyph = mLastCandidate;
+ mLastUni = mLastUniCandidate;
+ }
+
+ SkUnichar getUniChar(const SkBounder::GlyphRec& rec)
+ {
+ SkUnichar unichar;
+ SkPaint utfPaint = *mPaint;
+ utfPaint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ utfPaint.glyphsToUnichars(&rec.fGlyphID, 1, &unichar);
+ return unichar;
+ }
+
+ bool isSpace(const SkBounder::GlyphRec& rec)
+ {
+ DBG_NAV_LOGD("mLastGlyph=((%g, %g),(%g, %g), %d)"
+ " rec=((%g, %g),(%g, %g), %d)"
+ " mMinSpaceWidth=%g mLastUni=0x%04x '%c'",
+ SkFixedToScalar(mLastGlyph.fLSB.fX),
+ SkFixedToScalar(mLastGlyph.fLSB.fY),
+ SkFixedToScalar(mLastGlyph.fRSB.fX),
+ SkFixedToScalar(mLastGlyph.fRSB.fY), mLastGlyph.fGlyphID,
+ SkFixedToScalar(rec.fLSB.fX), SkFixedToScalar(rec.fLSB.fY),
+ SkFixedToScalar(rec.fRSB.fX), SkFixedToScalar(rec.fRSB.fY),
+ rec.fGlyphID,
+ SkFixedToScalar(mMinSpaceWidth),
+ mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?');
+ bool newBaseLine = mLastGlyph.fLSB.fY != rec.fLSB.fY;
+ if (newBaseLine)
+ return true;
+ SkFixed gapOne = mLastGlyph.fLSB.fX - rec.fRSB.fX;
+ SkFixed gapTwo = rec.fLSB.fX - mLastGlyph.fRSB.fX;
+ if (gapOne < 0 && gapTwo < 0)
+ return false; // overlaps
+ uint16_t test[2];
+ test[0] = mLastGlyph.fGlyphID;
+ test[1] = rec.fGlyphID;
+ SkIRect area;
+ area.set(0, 0, mWidth, mHeight);
+ SpaceCanvas spaceChecker(area);
+ spaceChecker.drawText(test, sizeof(test),
+ SkFixedToScalar(mLastGlyph.fLSB.fX),
+ SkFixedToScalar(mLastGlyph.fLSB.fY), *mPaint);
+ const SkBounder::GlyphRec& g1 = spaceChecker.mBounder.mFirstGlyph;
+ const SkBounder::GlyphRec& g2 = spaceChecker.mBounder.mLastGlyph;
+ DBG_NAV_LOGD("g1=(%g, %g,%g, %g) g2=(%g, %g, %g, %g)",
+ SkFixedToScalar(g1.fLSB.fX), SkFixedToScalar(g1.fLSB.fY),
+ SkFixedToScalar(g1.fRSB.fX), SkFixedToScalar(g1.fRSB.fY),
+ SkFixedToScalar(g2.fLSB.fX), SkFixedToScalar(g2.fLSB.fY),
+ SkFixedToScalar(g2.fRSB.fX), SkFixedToScalar(g2.fRSB.fY));
+ gapOne = SkFixedAbs(gapOne);
+ gapTwo = SkFixedAbs(gapTwo);
+ SkFixed gap = gapOne < gapTwo ? gapOne : gapTwo;
+ SkFixed overlap = g2.fLSB.fX - g1.fRSB.fX;
+ if (overlap < 0)
+ gap -= overlap;
+ DBG_NAV_LOGD("gap=%g overlap=%g gapOne=%g gapTwo=%g minSpaceWidth()=%g",
+ SkFixedToScalar(gap), SkFixedToScalar(overlap),
+ SkFixedToScalar(gapOne), SkFixedToScalar(gapTwo),
+ SkFixedToScalar(minSpaceWidth()));
+ // FIXME: the -1/2 below takes care of slop beween the computed gap
+ // and the actual space width -- it's a rounding error from
+ // moving from fixed to float and back and could be much smaller.
+ return gap >= minSpaceWidth() - SK_Fixed1 / 2;
+ }
+
+ SkFixed minSpaceWidth()
+ {
+ if (mMinSpaceWidth == SK_FixedMax) {
+ SkPaint charPaint = *mPaint;
+ charPaint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
+ SkScalar width = charPaint.measureText(" ", 1);
+ mMinSpaceWidth = SkScalarToFixed(width * mMatrix->getScaleX());
+ DBG_NAV_LOGD("width=%g matrix sx/sy=(%g, %g) tx/ty=(%g, %g)"
+ " mMinSpaceWidth=%g", width,
+ mMatrix->getScaleX(), mMatrix->getScaleY(),
+ mMatrix->getTranslateX(), mMatrix->getTranslateY(),
+ SkFixedToScalar(mMinSpaceWidth));
+ }
+ return mMinSpaceWidth;
+ }
+
+ void recordGlyph(const SkBounder::GlyphRec& rec)
+ {
+ mLastCandidate = rec;
+ mLastUniCandidate = getUniChar(rec);
+ }
+
+ void reset()
+ {
+ mMinSpaceWidth = SK_FixedMax; // mark as uninitialized
+ mBase = mBottom = mTop = INT_MAX; // mark as uninitialized
+ }
+
+ void set(CommonCheck& check)
+ {
+ mLastGlyph = check.mLastGlyph;
+ mLastUni = check.mLastUni;
+ mMatrix = check.mMatrix;
+ mPaint = check.mPaint;
+ reset();
+ }
+
+ void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y,
+ const void* text)
+ {
+ mMatrix = &matrix;
+ mPaint = &paint;
+ mText = static_cast<const uint16_t*>(text);
+ mY = y;
+ reset();
+ }
+
int top() {
if (mTop == INT_MAX) {
SkPoint result;
@@ -89,127 +361,417 @@ public:
}
return mTop;
}
-
-protected:
+
+#if DEBUG_NAV_UI
+ // make current (possibily uncomputed) value visible for debugging
+ int topDebug() const
+ {
+ return mTop;
+ }
+#endif
+
+protected:
+ int mHeight;
+ SkBounder::GlyphRec mLastCandidate;
+ SkBounder::GlyphRec mLastGlyph;
+ SkUnichar mLastUni;
+ SkUnichar mLastUniCandidate;
const SkMatrix* mMatrix;
const SkPaint* mPaint;
const uint16_t* mText;
+ int mWidth;
SkScalar mY;
+private:
int mBase;
int mBottom;
+ SkFixed mMinSpaceWidth;
int mTop;
+ friend class EdgeCheck;
};
class FirstCheck : public CommonCheck {
public:
- FirstCheck(int x, int y)
- : mDistance(INT_MAX), mFocusX(x), mFocusY(y) {
- mBestBounds.setEmpty();
+ FirstCheck(int x, int y, const SkIRect& area)
+ : INHERITED(area.width(), area.height())
+ , mFocusX(x - area.fLeft)
+ , mFocusY(y - area.fTop)
+ , mRecordGlyph(false)
+ {
+ reset();
}
- const SkIRect& bestBounds() {
- DBG_NAV_LOGD("mBestBounds:(%d, %d, %d, %d) mTop=%d mBottom=%d",
+ const SkIRect& adjustedBounds(const SkIRect& area, int* base)
+ {
+ *base = mBestBase + area.fTop;
+ mBestBounds.offset(area.fLeft, area.fTop);
+ DBG_NAV_LOGD("FirstCheck mBestBounds:(%d, %d, %d, %d) mTop=%d mBottom=%d",
mBestBounds.fLeft, mBestBounds.fTop, mBestBounds.fRight,
- mBestBounds.fBottom, mTop, mBottom);
- return mBestBounds;
- }
-
- void offsetBounds(int dx, int dy) {
- mBestBounds.offset(dx, dy);
+ mBestBounds.fBottom, topDebug(), bottomDebug());
+ return mBestBounds;
}
-
- virtual bool onIRect(const SkIRect& rect) {
- int dx = ((rect.fLeft + rect.fRight) >> 1) - mFocusX;
- int dy = ((top() + bottom()) >> 1) - mFocusY;
+
+ virtual bool onIRectGlyph(const SkIRect& rect,
+ const SkBounder::GlyphRec& rec)
+ {
+ /* compute distance from rectangle center.
+ * centerX = (rect.L + rect.R) / 2
+ * multiply centerX and comparison x by 2 to retain better precision
+ */
+ int dx = rect.fLeft + rect.fRight - (mFocusX << 1);
+ int dy = top() + bottom() - (mFocusY << 1);
int distance = dx * dx + dy * dy;
#ifdef EXTRA_NOISY_LOGGING
if (distance < 500 || abs(distance - mDistance) < 500)
- DBG_NAV_LOGD("distance=%d mDistance=%d", distance, mDistance);
+ DBG_NAV_LOGD("FirstCheck distance=%d mDistance=%d", distance, mDistance);
#endif
if (mDistance > distance) {
- mDistance = distance;
+ mBestBase = base();
mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
-#ifdef EXTRA_NOISY_LOGGING
- DBG_NAV_LOGD("mBestBounds={%d,%d,r=%d,b=%d}",
- mBestBounds.fLeft, mBestBounds.fTop,
- mBestBounds.fRight, mBestBounds.fBottom);
-#endif
+ if (distance < 100) {
+ DBG_NAV_LOGD("FirstCheck mBestBounds={%d,%d,r=%d,b=%d} distance=%d",
+ mBestBounds.fLeft, mBestBounds.fTop,
+ mBestBounds.fRight, mBestBounds.fBottom, distance >> 2);
+ }
+ mDistance = distance;
+ if (mRecordGlyph)
+ recordGlyph(rec);
}
return false;
}
+
+ void reset()
+ {
+ mBestBounds.setEmpty();
+ mDistance = INT_MAX;
+ }
+
+ void setRecordGlyph()
+ {
+ mRecordGlyph = true;
+ }
+
protected:
+ int mBestBase;
SkIRect mBestBounds;
int mDistance;
int mFocusX;
int mFocusY;
+ bool mRecordGlyph;
+private:
+ typedef CommonCheck INHERITED;
+};
+
+class EdgeCheck : public FirstCheck {
+public:
+ EdgeCheck(int x, int y, const SkIRect& area, CommonCheck& last, bool left)
+ : INHERITED(x, y, area)
+ , mLast(area.width(), area.height())
+ , mLeft(left)
+ {
+ mLast.set(last);
+ mLastGlyph = last.mLastGlyph;
+ mLastUni = last.mLastUni;
+ }
+
+ bool adjacent()
+ {
+ return !mLast.isSpace(mLastGlyph);
+ }
+
+ const SkIRect& bestBounds(int* base)
+ {
+ *base = mBestBase;
+ return mBestBounds;
+ }
+
+ virtual bool onIRectGlyph(const SkIRect& rect,
+ const SkBounder::GlyphRec& rec)
+ {
+ int dx = mLeft ? mFocusX - rect.fRight : rect.fLeft - mFocusX;
+ int dy = ((top() + bottom()) >> 1) - mFocusY;
+ if (mLeft ? mFocusX <= rect.fLeft : mFocusX >= rect.fRight) {
+ if (abs(dx) <= 10 && abs(dy) <= 10) {
+ DBG_NAV_LOGD("EdgeCheck fLeft=%d fRight=%d mFocusX=%d dx=%d dy=%d",
+ rect.fLeft, rect.fRight, mFocusX, dx, dy);
+ }
+ return false;
+ }
+ int distance = dx * dx + dy * dy;
+ if (mDistance > distance) {
+ if (rec.fLSB == mLastGlyph.fLSB && rec.fRSB == mLastGlyph.fRSB) {
+ DBG_NAV_LOGD("dup rec.fLSB.fX=%g rec.fRSB.fX=%g",
+ SkFixedToScalar(rec.fLSB.fX), SkFixedToScalar(rec.fRSB.fX));
+ return false;
+ }
+ recordGlyph(rec);
+ mDistance = distance;
+ mBestBase = base();
+ mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
+ if (distance <= 100) {
+ DBG_NAV_LOGD("EdgeCheck mBestBounds={%d,%d,r=%d,b=%d} distance=%d",
+ mBestBounds.fLeft, mBestBounds.fTop,
+ mBestBounds.fRight, mBestBounds.fBottom, distance);
+ }
+ }
+ return false;
+ }
+
+ void shiftStart(SkIRect bounds)
+ {
+ DBG_NAV_LOGD("EdgeCheck mFocusX=%d mLeft=%s bounds.fLeft=%d bounds.fRight=%d",
+ mFocusX, mLeft ? "true" : "false", bounds.fLeft, bounds.fRight);
+ reset();
+ mFocusX = mLeft ? bounds.fLeft : bounds.fRight;
+ mLast.set(*this);
+ }
+
+protected:
+ CommonCheck mLast;
+ bool mLeft;
+private:
+ typedef FirstCheck INHERITED;
+};
+
+class FindFirst : public CommonCheck {
+public:
+ FindFirst(int width, int height)
+ : INHERITED(width, height)
+ {
+ mBestBounds.set(width, height, width, height);
+ }
+
+ const SkIRect& bestBounds(int* base)
+ {
+ *base = mBestBase;
+ return mBestBounds;
+ }
+
+ virtual bool onIRect(const SkIRect& rect)
+ {
+ if (mBestBounds.isEmpty()) {
+ mBestBase = base();
+ mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
+ }
+ return false;
+ }
+
+protected:
+ int mBestBase;
+ SkIRect mBestBounds;
+private:
+ typedef CommonCheck INHERITED;
+};
+
+class FindLast : public FindFirst {
+public:
+ FindLast(int width, int height)
+ : INHERITED(width, height)
+ {
+ mBestBounds.setEmpty();
+ }
+
+ virtual bool onIRect(const SkIRect& rect)
+ {
+ mBestBase = base();
+ mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
+ return false;
+ }
+
+private:
+ typedef FindFirst INHERITED;
};
+static bool baseLinesAgree(const SkIRect& rectA, int baseA,
+ const SkIRect& rectB, int baseB)
+{
+ return (rectA.fTop < baseB && rectA.fBottom >= baseB)
+ || (rectB.fTop < baseA && rectB.fBottom >= baseA);
+}
+
class MultilineBuilder : public CommonCheck {
public:
- MultilineBuilder(const SkIRect& start, const SkIRect& end, int dx, int dy,
- SkRegion* region)
- : mStart(start), mEnd(end), mSelectRegion(region), mCapture(false) {
+ MultilineBuilder(const SkIRect& start, int startBase, const SkIRect& end,
+ int endBase, const SkIRect& area, SkRegion* region)
+ : INHERITED(area.width(),area.height())
+ , mCapture(false)
+ , mEnd(end)
+ , mEndBase(endBase)
+ , mFlipped(false)
+ , mSelectRegion(region)
+ , mStart(start)
+ , mStartBase(startBase)
+ {
+ mEnd.offset(-area.fLeft, -area.fTop);
+ mEndBase -= area.fTop;
mLast.setEmpty();
mLastBase = INT_MAX;
- mStart.offset(-dx, -dy);
- mEnd.offset(-dx, -dy);
+ mStart.offset(-area.fLeft, -area.fTop);
+ mStartBase -= area.fTop;
}
- virtual bool onIRect(const SkIRect& rect) {
- bool captureLast = false;
- if ((rect.fLeft == mStart.fLeft && rect.fRight == mStart.fRight &&
- top() == mStart.fTop && bottom() == mStart.fBottom) ||
- (rect.fLeft == mEnd.fLeft && rect.fRight == mEnd.fRight &&
- top() == mEnd.fTop && bottom() == mEnd.fBottom)) {
- captureLast = mCapture;
- mCapture ^= true;
+ void finish() {
+ if (!mFlipped || SkIRect::Intersects(mLast, mSelectRect)) {
+ if (VERBOSE_LOGGING) DBG_NAV_LOGD(" mLast=(%d,%d,r=%d,b=%d)",
+ mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom);
+ mSelectRegion->op(mLast, SkRegion::kUnion_Op);
}
- if (mCapture || captureLast) {
- SkIRect full;
- full.set(rect.fLeft, top(), rect.fRight, bottom());
- if ((mLast.fTop < base() && mLast.fBottom >= base())
- || (mLastBase <= full.fBottom && mLastBase > full.fTop)) {
- if (full.fLeft > mLast.fRight)
- full.fLeft = mLast.fRight;
- else if (full.fRight < mLast.fLeft)
- full.fRight = mLast.fLeft;
+ }
+
+ // return true if capture end was not found after capture begin
+ bool flipped() {
+ DBG_NAV_LOGD("flipped=%s", mCapture ? "true" : "false");
+ if (!mCapture)
+ return false;
+ mFlipped = true;
+ mSelectRect = mStart;
+ mSelectRect.join(mEnd);
+ mLast.setEmpty();
+ mLastBase = INT_MAX;
+ mSelectRegion->setEmpty();
+ return true;
+ }
+
+ virtual bool onIRect(const SkIRect& rect) {
+ SkIRect full;
+ full.set(rect.fLeft, top(), rect.fRight, bottom());
+ int fullBase = base();
+ if (mFlipped) {
+ if (fullBase < mStart.fTop || fullBase > mEnd.fBottom
+ || (baseLinesAgree(mStart, mStartBase, full, fullBase)
+ && full.fLeft < mStart.fLeft)
+ || (baseLinesAgree(mEnd, mEndBase, full, fullBase)
+ && full.fRight > mEnd.fRight)) {
+ return false;
+ }
+ if (baseLinesAgree(mLast, mLastBase, full, fullBase)
+ && (full.fLeft - mLast.fRight < minSpaceWidth() * 3
+ || (SkIRect::Intersects(full, mSelectRect)
+ && SkIRect::Intersects(mLast, mSelectRect)))) {
+ mLast.join(full);
+ return false;
}
- mSelectRegion->op(full, SkRegion::kUnion_Op);
- DBG_NAV_LOGD("MultilineBuilder full=(%d,%d,r=%d,b=%d)",
- full.fLeft, full.fTop, full.fRight, full.fBottom);
+ finish();
mLast = full;
- mLastBase = base();
- if (mStart == mEnd)
- mCapture = false;
+ mLastBase = fullBase;
+ return false;
+ }
+ if (full == mStart)
+ mCapture = true;
+ if (mCapture) {
+ if (baseLinesAgree(mLast, mLastBase, full, fullBase))
+ mLast.join(full);
+ else {
+ finish();
+ mLast = full;
+ mLastBase = fullBase;
+ }
}
+ if (full == mEnd)
+ mCapture = false;
return false;
}
-protected:
- SkIRect mStart;
+
+protected:
+ bool mCapture;
SkIRect mEnd;
+ int mEndBase;
+ bool mFlipped;
SkIRect mLast;
int mLastBase;
+ SkIRect mSelectRect;
SkRegion* mSelectRegion;
- bool mCapture;
+ SkIRect mStart;
+ int mStartBase;
+private:
+ typedef CommonCheck INHERITED;
};
-#define HYPHEN_MINUS 0x2D // ASCII hyphen
-#define HYPHEN 0x2010 // unicode hyphen, first in range of dashes
-#define HORZ_BAR 0x2015 // unicode horizontal bar, last in range of dashes
+static inline bool compareBounds(const SkIRect* first, const SkIRect* second)
+{
+ return first->fTop < second->fTop;
+}
class TextExtractor : public CommonCheck {
public:
- TextExtractor(const SkRegion& region) : mSelectRegion(region),
- mSkipFirstSpace(true) { // don't start with a space
+ TextExtractor(const SkIRect& start, int startBase, const SkIRect& end,
+ int endBase, const SkIRect& area, bool flipped)
+ : INHERITED(area.width(), area.height())
+ , mEnd(end)
+ , mEndBase(endBase)
+ , mFlipped(flipped)
+ , mRecord(false)
+ , mSelectRect(start)
+ , mSkipFirstSpace(true) // don't start with a space
+ , mStart(start)
+ , mStartBase(startBase)
+ {
+ mEmpty.setEmpty();
+ mEnd.offset(-area.fLeft, -area.fTop);
+ mEndBase -= area.fTop;
+ mLast.setEmpty();
+ mLastBase = INT_MAX;
+ mSelectRect.join(end);
+ mSelectRect.offset(-area.fLeft, -area.fTop);
+ mStart.offset(-area.fLeft, -area.fTop);
+ mStartBase -= area.fTop;
+ }
+
+ void addCharacter(const SkBounder::GlyphRec& rec)
+ {
+ if (!mSkipFirstSpace) {
+ if (addNewLine(rec)) {
+ DBG_NAV_LOG("write new line");
+ *mSelectText.append() = '\n';
+ *mSelectText.append() = '\n';
+ } else if (addSpace(rec)) {
+ DBG_NAV_LOG("write space");
+ *mSelectText.append() = ' ';
+ }
+ } else
+ mSkipFirstSpace = false;
+ recordGlyph(rec);
+ finishGlyph();
+ if (VERBOSE_LOGGING) DBG_NAV_LOGD("glyphID=%d uni=%d '%c'", rec.fGlyphID,
+ mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?');
+ if (mLastUni) {
+ uint16_t chars[2];
+ size_t count = SkUTF16_FromUnichar(mLastUni, chars);
+ *mSelectText.append() = chars[0];
+ if (count == 2)
+ *mSelectText.append() = chars[1];
+ }
}
- virtual void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y,
- const void* text) {
- INHERITED::setUp(paint, matrix, y, text);
- SkPaint charPaint = paint;
- charPaint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
- mMinSpaceWidth = std::max(0, SkScalarToFixed(
- charPaint.measureText(" ", 1)) - SK_Fixed1);
+ void finish()
+ {
+ Vector<SkIRect*> sortedBounds;
+ SkTDArray<uint16_t> temp;
+ int index;
+ DBG_NAV_LOGD("mSelectBounds.count=%d text=%d", mSelectBounds.count(),
+ mSelectText.count());
+ for (index = 0; index < mSelectBounds.count(); index++)
+ sortedBounds.append(&mSelectBounds[index]);
+ std::sort(sortedBounds.begin(), sortedBounds.end(), compareBounds);
+ int lastEnd = -1;
+ for (index = 0; index < mSelectBounds.count(); index++) {
+ if (sortedBounds[index]->isEmpty())
+ continue;
+ int order = sortedBounds[index] - &mSelectBounds[0];
+ int start = order > 0 ? mSelectCount[order - 1] : 0;
+ int end = mSelectCount[order];
+ DBG_NAV_LOGD("order=%d start=%d end=%d top=%d", order, start, end,
+ mSelectBounds[order].fTop);
+ int count = temp.count();
+ if (count > 0 && temp[count - 1] != '\n' && start != lastEnd) {
+ // always separate paragraphs when original text is out of order
+ DBG_NAV_LOG("write new line");
+ *temp.append() = '\n';
+ *temp.append() = '\n';
+ }
+ temp.append(end - start, &mSelectText[start]);
+ lastEnd = end;
+ }
+ mSelectText.swap(temp);
}
virtual bool onIRectGlyph(const SkIRect& rect,
@@ -217,64 +779,85 @@ public:
{
SkIRect full;
full.set(rect.fLeft, top(), rect.fRight, bottom());
- if (mSelectRegion.contains(full)) {
- if (!mSkipFirstSpace && (mLastUni < HYPHEN || mLastUni > HORZ_BAR)
- && mLastUni != HYPHEN_MINUS
- && (mLastGlyph.fLSB.fY != rec.fLSB.fY // new baseline
- || mLastGlyph.fLSB.fX > rec.fLSB.fX // glyphs are LTR
- || mLastGlyph.fRSB.fX + mMinSpaceWidth < rec.fLSB.fX)) {
- DBG_NAV_LOGD("TextExtractor append space"
- " mLast=(%d,%d,r=%d,b=%d) mLastGlyph=((%g,%g),(%g,%g),%d)"
- " full=(%d,%d,r=%d,b=%d) rec=((%g,%g),(%g,%g),%d)"
- " mMinSpaceWidth=%g",
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom,
- SkFixedToScalar(mLastGlyph.fLSB.fX),
- SkFixedToScalar(mLastGlyph.fLSB.fY),
- SkFixedToScalar(mLastGlyph.fRSB.fX),
- SkFixedToScalar(mLastGlyph.fRSB.fY), mLastGlyph.fGlyphID,
- full.fLeft, full.fTop, full.fRight, full.fBottom,
- SkFixedToScalar(rec.fLSB.fX),
- SkFixedToScalar(rec.fLSB.fY),
- SkFixedToScalar(rec.fRSB.fX),
- SkFixedToScalar(rec.fRSB.fY), rec.fGlyphID,
- SkFixedToScalar(mMinSpaceWidth));
- *mSelectText.append() = ' ';
- } else
- mSkipFirstSpace = false;
- DBG_NAV_LOGD("TextExtractor [%02x] append full=(%d,%d,r=%d,b=%d)",
- rec.fGlyphID, full.fLeft, full.fTop, full.fRight, full.fBottom);
- SkPaint utfPaint = *mPaint;
- utfPaint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
- utfPaint.glyphsToUnichars(&rec.fGlyphID, 1, &mLastUni);
- if (mLastUni) {
- uint16_t chars[2];
- size_t count = SkUTF16_FromUnichar(mLastUni, chars);
- *mSelectText.append() = chars[0];
- if (count == 2)
- *mSelectText.append() = chars[1];
+ int fullBase = base();
+ if (mFlipped) {
+ if (fullBase < mStart.fTop || fullBase > mEnd.fBottom
+ || (baseLinesAgree(mStart, mStartBase, full, fullBase)
+ && full.fLeft < mStart.fLeft)
+ || (baseLinesAgree(mEnd, mEndBase, full, fullBase)
+ && full.fRight > mEnd.fRight)) {
+ mSkipFirstSpace = true;
+ return false;
+ }
+ if (baseLinesAgree(mLast, mLastBase, full, fullBase)
+ && (full.fLeft - mLast.fRight < minSpaceWidth() * 3
+ || (SkIRect::Intersects(full, mSelectRect)
+ && SkIRect::Intersects(mLast, mSelectRect)))) {
+ mLast.join(full);
+ addCharacter(rec);
+ return false;
}
+ if (VERBOSE_LOGGING) DBG_NAV_LOGD("baseLinesAgree=%s"
+ " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
+ " full=(%d,%d,r=%d,b=%d) fullBase=%d"
+ " mSelectRect=(%d,%d,r=%d,b=%d)",
+ baseLinesAgree(mLast, mLastBase, full, fullBase) ? "true" : "false",
+ mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
+ full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
+ mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom);
+ *mSelectBounds.append() = SkIRect::Intersects(mLast, mSelectRect)
+ ? mLast : mEmpty;
+ *mSelectCount.append() = mSelectText.count();
+ addCharacter(rec);
mLast = full;
- mLastGlyph = rec;
- } else {
- mSkipFirstSpace = true;
- DBG_NAV_LOGD("TextExtractor [%02x] skip full=(%d,%d,r=%d,b=%d)",
- rec.fGlyphID, full.fLeft, full.fTop, full.fRight, full.fBottom);
+ mLastBase = fullBase;
+ return false;
}
+ if (full == mStart)
+ mRecord = true;
+ if (mRecord)
+ addCharacter(rec);
+ else
+ mSkipFirstSpace = true;
+ if (full == mEnd)
+ mRecord = false;
return false;
}
WebCore::String text() {
+ if (mFlipped)
+ finish();
+ // the text has been copied in visual order. Reverse as needed if
+ // result contains right-to-left characters.
+ const uint16_t* start = mSelectText.begin();
+ const uint16_t* end = mSelectText.end();
+ while (start < end) {
+ SkUnichar ch = SkUTF16_NextUnichar(&start);
+ WTF::Unicode::Direction charDirection = WTF::Unicode::direction(ch);
+ if (WTF::Unicode::RightToLeftArabic == charDirection
+ || WTF::Unicode::RightToLeft == charDirection) {
+ WebCore::ReverseBidi(mSelectText.begin(), mSelectText.count());
+ break;
+ }
+ }
return WebCore::String(mSelectText.begin(), mSelectText.count());
}
protected:
- const SkRegion& mSelectRegion;
- SkTDArray<uint16_t> mSelectText;
+ SkIRect mEmpty;
+ SkIRect mEnd;
+ int mEndBase;
+ bool mFlipped;
SkIRect mLast;
- SkBounder::GlyphRec mLastGlyph;
- SkUnichar mLastUni;
- SkFixed mMinSpaceWidth;
+ int mLastBase;
+ bool mRecord;
+ SkTDArray<SkIRect> mSelectBounds;
+ SkTDArray<int> mSelectCount;
+ SkIRect mSelectRect;
+ SkTDArray<uint16_t> mSelectText;
bool mSkipFirstSpace;
+ SkIRect mStart;
+ int mStartBase;
private:
typedef CommonCheck INHERITED;
};
@@ -282,7 +865,7 @@ private:
class TextCanvas : public SkCanvas {
public:
- TextCanvas(CommonCheck* bounder, const SkPicture& picture, const SkIRect& area)
+ TextCanvas(CommonCheck* bounder, const SkIRect& area)
: mBounder(*bounder) {
setBounder(bounder);
SkBitmap bitmap;
@@ -340,49 +923,201 @@ public:
CommonCheck& mBounder;
};
-void CopyPaste::buildSelection(const SkPicture& picture, const SkIRect& area,
- const SkIRect& selStart, const SkIRect& selEnd, SkRegion* region) {
+static bool buildSelection(const SkPicture& picture, const SkIRect& area,
+ const SkIRect& selStart, int startBase,
+ const SkIRect& selEnd, int endBase, SkRegion* region)
+{
DBG_NAV_LOGD("area=(%d, %d, %d, %d) selStart=(%d, %d, %d, %d)"
- " selEnd=(%d, %d, %d, %d)",
+ " selEnd=(%d, %d, %d, %d)",
area.fLeft, area.fTop, area.fRight, area.fBottom,
selStart.fLeft, selStart.fTop, selStart.fRight, selStart.fBottom,
selEnd.fLeft, selEnd.fTop, selEnd.fRight, selEnd.fBottom);
- MultilineBuilder builder(selStart, selEnd, area.fLeft, area.fTop, region);
- TextCanvas checker(&builder, picture, area);
+ MultilineBuilder builder(selStart, startBase, selEnd, endBase, area, region);
+ TextCanvas checker(&builder, area);
checker.drawPicture(const_cast<SkPicture&>(picture));
+ bool flipped = builder.flipped();
+ if (flipped) {
+ TextCanvas checker(&builder, area);
+ checker.drawPicture(const_cast<SkPicture&>(picture));
+ }
+ builder.finish();
region->translate(area.fLeft, area.fTop);
+ return flipped;
}
-SkIRect CopyPaste::findClosest(const SkPicture& picture, const SkIRect& area,
- int x, int y) {
- FirstCheck _check(x - area.fLeft, y - area.fTop);
- DBG_NAV_LOGD("area=(%d, %d, %d, %d) x=%d y=%d", area.fLeft, area.fTop,
- area.fRight, area.fBottom, x, y);
- TextCanvas checker(&_check, picture, area);
+static SkIRect findClosest(FirstCheck& _check, const SkPicture& picture,
+ const SkIRect& area, int* base)
+{
+ DBG_NAV_LOGD("area=(%d, %d, %d, %d)", area.fLeft, area.fTop,
+ area.fRight, area.fBottom);
+ TextCanvas checker(&_check, area);
checker.drawPicture(const_cast<SkPicture&>(picture));
- _check.offsetBounds(area.fLeft, area.fTop);
- return _check.bestBounds();
+ _check.finishGlyph();
+ return _check.adjustedBounds(area, base);
}
-WebCore::String CopyPaste::text(const SkPicture& picture, const SkIRect& area,
- const SkRegion& region) {
- SkRegion copy = region;
- copy.translate(-area.fLeft, -area.fTop);
- const SkIRect& bounds = copy.getBounds();
- DBG_NAV_LOGD("area=(%d, %d, %d, %d) region=(%d, %d, %d, %d)",
- area.fLeft, area.fTop, area.fRight, area.fBottom,
- bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
- TextExtractor extractor(copy);
- TextCanvas checker(&extractor, picture, area);
+static SkIRect findEdge(const SkPicture& picture, const SkIRect& area,
+ int x, int y, bool left, int* base)
+{
+ SkIRect result;
+ result.setEmpty();
+ FirstCheck center(x, y, area);
+ center.setRecordGlyph();
+ int closestBase;
+ SkIRect closest = findClosest(center, picture, area, &closestBase);
+ closest.inset(-TOUCH_SLOP, -TOUCH_SLOP);
+ if (!closest.contains(x, y)) {
+ DBG_NAV_LOGD("closest=(%d, %d, %d, %d) area=(%d, %d, %d, %d) x/y=%d,%d",
+ closest.fLeft, closest.fTop, closest.fRight, closest.fBottom,
+ area.fLeft, area.fTop, area.fRight, area.fBottom, x, y);
+ return result;
+ }
+ EdgeCheck edge(x, y, area, center, left);
+ do { // detect left or right until there's a gap
+ DBG_NAV_LOGD("edge=%p picture=%p area=%d,%d,%d,%d",
+ &edge, &picture, area.fLeft, area.fTop, area.fRight, area.fBottom);
+ TextCanvas checker(&edge, area);
+ checker.drawPicture(const_cast<SkPicture&>(picture));
+ edge.finishGlyph();
+ if (!edge.adjacent()) {
+ DBG_NAV_LOG("adjacent break");
+ break;
+ }
+ int nextBase;
+ const SkIRect& next = edge.bestBounds(&nextBase);
+ if (next.isEmpty()) {
+ DBG_NAV_LOG("empty");
+ break;
+ }
+ if (result == next) {
+ DBG_NAV_LOG("result == next");
+ break;
+ }
+ *base = nextBase;
+ result = next;
+ edge.shiftStart(result);
+ } while (true);
+ if (!result.isEmpty()) {
+ *base += area.fTop;
+ result.offset(area.fLeft, area.fTop);
+ }
+ return result;
+}
+
+static SkIRect findFirst(const SkPicture& picture, int* base)
+{
+ FindFirst finder(picture.width(), picture.height());
+ SkIRect area;
+ area.set(0, 0, picture.width(), picture.height());
+ TextCanvas checker(&finder, area);
+ checker.drawPicture(const_cast<SkPicture&>(picture));
+ return finder.bestBounds(base);
+}
+
+static SkIRect findLast(const SkPicture& picture, int* base)
+{
+ FindLast finder(picture.width(), picture.height());
+ SkIRect area;
+ area.set(0, 0, picture.width(), picture.height());
+ TextCanvas checker(&finder, area);
+ checker.drawPicture(const_cast<SkPicture&>(picture));
+ return finder.bestBounds(base);
+}
+
+static SkIRect findLeft(const SkPicture& picture, const SkIRect& area,
+ int x, int y, int* base)
+{
+ return findEdge(picture, area, x, y, true, base);
+}
+
+static SkIRect findRight(const SkPicture& picture, const SkIRect& area,
+ int x, int y, int* base)
+{
+ return findEdge(picture, area, x, y, false, base);
+}
+
+static WebCore::String text(const SkPicture& picture, const SkIRect& area,
+ const SkIRect& start, int startBase, const SkIRect& end,
+ int endBase, bool flipped)
+{
+ TextExtractor extractor(start, startBase, end, endBase, area, flipped);
+ TextCanvas checker(&extractor, area);
checker.drawPicture(const_cast<SkPicture&>(picture));
return extractor.text();
}
+#define CONTROL_OFFSET 3
+#define CONTROL_NOTCH 9
+#define CONTROL_HEIGHT 18
+#define CONTROL_WIDTH 12
+#define STROKE_WIDTH 0.4f
+#define SLOP 20
+
+SelectText::SelectText()
+{
+ reset();
+ SkScalar innerW = CONTROL_WIDTH - STROKE_WIDTH;
+ SkScalar innerH = CONTROL_HEIGHT - STROKE_WIDTH;
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStrokeWidth(STROKE_WIDTH);
+
+ SkPath startPath;
+ startPath.moveTo(-CONTROL_WIDTH, CONTROL_NOTCH);
+ startPath.lineTo(-CONTROL_WIDTH, CONTROL_HEIGHT);
+ startPath.lineTo(0, CONTROL_HEIGHT);
+ startPath.lineTo(0, CONTROL_OFFSET);
+ startPath.close();
+
+ SkCanvas* canvas = m_startControl.beginRecording(CONTROL_WIDTH, CONTROL_HEIGHT);
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(0xD077A14B);
+ canvas->drawPath(startPath, paint);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(0x40000000);
+ canvas->drawLine(-innerW, CONTROL_NOTCH, -innerW, innerH, paint);
+ canvas->drawLine(-innerW + STROKE_WIDTH, innerH, -STROKE_WIDTH, innerH, paint);
+ paint.setColor(0x40ffffff);
+ canvas->drawLine(0, CONTROL_OFFSET + STROKE_WIDTH,
+ -CONTROL_WIDTH, CONTROL_NOTCH + STROKE_WIDTH, paint);
+ canvas->drawLine(-STROKE_WIDTH, CONTROL_NOTCH + STROKE_WIDTH,
+ -STROKE_WIDTH, innerH, paint);
+ paint.setColor(0xffaaaaaa);
+ canvas->drawPath(startPath, paint);
+ m_startControl.endRecording();
+
+ SkPath endPath;
+ endPath.moveTo(0, CONTROL_OFFSET);
+ endPath.lineTo(0, CONTROL_HEIGHT);
+ endPath.lineTo(CONTROL_WIDTH, CONTROL_HEIGHT);
+ endPath.lineTo(CONTROL_WIDTH, CONTROL_NOTCH);
+ endPath.close();
+
+ canvas = m_endControl.beginRecording(CONTROL_WIDTH, CONTROL_HEIGHT);
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(0xD077A14B);
+ canvas->drawPath(endPath, paint);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(0x40000000);
+ canvas->drawLine(STROKE_WIDTH, CONTROL_OFFSET + STROKE_WIDTH,
+ STROKE_WIDTH, innerH, paint);
+ canvas->drawLine(STROKE_WIDTH + STROKE_WIDTH, innerH, innerW, innerH, paint);
+ paint.setColor(0x40ffffff);
+ canvas->drawLine(0, CONTROL_OFFSET + STROKE_WIDTH,
+ CONTROL_WIDTH, CONTROL_NOTCH + STROKE_WIDTH, paint);
+ canvas->drawLine(STROKE_WIDTH, CONTROL_NOTCH + STROKE_WIDTH,
+ STROKE_WIDTH, innerH, paint);
+ paint.setColor(0xffaaaaaa);
+ canvas->drawPath(endPath, paint);
+ m_endControl.endRecording();
+}
+
void SelectText::draw(SkCanvas* canvas, LayerAndroid* layer)
{
- if (layer->picture() != m_picture)
- return;
- if (m_drawRegion)
+ // FIXME: layer may not own the original selected picture
+ m_picture = layer->picture();
+ DBG_NAV_LOGD("m_extendSelection=%d m_drawPointer=%d", m_extendSelection, m_drawPointer);
+ if (m_extendSelection)
drawSelectionRegion(canvas);
if (m_drawPointer)
drawSelectionPointer(canvas);
@@ -406,7 +1141,7 @@ void SelectText::drawSelectionPointer(SkCanvas* canvas)
paint.setStrokeWidth(SK_Scalar1 * 2);
int sc = canvas->save();
canvas->scale(m_inverseScale, m_inverseScale);
- canvas->translate(SkIntToScalar(m_selectX), SkIntToScalar(m_selectY));
+ canvas->translate(m_selectX, m_selectY);
canvas->drawPath(path, paint);
if (!m_extendSelection) {
paint.setStyle(SkPaint::kFill_Style);
@@ -424,19 +1159,92 @@ void SelectText::drawSelectionRegion(SkCanvas* canvas)
return;
SkIRect ivisBounds;
visBounds.round(&ivisBounds);
- CopyPaste::buildSelection(*m_picture, ivisBounds, m_selStart, m_selEnd,
- &m_selRegion);
+ ivisBounds.join(m_selStart);
+ ivisBounds.join(m_selEnd);
+ DBG_NAV_LOGD("m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)",
+ m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
+ m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
+ m_flipped = buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
+ m_selEnd, m_endBase, &m_selRegion);
SkPath path;
m_selRegion.getBoundaryPath(&path);
+ path.setFillType(SkPath::kEvenOdd_FillType);
+
SkPaint paint;
paint.setAntiAlias(true);
- paint.setColor(SkColorSetARGB(0x40, 255, 51, 204));
+ paint.setColor(SkColorSetARGB(0x80, 151, 200, 73));
canvas->drawPath(path, paint);
+ // experiment to draw touchable controls that resize the selection
+ canvas->save();
+ canvas->translate(m_selStart.fLeft, m_selStart.fBottom);
+ canvas->drawPicture(m_startControl);
+ canvas->restore();
+ canvas->save();
+ canvas->translate(m_selEnd.fRight, m_selEnd.fBottom);
+ canvas->drawPicture(m_endControl);
+ canvas->restore();
+}
+
+void SelectText::extendSelection(const SkPicture* picture, int x, int y)
+{
+ SkIRect clipRect = m_visibleRect;
+ int base;
+ if (m_startSelection) {
+ if (!clipRect.contains(x, y)
+ || !clipRect.contains(m_original.fX, m_original.fY)) {
+ clipRect.set(m_original.fX, m_original.fY, x, y);
+ clipRect.sort();
+ clipRect.inset(-m_visibleRect.width(), -m_visibleRect.height());
+ }
+ DBG_NAV_LOGD("selStart clip=(%d,%d,%d,%d)", clipRect.fLeft,
+ clipRect.fTop, clipRect.fRight, clipRect.fBottom);
+ m_picture = picture;
+ FirstCheck center(m_original.fX, m_original.fY, clipRect);
+ m_selStart = m_selEnd = findClosest(center, *picture, clipRect, &base);
+ m_startBase = m_endBase = base;
+ m_startSelection = false;
+ m_extendSelection = true;
+ m_original.fX = m_original.fY = 0;
+ } else if (picture != m_picture)
+ return;
+ x -= m_original.fX;
+ y -= m_original.fY;
+ if (!clipRect.contains(x, y) || !clipRect.contains(m_selStart)) {
+ clipRect.set(m_selStart.fLeft, m_selStart.fTop, x, y);
+ clipRect.sort();
+ clipRect.inset(-m_visibleRect.width(), -m_visibleRect.height());
+ }
+ DBG_NAV_LOGD("extend clip=(%d,%d,%d,%d)", clipRect.fLeft,
+ clipRect.fTop, clipRect.fRight, clipRect.fBottom);
+ FirstCheck extension(x, y, clipRect);
+ SkIRect found = findClosest(extension, *picture, clipRect, &base);
+ DBG_NAV_LOGD("pic=%p x=%d y=%d m_startSelection=%s %s=(%d, %d, %d, %d)"
+ " m_extendSelection=%s",
+ picture, x, y, m_startSelection ? "true" : "false",
+ m_hitTopLeft ? "m_selStart" : "m_selEnd",
+ found.fLeft, found.fTop, found.fRight, found.fBottom,
+ m_extendSelection ? "true" : "false");
+ if (m_hitTopLeft) {
+ m_startBase = base;
+ m_selStart = found;
+ } else {
+ m_endBase = base;
+ m_selEnd = found;
+ }
+ swapAsNeeded();
}
const String SelectText::getSelection()
{
- String result = CopyPaste::text(*m_picture, m_visibleRect, m_selRegion);
+ SkIRect clipRect;
+ clipRect.set(0, 0, m_picture->width(), m_picture->height());
+ String result = text(*m_picture, clipRect, m_selStart, m_startBase,
+ m_selEnd, m_endBase, m_flipped);
+ DBG_NAV_LOGD("clip=(%d,%d,%d,%d)"
+ " m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)",
+ clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom,
+ m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
+ m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
DBG_NAV_LOGD("text=%s", result.latin1().data()); // uses CString
return result;
}
@@ -447,35 +1255,173 @@ void SelectText::getSelectionArrow(SkPath* path)
0, 14, 3, 11, 5, 15, 9, 15, 7, 11, 11, 11
};
for (unsigned index = 0; index < sizeof(arrow)/sizeof(arrow[0]); index += 2)
- path->lineTo(SkIntToScalar(arrow[index]), SkIntToScalar(arrow[index + 1]));
+ path->lineTo(arrow[index], arrow[index + 1]);
path->close();
}
void SelectText::getSelectionCaret(SkPath* path)
{
- SkScalar height = SkIntToScalar(m_selStart.fBottom - m_selStart.fTop);
+ SkScalar height = m_selStart.fBottom - m_selStart.fTop;
SkScalar dist = height / 4;
path->moveTo(0, -height / 2);
path->rLineTo(0, height);
path->rLineTo(-dist, dist);
- path->rMoveTo(0, -SK_Scalar1/2);
+ path->rMoveTo(0, -0.5f);
path->rLineTo(dist * 2, 0);
- path->rMoveTo(0, SK_Scalar1/2);
+ path->rMoveTo(0, 0.5f);
path->rLineTo(-dist, -dist);
}
-void SelectText::moveSelection(const SkPicture* picture, int x, int y,
- bool extendSelection)
+bool SelectText::hitCorner(int cx, int cy, int x, int y) const
+{
+ SkIRect test;
+ test.set(cx, cy, cx, cy);
+ test.inset(-SLOP, -SLOP);
+ return test.contains(x, y);
+}
+
+bool SelectText::hitSelection(int x, int y) const
+{
+ int left = m_selStart.fLeft - CONTROL_WIDTH / 2;
+ int top = m_selStart.fBottom + CONTROL_HEIGHT / 2;
+ if (hitCorner(left, top, x, y))
+ return true;
+ int right = m_selEnd.fRight + CONTROL_WIDTH / 2;
+ int bottom = m_selEnd.fBottom + CONTROL_HEIGHT / 2;
+ if (hitCorner(right, bottom, x, y))
+ return true;
+ return m_selRegion.contains(x, y);
+}
+
+void SelectText::moveSelection(const SkPicture* picture, int x, int y)
{
- if (!extendSelection)
+ SkIRect clipRect = m_visibleRect;
+ clipRect.join(m_selStart);
+ clipRect.join(m_selEnd);
+ if (!m_extendSelection)
m_picture = picture;
- m_selEnd = CopyPaste::findClosest(*picture, m_visibleRect, x, y);
- if (!extendSelection)
- m_selStart = m_selEnd;
+ FirstCheck center(x, y, clipRect);
+ int base;
+ SkIRect found = findClosest(center, *picture, clipRect, &base);
+ if (m_hitTopLeft || !m_extendSelection) {
+ m_startBase = base;
+ m_selStart = found;
+ }
+ if (!m_hitTopLeft || !m_extendSelection) {
+ m_endBase = base;
+ m_selEnd = found;
+ }
+ swapAsNeeded();
DBG_NAV_LOGD("x=%d y=%d extendSelection=%s m_selStart=(%d, %d, %d, %d)"
- " m_selEnd=(%d, %d, %d, %d)", x, y, extendSelection ? "true" : "false",
+ " m_selEnd=(%d, %d, %d, %d)", x, y, m_extendSelection ? "true" : "false",
+ m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
+ m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
+}
+
+void SelectText::reset()
+{
+ DBG_NAV_LOG("m_extendSelection=false");
+ m_selStart.setEmpty();
+ m_selEnd.setEmpty();
+ m_extendSelection = false;
+ m_startSelection = false;
+}
+
+void SelectText::selectAll(const SkPicture* picture)
+{
+ m_selStart = findFirst(*picture, &m_startBase);
+ m_selEnd = findLast(*picture, &m_endBase);
+ m_extendSelection = true;
+}
+
+int SelectText::selectionX() const
+{
+ return m_hitTopLeft ? m_selStart.fLeft : m_selEnd.fRight;
+}
+
+int SelectText::selectionY() const
+{
+ const SkIRect& rect = m_hitTopLeft ? m_selStart : m_selEnd;
+ return (rect.fTop + rect.fBottom) >> 1;
+}
+
+bool SelectText::startSelection(int x, int y)
+{
+ m_original.fX = x;
+ m_original.fY = y;
+ if (m_selStart.isEmpty()) {
+ DBG_NAV_LOGD("empty start x=%d y=%d", x, y);
+ m_startSelection = true;
+ return true;
+ }
+ int left = m_selStart.fLeft - CONTROL_WIDTH / 2;
+ int top = m_selStart.fBottom + CONTROL_HEIGHT / 2;
+ m_hitTopLeft = hitCorner(left, top, x, y);
+ int right = m_selEnd.fRight + CONTROL_WIDTH / 2;
+ int bottom = m_selEnd.fBottom + CONTROL_HEIGHT / 2;
+ bool hitBottomRight = hitCorner(right, bottom, x, y);
+ DBG_NAV_LOGD("left=%d top=%d right=%d bottom=%d x=%d y=%d", left, top,
+ right, bottom, x, y);
+ if (m_hitTopLeft && (!hitBottomRight || y - top < bottom - y)) {
+ DBG_NAV_LOG("hit top left");
+ m_original.fX -= left;
+ m_original.fY -= (m_selStart.fTop + m_selStart.fBottom) >> 1;
+ } else if (hitBottomRight) {
+ DBG_NAV_LOG("hit bottom right");
+ m_original.fX -= right;
+ m_original.fY -= (m_selEnd.fTop + m_selEnd.fBottom) >> 1;
+ }
+ return m_hitTopLeft || hitBottomRight;
+}
+
+/* selects the word at (x, y)
+* a word is normally delimited by spaces
+* a string of digits (even with inside spaces) is a word (for phone numbers)
+* FIXME: digit find isn't implemented yet
+* returns true if a word was selected
+*/
+bool SelectText::wordSelection(const SkPicture* picture)
+{
+ int x = m_selStart.fLeft;
+ int y = (m_selStart.fTop + m_selStart.fBottom) >> 1;
+ SkIRect clipRect = m_visibleRect;
+ clipRect.fLeft -= m_visibleRect.width() >> 1;
+ int base;
+ SkIRect left = findLeft(*picture, clipRect, x, y, &base);
+ if (!left.isEmpty()) {
+ m_startBase = base;
+ m_selStart = left;
+ }
+ x = m_selEnd.fRight;
+ y = (m_selEnd.fTop + m_selEnd.fBottom) >> 1;
+ clipRect = m_visibleRect;
+ clipRect.fRight += m_visibleRect.width() >> 1;
+ SkIRect right = findRight(*picture, clipRect, x, y, &base);
+ if (!right.isEmpty()) {
+ m_endBase = base;
+ m_selEnd = right;
+ }
+ DBG_NAV_LOGD("m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)",
m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
+ if (!left.isEmpty() || !right.isEmpty()) {
+ m_extendSelection = true;
+ return true;
+ }
+ return false;
+}
+
+void SelectText::swapAsNeeded()
+{
+ if (m_selStart.fTop >= m_selEnd.fBottom
+ || (m_selStart.fBottom > m_selEnd.fTop
+ && m_selStart.fRight > m_selEnd.fLeft))
+ {
+ SkTSwap(m_startBase, m_endBase);
+ SkTSwap(m_selStart, m_selEnd);
+ m_hitTopLeft ^= true;
+ DBG_NAV_LOGD("m_hitTopLeft=%s", m_hitTopLeft ? "true" : "false");
+ }
}
}
diff --git a/WebKit/android/nav/SelectText.h b/WebKit/android/nav/SelectText.h
index 8174046..404e9e7 100644
--- a/WebKit/android/nav/SelectText.h
+++ b/WebKit/android/nav/SelectText.h
@@ -29,6 +29,7 @@
#include "DrawExtra.h"
#include "IntRect.h"
#include "PlatformString.h"
+#include "SkPath.h"
class SkPicture;
struct SkIRect;
@@ -38,47 +39,57 @@ namespace android {
class CachedRoot;
-class CopyPaste {
-public:
- static void buildSelection(const SkPicture& , const SkIRect& area,
- const SkIRect& selStart, const SkIRect& selEnd, SkRegion* region);
- static SkIRect findClosest(const SkPicture& , const SkIRect& area,
- int x, int y);
- static String text(const SkPicture& , const SkIRect& area,
- const SkRegion& );
-};
-
class SelectText : public DrawExtra {
public:
- SelectText() {
- m_selStart.setEmpty();
- m_selEnd.setEmpty();
- }
+ SelectText();
virtual void draw(SkCanvas* , LayerAndroid* );
+ void extendSelection(const SkPicture* , int x, int y);
const String getSelection();
- void moveSelection(const SkPicture* , int x, int y, bool extendSelection);
+ bool hitSelection(int x, int y) const;
+ void moveSelection(const SkPicture* , int x, int y);
+ void reset();
+ void selectAll(const SkPicture* );
+ int selectionX() const;
+ int selectionY() const;
void setDrawPointer(bool drawPointer) { m_drawPointer = drawPointer; }
- void setDrawRegion(bool drawRegion) { m_drawRegion = drawRegion; }
+ void setExtendSelection(bool extend) { m_extendSelection = extend; }
void setVisibleRect(const IntRect& rect) { m_visibleRect = rect; }
+ bool startSelection(int x, int y);
+ bool wordSelection(const SkPicture* picture);
+public:
+ float m_inverseScale; // inverse scale, x, y used for drawing select path
+ int m_selectX;
+ int m_selectY;
private:
- friend class WebView;
void drawSelectionPointer(SkCanvas* );
void drawSelectionRegion(SkCanvas* );
static void getSelectionArrow(SkPath* );
void getSelectionCaret(SkPath* );
+ bool hitCorner(int cx, int cy, int x, int y) const;
+ void swapAsNeeded();
+ SkIPoint m_original; // computed start of extend selection
SkIRect m_selStart;
SkIRect m_selEnd;
- SkIRect m_visibleRect;
- SkRegion m_selRegion;
+ int m_startBase;
+ int m_endBase;
+ SkIRect m_visibleRect; // constrains picture computations to visible area
+ SkRegion m_selRegion; // computed from sel start, end
+ SkPicture m_startControl;
+ SkPicture m_endControl;
const SkPicture* m_picture;
- float m_inverseScale;
- int m_selectX;
- int m_selectY;
- bool m_drawRegion;
bool m_drawPointer;
- bool m_extendSelection;
+ bool m_extendSelection; // false when trackball is moving pointer
+ bool m_flipped;
+ bool m_hitTopLeft;
+ bool m_startSelection;
};
}
+namespace WebCore {
+
+void ReverseBidi(UChar* chars, int len);
+
+}
+
#endif
diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp
index 2ed6148..5154b42 100644
--- a/WebKit/android/nav/WebView.cpp
+++ b/WebKit/android/nav/WebView.cpp
@@ -30,10 +30,10 @@
#include "AndroidAnimation.h"
#include "AndroidLog.h"
#include "AtomicString.h"
+#include "BaseLayerAndroid.h"
#include "CachedFrame.h"
#include "CachedNode.h"
#include "CachedRoot.h"
-#include "CString.h"
#include "DrawExtra.h"
#include "FindCanvas.h"
#include "Frame.h"
@@ -68,6 +68,7 @@
#include <JNIHelp.h>
#include <jni.h>
#include <ui/KeycodeLabels.h>
+#include <wtf/text/CString.h>
namespace android {
@@ -177,7 +178,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) :
m_lastDx = 0;
m_lastDxTime = 0;
m_ringAnimationEnd = 0;
- m_rootLayer = 0;
+ m_baseLayer = 0;
}
~WebView()
@@ -190,7 +191,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) :
}
delete m_frameCacheUI;
delete m_navPictureUI;
- delete m_rootLayer;
+ delete m_baseLayer;
}
WebViewCore* getWebViewCore() const {
@@ -303,10 +304,11 @@ void scrollRectOnScreen(const IntRect& rect)
SkRect visible;
calcOurContentVisibleRect(&visible);
#if USE(ACCELERATED_COMPOSITING)
- if (m_rootLayer) {
- m_rootLayer->updateFixedLayersPositions(visible);
- m_rootLayer->updatePositions();
- visible = m_rootLayer->subtractLayers(visible);
+ LayerAndroid* root = compositeRoot();
+ if (root) {
+ root->updateFixedLayersPositions(visible);
+ root->updatePositions();
+ visible = root->subtractLayers(visible);
}
#endif
int dx = 0;
@@ -394,14 +396,30 @@ void drawCursorPostamble()
}
}
-void drawExtras(SkCanvas* canvas, int extras)
+PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split)
{
+ PictureSet* ret = 0;
+ if (!m_baseLayer) {
+ canvas->drawColor(bgColor);
+ return ret;
+ }
+
+ // draw the content of the base layer first
+ PictureSet* content = m_baseLayer->content();
+ int sc = canvas->save(SkCanvas::kClip_SaveFlag);
+ canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(),
+ content->height()), SkRegion::kDifference_Op);
+ canvas->drawColor(bgColor);
+ canvas->restoreToCount(sc);
+ if (content->draw(canvas))
+ ret = split ? new PictureSet(*content) : 0;
+
CachedRoot* root = getFrameCache(AllowNewer);
if (!root) {
DBG_NAV_LOG("!root");
if (extras == DrawExtrasCursorRing)
resetCursorRing();
- return;
+ return ret;
}
LayerAndroid mainPicture(m_navPictureUI);
DrawExtra* extra = 0;
@@ -425,22 +443,24 @@ void drawExtras(SkCanvas* canvas, int extras)
if (extra)
extra->draw(canvas, &mainPicture);
#if USE(ACCELERATED_COMPOSITING)
- if (!m_rootLayer)
- return;
- m_rootLayer->setExtra(extra);
+ LayerAndroid* compositeLayer = compositeRoot();
+ if (!compositeLayer)
+ return ret;
+ compositeLayer->setExtra(extra);
SkRect visible;
calcOurContentVisibleRect(&visible);
// call this to be sure we've adjusted for any scrolling or animations
// before we actually draw
- m_rootLayer->updateFixedLayersPositions(visible);
- m_rootLayer->updatePositions();
- // We have to set the canvas' matrix on the root layer
+ compositeLayer->updateFixedLayersPositions(visible);
+ compositeLayer->updatePositions();
+ // We have to set the canvas' matrix on the base layer
// (to have fixed layers work as intended)
SkAutoCanvasRestore restore(canvas, true);
- m_rootLayer->setMatrix(canvas->getTotalMatrix());
+ m_baseLayer->setMatrix(canvas->getTotalMatrix());
canvas->resetMatrix();
- m_rootLayer->draw(canvas);
+ m_baseLayer->draw(canvas);
#endif
+ return ret;
}
@@ -565,7 +585,7 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer)
m_viewImpl->m_navPictureKit = 0;
m_viewImpl->gFrameCacheMutex.unlock();
if (m_frameCacheUI)
- m_frameCacheUI->setRootLayer(m_rootLayer);
+ m_frameCacheUI->setRootLayer(compositeRoot());
#if USE(ACCELERATED_COMPOSITING)
if (layerId >= 0) {
SkRect visible;
@@ -892,7 +912,8 @@ bool motionUp(int x, int y, int slop)
viewInvalidate();
if (!result->isTextInput()) {
clearTextEntry();
- setFollowedLink(true);
+ if (!result->isSelect() && !result->isContentEditable())
+ setFollowedLink(true);
if (syntheticLink)
overrideUrlLoading(result->getExport());
}
@@ -946,7 +967,7 @@ String getSelection()
return m_selectText.getSelection();
}
-void moveSelection(int x, int y, bool extendSelection)
+void moveSelection(int x, int y)
{
const CachedRoot* root = getFrameCache(DontAllowNewer);
if (!root)
@@ -957,26 +978,81 @@ void moveSelection(int x, int y, bool extendSelection)
IntRect visibleRect;
getVisibleRect(&visibleRect);
m_selectText.setVisibleRect(visibleRect);
- m_selectText.moveSelection(picture, x, y, extendSelection);
+ m_selectText.moveSelection(picture, x, y);
+}
+
+void selectAll()
+{
+ const CachedRoot* root = getFrameCache(DontAllowNewer);
+ if (!root)
+ return;
+ SkPicture* picture = root->pictureAt(0, 0);
+ m_selectText.selectAll(picture);
+}
+
+int selectionX()
+{
+ return m_selectText.selectionX();
}
-void setSelectionPointer(bool set, float scale, int x, int y,
- bool extendSelection)
+int selectionY()
+{
+ return m_selectText.selectionY();
+}
+
+void resetSelection()
+{
+ m_selectText.reset();
+}
+
+bool startSelection(int x, int y)
+{
+ return m_selectText.startSelection(x, y);
+}
+
+bool wordSelection(int x, int y)
+{
+ startSelection(x, y);
+ if (!extendSelection(x, y))
+ return false;
+ m_selectText.setDrawPointer(false);
+ SkPicture* picture = getFrameCache(DontAllowNewer)->pictureAt(x, y);
+ return m_selectText.wordSelection(picture);
+}
+
+bool extendSelection(int x, int y)
+{
+ const CachedRoot* root = getFrameCache(DontAllowNewer);
+ if (!root)
+ return false;
+ SkPicture* picture = root->pictureAt(x, y);
+ IntRect visibleRect;
+ getVisibleRect(&visibleRect);
+ m_selectText.setVisibleRect(visibleRect);
+ m_selectText.extendSelection(picture, x, y);
+ return true;
+}
+
+bool hitSelection(int x, int y)
+{
+ return m_selectText.hitSelection(x, y);
+}
+
+void setExtendSelection()
+{
+ m_selectText.setExtendSelection(true);
+}
+
+void setSelectionPointer(bool set, float scale, int x, int y)
{
m_selectText.setDrawPointer(set);
if (!set)
return;
- m_selectText.m_extendSelection = extendSelection;
m_selectText.m_inverseScale = scale;
m_selectText.m_selectX = x;
m_selectText.m_selectY = y;
}
-void setSelectionRegion(bool set)
-{
- m_selectText.setDrawRegion(set);
-}
-
void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
{
DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr);
@@ -1035,6 +1111,11 @@ void setMatches(WTF::Vector<MatchInfo>* matches)
viewInvalidate();
}
+int currentMatchIndex()
+{
+ return m_findOnPage.currentMatchIndex();
+}
+
bool scrollBy(int dx, int dy)
{
LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
@@ -1109,20 +1190,49 @@ int moveGeneration()
return m_viewImpl->m_moveGeneration;
}
-LayerAndroid* rootLayer() const
+LayerAndroid* compositeRoot() const
{
- return m_rootLayer;
+ LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1,
+ "base layer can't have more than one child %s", __FUNCTION__);
+ if (m_baseLayer && m_baseLayer->countChildren() == 1)
+ return static_cast<LayerAndroid*>(m_baseLayer->getChild(0));
+ else
+ return 0;
}
-void setRootLayer(LayerAndroid* layer)
+void setBaseLayer(BaseLayerAndroid* layer)
{
- delete m_rootLayer;
- m_rootLayer = layer;
+ delete m_baseLayer;
+ m_baseLayer = layer;
CachedRoot* root = getFrameCache(DontAllowNewer);
if (!root)
return;
root->resetLayers();
- root->setRootLayer(m_rootLayer);
+ root->setRootLayer(compositeRoot());
+}
+
+void replaceBaseContent(PictureSet* set)
+{
+ if (!m_baseLayer)
+ return;
+ m_baseLayer->setContent(*set);
+ delete set;
+}
+
+void copyBaseContentToPicture(SkPicture* picture)
+{
+ if (!m_baseLayer)
+ return;
+ PictureSet* content = m_baseLayer->content();
+ content->draw(picture->beginRecording(content->width(), content->height(),
+ SkPicture::kUsePathBoundsForClip_RecordingFlag));
+ picture->endRecording();
+}
+
+bool hasContent() {
+ if (!m_baseLayer)
+ return false;
+ return !m_baseLayer->content()->isEmpty();
}
private: // local state for WebView
@@ -1139,7 +1249,7 @@ private: // local state for WebView
SelectText m_selectText;
FindOnPage m_findOnPage;
CursorRing m_ring;
- LayerAndroid* m_rootLayer;
+ BaseLayerAndroid* m_baseLayer;
}; // end of WebView class
/*
@@ -1272,6 +1382,19 @@ static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj)
return cursor ? frame->textInput(cursor) : 0;
}
+static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj)
+{
+ const CachedNode* focus = getFocusNode(env, obj);
+ if (!focus) return false;
+ // Plugins handle shift and arrows whether or not they have focus.
+ if (focus->isPlugin()) return true;
+ const CachedNode* cursor = getCursorNode(env, obj);
+ // ContentEditable nodes should only receive shift and arrows if they have
+ // both the cursor and the focus.
+ return cursor && cursor->nodePointer() == focus->nodePointer()
+ && cursor->isContentEditable();
+}
+
static jboolean nativeCursorMatchesFocus(JNIEnv *env, jobject obj)
{
const CachedNode* cursor = getCursorNode(env, obj);
@@ -1357,28 +1480,43 @@ static void nativeDebugDump(JNIEnv *env, jobject obj)
#endif
}
-static void nativeDrawExtras(JNIEnv *env, jobject obj, jobject canv, jint extras)
-{
+static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, jint color,
+ jint extras, jboolean split) {
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
- GET_NATIVE_VIEW(env, obj)->drawExtras(canvas, extras);
+ return reinterpret_cast<jint>(GET_NATIVE_VIEW(env, obj)->draw(canvas, color, extras, split));
}
static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj)
{
#if USE(ACCELERATED_COMPOSITING)
- const LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->rootLayer();
+ const LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
if (root)
return root->evaluateAnimations();
#endif
return false;
}
-static void nativeSetRootLayer(JNIEnv *env, jobject obj, jint layer)
+static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer)
{
-#if USE(ACCELERATED_COMPOSITING)
- LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
- GET_NATIVE_VIEW(env, obj)->setRootLayer(layerImpl);
-#endif
+ BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
+ GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl);
+}
+
+static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
+{
+ PictureSet* set = reinterpret_cast<PictureSet*>(content);
+ GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set);
+}
+
+static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
+{
+ SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
+ GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture);
+}
+
+static bool nativeHasContent(JNIEnv *env, jobject obj)
+{
+ return GET_NATIVE_VIEW(env, obj)->hasContent();
}
static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
@@ -1568,7 +1706,7 @@ static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect)
{
SkIRect irect = jrect_to_webrect(env, jrect);
#if USE(ACCELERATED_COMPOSITING)
- LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->rootLayer();
+ LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
if (root) {
SkRect rect;
rect.set(irect);
@@ -1644,9 +1782,12 @@ static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj)
static void nativeSetFollowedLink(JNIEnv *env, jobject obj, bool followed)
{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->setFollowedLink(followed);
+ const CachedNode* cursor = getCursorNode(env, obj);
+ if (cursor && !cursor->isSelect() && ! cursor->isContentEditable()) {
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ view->setFollowedLink(followed);
+ }
}
static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
@@ -1735,6 +1876,13 @@ static void nativeFindNext(JNIEnv *env, jobject obj, bool forward)
view->findNext(forward);
}
+static int nativeFindIndex(JNIEnv *env, jobject obj)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in nativeFindIndex");
+ return view->currentMatchIndex();
+}
+
static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
{
WebView* view = GET_NATIVE_VIEW(env, obj);
@@ -1805,11 +1953,39 @@ static int nativeMoveGeneration(JNIEnv *env, jobject obj)
return view->moveGeneration();
}
-static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y, bool ex)
+static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y)
{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->moveSelection(x, y, ex);
+ GET_NATIVE_VIEW(env, obj)->moveSelection(x, y);
+}
+
+static void nativeResetSelection(JNIEnv *env, jobject obj)
+{
+ return GET_NATIVE_VIEW(env, obj)->resetSelection();
+}
+
+static void nativeSelectAll(JNIEnv* env, jobject obj)
+{
+ GET_NATIVE_VIEW(env, obj)->selectAll();
+}
+
+static void nativeSetExtendSelection(JNIEnv *env, jobject obj)
+{
+ GET_NATIVE_VIEW(env, obj)->setExtendSelection();
+}
+
+static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y)
+{
+ return GET_NATIVE_VIEW(env, obj)->startSelection(x, y);
+}
+
+static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y)
+{
+ return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y);
+}
+
+static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y)
+{
+ GET_NATIVE_VIEW(env, obj)->extendSelection(x, y);
}
static jobject nativeGetSelection(JNIEnv *env, jobject obj)
@@ -1820,15 +1996,25 @@ static jobject nativeGetSelection(JNIEnv *env, jobject obj)
return env->NewString((jchar*)selection.characters(), selection.length());
}
-static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jboolean set,
- jfloat scale, jint x, jint y, bool ex)
+static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y)
{
- GET_NATIVE_VIEW(env, obj)->setSelectionPointer(set, scale, x, y, ex);
+ return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y);
}
-static void nativeSetSelectionRegion(JNIEnv *env, jobject obj, jboolean set)
+static jint nativeSelectionX(JNIEnv *env, jobject obj)
{
- GET_NATIVE_VIEW(env, obj)->setSelectionRegion(set);
+ return GET_NATIVE_VIEW(env, obj)->selectionX();
+}
+
+static jint nativeSelectionY(JNIEnv *env, jobject obj)
+{
+ return GET_NATIVE_VIEW(env, obj)->selectionY();
+}
+
+static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jboolean set,
+ jfloat scale, jint x, jint y)
+{
+ GET_NATIVE_VIEW(env, obj)->setSelectionPointer(set, scale, x, y);
}
#ifdef ANDROID_DUMP_DISPLAY_TREE
@@ -1859,26 +2045,13 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
SkDumpCanvas canvas(&dumper);
// this will playback the picture into the canvas, which will
// spew its contents to the dumper
- view->getWebViewCore()->drawContent(&canvas, 0);
-#if USE(ACCELERATED_COMPOSITING)
- if (true) {
- LayerAndroid* rootLayer = view->rootLayer();
- if (rootLayer) {
- // We have to set the canvas' matrix on the root layer
- // (to have fixed layers work as intended)
- SkAutoCanvasRestore restore(&canvas, true);
- rootLayer->setMatrix(canvas.getTotalMatrix());
- canvas.resetMatrix();
- rootLayer->draw(&canvas);
- }
- }
-#endif
+ view->draw(&canvas, 0, 0, false);
// we're done with the file now
fwrite("\n", 1, 1, file);
fclose(file);
}
#if USE(ACCELERATED_COMPOSITING)
- const LayerAndroid* rootLayer = view->rootLayer();
+ const LayerAndroid* rootLayer = view->compositeRoot();
if (rootLayer) {
FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
if (file) {
@@ -1907,6 +2080,8 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeCreate },
{ "nativeCursorFramePointer", "()I",
(void*) nativeCursorFramePointer },
+ { "nativePageShouldHandleShiftAndArrows", "()Z",
+ (void*) nativePageShouldHandleShiftAndArrows },
{ "nativeCursorMatchesFocus", "()Z",
(void*) nativeCursorMatchesFocus },
{ "nativeCursorNodeBounds", "()Landroid/graphics/Rect;",
@@ -1929,16 +2104,20 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeDebugDump },
{ "nativeDestroy", "()V",
(void*) nativeDestroy },
- { "nativeDrawExtras", "(Landroid/graphics/Canvas;I)V",
- (void*) nativeDrawExtras },
+ { "nativeDraw", "(Landroid/graphics/Canvas;IIZ)I",
+ (void*) nativeDraw },
{ "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
(void*) nativeDumpDisplayTree },
{ "nativeEvaluateLayersAnimations", "()Z",
(void*) nativeEvaluateLayersAnimations },
+ { "nativeExtendSelection", "(II)V",
+ (void*) nativeExtendSelection },
{ "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;)I",
(void*) nativeFindAll },
{ "nativeFindNext", "(Z)V",
(void*) nativeFindNext },
+ { "nativeFindIndex", "()I",
+ (void*) nativeFindIndex},
{ "nativeFocusCandidateFramePointer", "()I",
(void*) nativeFocusCandidateFramePointer },
{ "nativeFocusCandidateHasNextTextfield", "()Z",
@@ -1979,6 +2158,8 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeHasFocusNode },
{ "nativeHideCursor", "()V",
(void*) nativeHideCursor },
+ { "nativeHitSelection", "(II)Z",
+ (void*) nativeHitSelection },
{ "nativeImageURI", "(II)Ljava/lang/String;",
(void*) nativeImageURI },
{ "nativeInstrumentReport", "()V",
@@ -1991,14 +2172,24 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeMoveCursorToNextTextInput },
{ "nativeMoveGeneration", "()I",
(void*) nativeMoveGeneration },
- { "nativeMoveSelection", "(IIZ)V",
+ { "nativeMoveSelection", "(II)V",
(void*) nativeMoveSelection },
{ "nativePointInNavCache", "(III)Z",
(void*) nativePointInNavCache },
{ "nativeRecordButtons", "(ZZZ)V",
(void*) nativeRecordButtons },
+ { "nativeResetSelection", "()V",
+ (void*) nativeResetSelection },
+ { "nativeSelectAll", "()V",
+ (void*) nativeSelectAll },
{ "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
(void*) nativeSelectBestAt },
+ { "nativeSelectionX", "()I",
+ (void*) nativeSelectionX },
+ { "nativeSelectionY", "()I",
+ (void*) nativeSelectionY },
+ { "nativeSetExtendSelection", "()V",
+ (void*) nativeSetExtendSelection },
{ "nativeSetFindIsEmpty", "()V",
(void*) nativeSetFindIsEmpty },
{ "nativeSetFindIsUp", "(Z)V",
@@ -2007,18 +2198,26 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeSetFollowedLink },
{ "nativeSetHeightCanMeasure", "(Z)V",
(void*) nativeSetHeightCanMeasure },
- { "nativeSetRootLayer", "(I)V",
- (void*) nativeSetRootLayer },
- { "nativeSetSelectionPointer", "(ZFIIZ)V",
+ { "nativeSetBaseLayer", "(I)V",
+ (void*) nativeSetBaseLayer },
+ { "nativeReplaceBaseContent", "(I)V",
+ (void*) nativeReplaceBaseContent },
+ { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
+ (void*) nativeCopyBaseContentToPicture },
+ { "nativeHasContent", "()Z",
+ (void*) nativeHasContent },
+ { "nativeSetSelectionPointer", "(ZFII)V",
(void*) nativeSetSelectionPointer },
- { "nativeSetSelectionRegion", "(Z)V",
- (void*) nativeSetSelectionRegion },
+ { "nativeStartSelection", "(II)Z",
+ (void*) nativeStartSelection },
{ "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
(void*) nativeSubtractLayers },
{ "nativeTextGeneration", "()I",
(void*) nativeTextGeneration },
{ "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
(void*) nativeUpdateCachedTextfield },
+ { "nativeWordSelection", "(II)Z",
+ (void*) nativeWordSelection },
{ "nativeGetBlockLeftEdge", "(IIF)I",
(void*) nativeGetBlockLeftEdge },
};
diff --git a/WebKit/android/plugins/ANPSystemInterface.cpp b/WebKit/android/plugins/ANPSystemInterface.cpp
index 42ec9e4..34fe162 100644
--- a/WebKit/android/plugins/ANPSystemInterface.cpp
+++ b/WebKit/android/plugins/ANPSystemInterface.cpp
@@ -26,7 +26,7 @@
// must include config.h first for webkit to fiddle with new/delete
#include "config.h"
-#include "CString.h"
+#include "ANPSystem_npapi.h"
#include "JavaSharedClient.h"
#include "PluginClient.h"
#include "PluginPackage.h"
@@ -34,8 +34,7 @@
#include "PluginWidgetAndroid.h"
#include "SkString.h"
#include "WebViewCore.h"
-
-#include "ANPSystem_npapi.h"
+#include <wtf/text/CString.h>
static const char* gApplicationDataDir = NULL;
diff --git a/WebKit/android/plugins/PluginDebugAndroid.cpp b/WebKit/android/plugins/PluginDebugAndroid.cpp
index e13e928..0388d4b 100644
--- a/WebKit/android/plugins/PluginDebugAndroid.cpp
+++ b/WebKit/android/plugins/PluginDebugAndroid.cpp
@@ -60,7 +60,7 @@ void anp_logPlugin(const char format[], ...) {
va_end(args);
}
-void anp_logPluginEvent(void* npp, const ANPEvent* evt, int16 returnVal, int elapsedTime) {
+void anp_logPluginEvent(void* npp, const ANPEvent* evt, int16_t returnVal, int elapsedTime) {
switch(evt->eventType) {
diff --git a/WebKit/android/plugins/PluginTimer.cpp b/WebKit/android/plugins/PluginTimer.cpp
index a813d25..ae7cb84 100644
--- a/WebKit/android/plugins/PluginTimer.cpp
+++ b/WebKit/android/plugins/PluginTimer.cpp
@@ -29,10 +29,10 @@
namespace WebCore {
- static uint32 gTimerID;
+ static uint32_t gTimerID;
PluginTimer::PluginTimer(PluginTimer** list, NPP instance, bool repeat,
- void (*timerFunc)(NPP npp, uint32 timerID))
+ void (*timerFunc)(NPP npp, uint32_t timerID))
: m_list(list),
m_instance(instance),
m_timerFunc(timerFunc),
@@ -71,7 +71,7 @@ namespace WebCore {
}
// may return null if timerID is not found
- PluginTimer* PluginTimer::Find(PluginTimer* list, uint32 timerID)
+ PluginTimer* PluginTimer::Find(PluginTimer* list, uint32_t timerID)
{
PluginTimer* curr = list;
while (curr) {
@@ -92,8 +92,8 @@ namespace WebCore {
}
}
- uint32 PluginTimerList::schedule(NPP instance, uint32 interval, bool repeat,
- void (*proc)(NPP npp, uint32 timerID))
+ uint32_t PluginTimerList::schedule(NPP instance, uint32_t interval, bool repeat,
+ void (*proc)(NPP npp, uint32_t timerID))
{
PluginTimer* timer = new PluginTimer(&m_list, instance, repeat, proc);
@@ -106,7 +106,7 @@ namespace WebCore {
return timer->timerID();
}
- void PluginTimerList::unschedule(NPP instance, uint32 timerID)
+ void PluginTimerList::unschedule(NPP instance, uint32_t timerID)
{
// Although it looks like simply deleting the timer would work here
// (stop() will be executed by the dtor), we cannot do this, as
diff --git a/WebKit/android/plugins/PluginTimer.h b/WebKit/android/plugins/PluginTimer.h
index 2ffe437..dcb29bf 100644
--- a/WebKit/android/plugins/PluginTimer.h
+++ b/WebKit/android/plugins/PluginTimer.h
@@ -37,14 +37,14 @@ namespace WebCore {
class PluginTimer : public TimerBase {
public:
PluginTimer(PluginTimer** list, NPP instance, bool repeat,
- void (*proc)(NPP npp, uint32 timerID));
+ void (*proc)(NPP npp, uint32_t timerID));
virtual ~PluginTimer();
- uint32 timerID() const { return m_timerID; }
+ uint32_t timerID() const { return m_timerID; }
void unschedule() { m_unscheduled = true; }
- static PluginTimer* Find(PluginTimer* list, uint32 timerID);
+ static PluginTimer* Find(PluginTimer* list, uint32_t timerID);
private:
// override from TimerBase
@@ -57,8 +57,8 @@ namespace WebCore {
PluginTimer* m_prev;
PluginTimer* m_next;
NPP m_instance;
- void (*m_timerFunc)(NPP, uint32);
- uint32 m_timerID;
+ void (*m_timerFunc)(NPP, uint32_t);
+ uint32_t m_timerID;
bool m_repeat;
bool m_unscheduled;
};
@@ -68,9 +68,9 @@ namespace WebCore {
PluginTimerList() : m_list(0) {}
~PluginTimerList();
- uint32 schedule(NPP instance, uint32 interval, bool repeat,
- void (*proc)(NPP npp, uint32 timerID));
- void unschedule(NPP instance, uint32 timerID);
+ uint32_t schedule(NPP instance, uint32_t interval, bool repeat,
+ void (*proc)(NPP npp, uint32_t timerID));
+ void unschedule(NPP instance, uint32_t timerID);
private:
PluginTimer* m_list;
diff --git a/WebKit/android/plugins/PluginWidgetAndroid.cpp b/WebKit/android/plugins/PluginWidgetAndroid.cpp
index c5a1f5b..b90b53b 100644
--- a/WebKit/android/plugins/PluginWidgetAndroid.cpp
+++ b/WebKit/android/plugins/PluginWidgetAndroid.cpp
@@ -275,7 +275,7 @@ void PluginWidgetAndroid::layoutSurface(bool pluginBoundsChanged) {
}
}
-int16 PluginWidgetAndroid::sendEvent(const ANPEvent& evt) {
+int16_t PluginWidgetAndroid::sendEvent(const ANPEvent& evt) {
if (!m_acceptEvents)
return 0;
WebCore::PluginPackage* pkg = m_pluginView->plugin();
@@ -297,7 +297,7 @@ int16 PluginWidgetAndroid::sendEvent(const ANPEvent& evt) {
// make a localCopy since the actual plugin may not respect its constness,
// and so we don't want our caller to have its param modified
ANPEvent localCopy = evt;
- int16 result = pkg->pluginFuncs()->event(instance, &localCopy);
+ int16_t result = pkg->pluginFuncs()->event(instance, &localCopy);
#if DEBUG_EVENTS
SkMSec endTime = SkTime::GetMSecs();
diff --git a/WebKit/android/plugins/PluginWidgetAndroid.h b/WebKit/android/plugins/PluginWidgetAndroid.h
index 2e55aaa..162fb1d 100644
--- a/WebKit/android/plugins/PluginWidgetAndroid.h
+++ b/WebKit/android/plugins/PluginWidgetAndroid.h
@@ -97,7 +97,7 @@ struct PluginWidgetAndroid {
/* Send this event to the plugin instance. A non-zero value will be
returned if the plugin handled the event.
*/
- int16 sendEvent(const ANPEvent&);
+ int16_t sendEvent(const ANPEvent&);
/* Update the plugins event flags. If a flag is set to true then the plugin
wants to be notified of events of this type.
diff --git a/WebKit/android/smoke/MessageThread.cpp b/WebKit/android/smoke/MessageThread.cpp
new file mode 100644
index 0000000..48f2222
--- /dev/null
+++ b/WebKit/android/smoke/MessageThread.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "MessageThread"
+
+#include "config.h"
+
+#include <sys/time.h>
+#include <time.h>
+
+#include "MessageThread.h"
+#include "ScriptController.h"
+
+#include <utils/Log.h>
+
+namespace android {
+
+static bool compareMessages(const Message& msg1,
+ const Message& msg2,
+ bool memberIsNull) {
+ return (msg1.object() == msg2.object() &&
+ (memberIsNull || msg1.member() == msg2.member()));
+}
+
+bool MessageQueue::hasMessages(const Message& message) {
+ AutoMutex lock(m_mutex);
+
+ static const Message::GenericMemberFunction nullMember = NULL;
+ const bool memberIsNull = message.member() == nullMember;
+
+ for (list<Message*>::iterator it = m_messages.begin();
+ it != m_messages.end(); ++it) {
+ Message* m = *it;
+ if (compareMessages(message, *m, memberIsNull))
+ return true;
+ }
+ return false;
+}
+
+void MessageQueue::remove(const Message& message) {
+ AutoMutex lock(m_mutex);
+
+ static const Message::GenericMemberFunction nullMember = NULL;
+ const bool memberIsNull = message.member() == nullMember;
+
+ for (list<Message*>::iterator it = m_messages.begin();
+ it != m_messages.end(); ++it) {
+ Message* m = *it;
+ if (compareMessages(message, *m, memberIsNull)) {
+ it = m_messages.erase(it);
+ delete m;
+ }
+ }
+}
+
+void MessageQueue::post(Message* message) {
+ AutoMutex lock(m_mutex);
+
+ double when = message->m_when;
+ LOG_ASSERT(when > 0, "Message time may not be 0");
+
+ list<Message*>::iterator it;
+ for (it = m_messages.begin(); it != m_messages.end(); ++it) {
+ Message* m = *it;
+ if (when < m->m_when) {
+ break;
+ }
+ }
+ m_messages.insert(it, message);
+ m_condition.signal();
+}
+
+void MessageQueue::postAtFront(Message* message) {
+ AutoMutex lock(m_mutex);
+ message->m_when = 0;
+ m_messages.push_front(message);
+}
+
+Message* MessageQueue::next() {
+ AutoMutex lock(m_mutex);
+ while (true) {
+ if (m_messages.empty()) {
+ // No messages, wait until another arrives
+ m_condition.wait(m_mutex);
+ }
+ Message* next = m_messages.front();
+ double now = WTF::currentTimeMS();
+ double diff = next->m_when - now;
+ if (diff > 0) {
+ // Not time for this message yet, wait the difference in nanos
+ m_condition.waitRelative(m_mutex,
+ static_cast<nsecs_t>(diff * 1000000) /* nanos */);
+ } else {
+ // Time for this message to run.
+ m_messages.pop_front();
+ return next;
+ }
+ }
+}
+
+bool MessageThread::threadLoop() {
+ WebCore::ScriptController::initializeThreading();
+
+ while (true) {
+ Message* message = m_queue.next();
+ if (message != NULL) {
+ message->run();
+ }
+ }
+ return false;
+}
+
+// Global thread object obtained by messageThread().
+static sp<MessageThread> gMessageThread;
+
+MessageThread* messageThread() {
+ if (gMessageThread == NULL) {
+ gMessageThread = new MessageThread();
+ gMessageThread->run("WebCoreThread");
+ }
+ return gMessageThread.get();
+}
+
+} // namespace android
diff --git a/WebKit/android/smoke/MessageThread.h b/WebKit/android/smoke/MessageThread.h
new file mode 100644
index 0000000..ca0115b
--- /dev/null
+++ b/WebKit/android/smoke/MessageThread.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_WEBKIT_MESSAGETHREAD_H
+#define ANDROID_WEBKIT_MESSAGETHREAD_H
+
+#include <list>
+
+#include "MessageTypes.h"
+
+#include <utils/threads.h>
+
+using std::list;
+
+namespace android {
+
+class MessageQueue {
+public:
+ MessageQueue() {}
+
+ // Return true if the queue has messages with the given object and member
+ // function. If member is null, return true if the message has the same
+ // object.
+ template <class T>
+ bool hasMessages(T* object, void (T::*member)(void));
+
+ // Remove all messages with the given object and member function. If
+ // member is null, remove all messages with the given object.
+ template <class T>
+ void remove(T* object, void (T::*member)(void));
+
+ // Post a new message to the queue.
+ void post(Message* closure);
+
+ // Post a new message at the front of the queue.
+ void postAtFront(Message* closure);
+
+ // Obtain the next message. Blocks until either a new message arrives or
+ // we reach the time of the next message.
+ Message* next();
+
+private:
+ bool hasMessages(const Message& message);
+ void remove(const Message& message);
+
+ list<Message*> m_messages;
+ Mutex m_mutex;
+ Condition m_condition;
+};
+
+template <class T>
+bool MessageQueue::hasMessages(T* object, void (T::*member)(void)) {
+ MemberFunctionMessage<T, void> message(object, member);
+ return hasMessages(message);
+}
+
+template <class T>
+void MessageQueue::remove(T* object, void (T::*member)(void)) {
+ MemberFunctionMessage<T, void> message(object, member);
+ remove(message);
+}
+
+class MessageThread : public Thread {
+public:
+ MessageQueue& queue() { return m_queue; }
+
+private:
+ MessageThread() : Thread(true /* canCallJava */) {}
+
+ virtual bool threadLoop();
+
+ MessageQueue m_queue;
+ // Used for thread initialization
+ Mutex m_mutex;
+ Condition m_condition;
+
+ friend MessageThread* messageThread();
+};
+
+// Get (possibly creating) the global MessageThread object used to pass
+// messages to WebCore.
+MessageThread* messageThread();
+
+} // namespace android
+
+#endif // ANDROID_WEBKIT_MESSAGETHREAD_H
diff --git a/WebKit/android/smoke/MessageTypes.h b/WebKit/android/smoke/MessageTypes.h
new file mode 100644
index 0000000..7da6cb8
--- /dev/null
+++ b/WebKit/android/smoke/MessageTypes.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_WEBKIT_MESSAGETYPES_H_
+#define ANDROID_WEBKIT_MESSAGETYPES_H_
+
+#include <wtf/CurrentTime.h>
+
+// TODO(phanna): autogenerate these types!
+
+namespace android {
+
+// Forward declared for friendship!
+class MessageQueue;
+
+// Removes the reference from the typename so we store the actual value in the
+// closure.
+template <typename T> struct remove_reference { typedef T type; };
+template <typename T> struct remove_reference<T&> { typedef T type; };
+
+// Prevent the compiler from inferring the type.
+template <typename T> struct identity { typedef T type; };
+
+// Message base class. Defines the public run() method and contains generic
+// object and member function variables for use in MessageQueue.
+//
+// Note: The template subclass MemberFunctionMessage casts its object and
+// member function to the generic void* and Message::* types. During run(),
+// each template specialization downcasts to the original type and invokes the
+// correct function. This may seem dangerous but the compiler enforces
+// correctness in NewMessage and in the template constructor.
+class Message {
+public:
+ typedef void (Message::*GenericMemberFunction)(void);
+
+ virtual ~Message() {}
+ virtual void run() = 0;
+
+ // The wall time that the message is supposed to run.
+ double m_when;
+
+ void* object() const { return m_object; }
+ GenericMemberFunction member() const { return m_member; }
+
+protected:
+ Message(void* object, GenericMemberFunction member, long delay = 0)
+ : m_object(object)
+ , m_member(member) {
+ m_when = WTF::currentTimeMS() + delay;
+ }
+
+ // Downcast back to the original template params in run(). Also accessed
+ // by MessageQueue to compare messages.
+ void* m_object;
+ GenericMemberFunction m_member;
+
+private:
+ // Disallow copy
+ Message(const Message&);
+};
+
+// Forward declaration for partial specialization.
+template <class T, typename A1>
+class MemberFunctionMessage;
+
+template <class T>
+class MemberFunctionMessage<T, void> : public Message {
+private:
+ typedef void (T::*MemberSignature)();
+
+public:
+ inline MemberFunctionMessage(T* object,
+ MemberSignature member,
+ long delay = 0)
+ : Message(reinterpret_cast<void*>(object),
+ reinterpret_cast<GenericMemberFunction>(member),
+ delay) {}
+
+ virtual void run() {
+ MemberSignature member = reinterpret_cast<MemberSignature>(m_member);
+ (reinterpret_cast<T*>(m_object)->*member)();
+ delete this;
+ }
+};
+
+template <class T>
+inline Message* NewMessage(T* object, void (T::*member)()) {
+ return new MemberFunctionMessage<T, void>(object, member);
+}
+
+template <class T>
+inline Message* NewDelayedMessage(T* object, void (T::*member)(), long delay) {
+ return new MemberFunctionMessage<T, void>(object, member, delay);
+}
+
+template <class T, typename A1>
+class MemberFunctionMessage : public Message {
+private:
+ typedef void (T::*MemberSignature)(A1);
+
+public:
+ inline MemberFunctionMessage(T* object,
+ MemberSignature member,
+ A1 arg1,
+ long delay = 0)
+ : Message(reinterpret_cast<void*>(object),
+ reinterpret_cast<GenericMemberFunction>(member),
+ delay)
+ , m_arg1(arg1) {}
+
+ virtual void run() {
+ MemberSignature member = reinterpret_cast<MemberSignature>(m_member);
+ (reinterpret_cast<T*>(m_object)->*member)(m_arg1);
+ delete this;
+ }
+
+private:
+ typename remove_reference<A1>::type m_arg1;
+};
+
+template <class T, typename A1>
+inline Message* NewMessage(T* object, void (T::*member)(A1),
+ typename identity<A1>::type arg1) {
+ return new MemberFunctionMessage<T, A1>(
+ object, member, arg1);
+}
+
+template <class T, typename A1>
+inline Message* NewDelayedMessage(T* object, void (T::*member)(A1),
+ typename identity<A1>::type arg1, long delay) {
+ return new MemberFunctionMessage<T, A1>(object, member, arg1, delay);
+}
+
+} // namespace android
+
+
+#endif // ANDROID_WEBKIT_MESSAGETYPES_H_
diff --git a/WebKit/android/wds/Command.cpp b/WebKit/android/wds/Command.cpp
index 7f2046e..bd8536f 100644
--- a/WebKit/android/wds/Command.cpp
+++ b/WebKit/android/wds/Command.cpp
@@ -27,7 +27,6 @@
#include "config.h"
#include "AndroidLog.h"
-#include "CString.h"
#include "Command.h"
#include "Connection.h"
#include "DebugServer.h"
@@ -36,6 +35,7 @@
#include "RenderView.h"
#include "WebViewCore.h"
#include <utils/Log.h>
+#include <wtf/text/CString.h>
#if ENABLE(WDS)