summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-01-09 17:51:23 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-01-09 17:51:23 -0800
commite933faefa1e899dbd5bf371f499cc682aff46c83 (patch)
tree8fb31ff5c9a41aec9912d0253be7ef0445e2f58a
parent1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353 (diff)
downloadexternal_webkit-e933faefa1e899dbd5bf371f499cc682aff46c83.zip
external_webkit-e933faefa1e899dbd5bf371f499cc682aff46c83.tar.gz
external_webkit-e933faefa1e899dbd5bf371f499cc682aff46c83.tar.bz2
auto import from //branches/cupcake/...@125939
-rw-r--r--Android.mk12
-rw-r--r--WebCore/WebCorePrefixAndroid.h38
-rw-r--r--WebCore/dom/ContainerNode.cpp10
-rw-r--r--WebCore/dom/Document.cpp13
-rw-r--r--WebCore/dom/Element.h8
-rw-r--r--WebCore/dom/Node.cpp2
-rw-r--r--WebCore/history/HistoryItem.cpp7
-rw-r--r--WebCore/history/HistoryItem.h3
-rw-r--r--WebCore/html/HTMLAreaElement.cpp18
-rw-r--r--WebCore/html/HTMLAreaElement.h16
-rw-r--r--WebCore/html/HTMLElement.cpp4
-rw-r--r--WebCore/html/HTMLInputElement.cpp11
-rw-r--r--WebCore/html/HTMLSelectElement.cpp2
-rw-r--r--WebCore/loader/CachedCSSStyleSheet.cpp2
-rw-r--r--WebCore/loader/CachedScript.cpp2
-rw-r--r--WebCore/loader/icon/IconDatabase.cpp18
-rw-r--r--WebCore/page/android/DragControllerAndroid.cpp2
-rw-r--r--WebCore/page/android/EventHandlerAndroid.cpp14
-rw-r--r--WebCore/page/android/InspectorControllerAndroid.cpp17
-rw-r--r--WebCore/platform/android/KeyEventAndroid.cpp2
-rw-r--r--WebCore/platform/graphics/Font.cpp11
-rw-r--r--WebCore/platform/graphics/GlyphBuffer.h22
-rw-r--r--WebCore/platform/graphics/WidthIterator.cpp24
-rw-r--r--WebCore/platform/graphics/WidthIterator.h4
-rw-r--r--WebCore/platform/graphics/android/AffineTransformAndroid.cpp6
-rw-r--r--WebCore/platform/graphics/android/FontAndroid.cpp38
-rw-r--r--WebCore/rendering/RenderImage.cpp22
-rw-r--r--WebCore/rendering/RenderImage.h9
-rw-r--r--WebCore/rendering/RenderObject.cpp5
-rw-r--r--WebKit/Android.mk6
-rw-r--r--WebKit/android/jni/WebCoreFrameBridge.cpp7
-rw-r--r--WebKit/android/jni/WebViewCore.cpp135
-rw-r--r--WebKit/android/jni/WebViewCore.h17
-rw-r--r--WebKit/android/nav/CacheBuilder.cpp47
-rw-r--r--WebKit/android/nav/CacheBuilder.h4
-rw-r--r--WebKit/android/nav/FindCanvas.cpp197
-rw-r--r--WebKit/android/nav/FindCanvas.h65
-rw-r--r--WebKit/android/nav/WebView.cpp111
-rw-r--r--WebKit/android/plugins/sample/main.cpp1
-rw-r--r--WebKit/android/wds/Command.cpp145
-rw-r--r--WebKit/android/wds/Command.h99
-rw-r--r--WebKit/android/wds/Connection.cpp84
-rw-r--r--WebKit/android/wds/Connection.h76
-rw-r--r--WebKit/android/wds/DebugServer.cpp107
-rw-r--r--WebKit/android/wds/DebugServer.h68
-rw-r--r--WebKit/android/wds/client/AdbConnection.cpp228
-rw-r--r--WebKit/android/wds/client/AdbConnection.h38
-rw-r--r--WebKit/android/wds/client/Android.mk32
-rw-r--r--WebKit/android/wds/client/ClientUtils.cpp26
-rw-r--r--WebKit/android/wds/client/ClientUtils.h29
-rw-r--r--WebKit/android/wds/client/Device.cpp22
-rw-r--r--WebKit/android/wds/client/Device.h53
-rw-r--r--WebKit/android/wds/client/DeviceList.h26
-rw-r--r--WebKit/android/wds/client/main.cpp164
54 files changed, 1569 insertions, 560 deletions
diff --git a/Android.mk b/Android.mk
index 40db5c2..235ba7b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -18,6 +18,9 @@
BASE_PATH := $(call my-dir)
include $(CLEAR_VARS)
+# if you need to make webcore huge (for debugging), enable this line
+#LOCAL_PRELINK_MODULE := false
+
# Define our module and find the intermediates directory
LOCAL_MODULE := libwebcore
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
@@ -77,7 +80,11 @@ LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE) \
external/icu4c/common \
external/libxml2/include \
- external/skia/libsgl/ports \
+ external/skia/include/effects \
+ external/skia/include/images \
+ external/skia/include/ports \
+ external/skia/include/utils \
+ external/skia/src/ports \
external/sqlite/dist \
frameworks/base/core/jni/android/graphics \
$(LOCAL_PATH)/WebCore \
@@ -176,3 +183,6 @@ include $(BUILD_SHARED_LIBRARY)
# Build the plugin test separately from libwebcore
include $(BASE_PATH)/WebKit/android/plugins/sample/Android.mk
+
+# Build the wds client
+include $(BASE_PATH)/WebKit/android/wds/client/Android.mk
diff --git a/WebCore/WebCorePrefixAndroid.h b/WebCore/WebCorePrefixAndroid.h
index 1f4287f..c933562 100644
--- a/WebCore/WebCorePrefixAndroid.h
+++ b/WebCore/WebCorePrefixAndroid.h
@@ -68,23 +68,11 @@ typedef unsigned char flex_uint8_t;
#define ANDROID_EXPOSE_COLUMN_GAP
-// This change was made before we changed ListBoxes to operate the same way
-// as drop down lists.
-// FIXME: Check to make sure we can delete it.
-#define ANDROID_NAVIGATE_LISTBOX
-
-// Allows us to get the rectangle of an <area> element so we can navigate to it
-// This could be submitted back to webkit if anyone else wants to use the
-// hit rectangles for navigation.
-#define ANDROID_NAVIGATE_AREAMAPS
-
#define ANDROID_LAYOUT
// Allows us to select all of the text in a <textarea> in onfocus
#define ANDROID_SELECT_TEXT_AREAS
-#define ANDROID_KEYBOARD_NAVIGATION
-#define ANDROID_NO_BODY_INNER_HTML
#define ANDROID_FIX
// note: if uncomment ANDROID_INSTRUMENT here, you must also
// uncomment it on line 31 of JavaScriptCore/kjs/config.h
@@ -101,14 +89,6 @@ typedef unsigned char flex_uint8_t;
// Unnecessary for us, since we handle scrolling outside of WebKit.
#define ANDROID_SCROLL_FIX
-// Fixes an issue where going back to a page that sets focus to a textfield
-// results in restoring the selection rather than selecting all.
-#define ANDROID_DO_NOT_RESTORE_PREVIOUS_SELECTION
-
-// Fix for issue 986508. May be possible to combine with
-// ANDROID_DO_NOT_RESTORE_PREVIOUS_SELECTION
-#define ANDROID_RESET_SELECTION
-
#define ANDROID_META_SUPPORT
// Give public access to a private method in HTMLSelectElement so that
@@ -131,7 +111,7 @@ typedef unsigned char flex_uint8_t;
// Changes needed to support native plugins (npapi.h). If the change is generic,
// it may be under a different #define (see: PLUGIN_PLATFORM_SETVALUE,
-// PLUGIN_SCHEDULE_TIMER, ANDROID_PLUGIN_MAIN_THREAD_SCHEDULER_FIXES)
+// PLUGIN_SCHEDULE_TIMER)
#define ANDROID_PLUGINS
// Prevent Webkit from drawing the selection in textfields/textareas, since we
@@ -144,15 +124,6 @@ typedef unsigned char flex_uint8_t;
// ResourceRequest.
#define ANDROID_USER_GESTURE
-// Inform webkit (Font.cpp) that we NEVER want to perform rounding hacks for
-// text, since we always measure/draw in subpixel mode (performance)
-#define ANDROID_NEVER_ROUND_FONT_METRICS
-
-// Add bool to GlyphBuffer as a drawing hint, marking buffers whose array of
-// widths happen to exactly match the values returned from the font. This allows
-// the drawing code to ignore the position array if they choose (performace)
-#define ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
-
// Add support for the orientation window property
#define ANDROID_ORIENTATION_SUPPORT
@@ -164,12 +135,6 @@ typedef unsigned char flex_uint8_t;
// Will submit this as a patch to apple
#define PLUGIN_PLATFORM_SETVALUE
-// This fixes a bug in PluginMainThreadScheduler: it is obviously
-// missing a reset of m_callPending. This means that it never wakes up
-// the main thread after the first time triggered.
-// https://bugs.webkit.org/show_bug.cgi?id=21503
-#define ANDROID_PLUGIN_MAIN_THREAD_SCHEDULER_FIXES
-
// This enables logging the DOM tree, Render tree even for the release build
#define ANDROID_DOM_LOGGING
@@ -187,4 +152,3 @@ typedef unsigned char flex_uint8_t;
// Enable dumping the display tree to a file (triggered in WebView.java)
#define ANDROID_DUMP_DISPLAY_TREE
-
diff --git a/WebCore/dom/ContainerNode.cpp b/WebCore/dom/ContainerNode.cpp
index cef9b7d..bcd54c1 100644
--- a/WebCore/dom/ContainerNode.cpp
+++ b/WebCore/dom/ContainerNode.cpp
@@ -182,16 +182,6 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce
if (oldChild == newChild) // nothing to do
return true;
-#ifdef ANDROID_FIX
- // if oldChild is null, it will cause crash in checkReplaceChild(). We
- // should check null first.
- // Fix Android bug, http://b/issue?id=847893
- if (!oldChild) {
- ec = NOT_FOUND_ERR;
- return false;
- }
-#endif
-
// Make sure replacing the old child with the new is ok
checkReplaceChild(newChild.get(), oldChild, ec);
if (ec)
diff --git a/WebCore/dom/Document.cpp b/WebCore/dom/Document.cpp
index 3e866a6..c35177a 100644
--- a/WebCore/dom/Document.cpp
+++ b/WebCore/dom/Document.cpp
@@ -2510,19 +2510,6 @@ bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode)
if (m_inPageCache)
return false;
-#ifdef ANDROID_RESET_SELECTION
- WebCore::Node* oldFocus = frame()->getCacheBuilder().currentFocus();
- if (oldFocus) {
- if (oldFocus->hasTagName(WebCore::HTMLNames::inputTag)) {
- WebCore::HTMLInputElement* input = static_cast<WebCore::HTMLInputElement*>(oldFocus);
- if (input->isTextField())
- input->setSelectionRange(-1, -1);
- } else if (oldFocus->hasTagName(WebCore::HTMLNames::textareaTag)) {
- WebCore::HTMLTextAreaElement* textArea = static_cast<WebCore::HTMLTextAreaElement*>(oldFocus);
- textArea->setSelectionRange(-1, -1);
- }
- }
-#endif
bool focusChangeBlocked = false;
RefPtr<Node> oldFocusedNode = m_focusedNode;
m_focusedNode = 0;
diff --git a/WebCore/dom/Element.h b/WebCore/dom/Element.h
index 3aae0b5..b9dc0fd 100644
--- a/WebCore/dom/Element.h
+++ b/WebCore/dom/Element.h
@@ -157,15 +157,7 @@ public:
virtual bool isURLAttribute(Attribute*) const;
virtual const QualifiedName& imageSourceAttributeName() const;
virtual String target() const { return String(); }
-#ifdef ANDROID_DO_NOT_RESTORE_PREVIOUS_SELECTION
- // Set the default to not restore the previous selection, since
- // we want the selection to cover the whole textfield.
- // FIXME: Would it be a better fix to simply ignore the input
- // value in the implementation?
- virtual void focus(bool restorePreviousSelection = false);
-#else
virtual void focus(bool restorePreviousSelection = true);
-#endif
virtual void updateFocusAppearance(bool restorePreviousSelection);
void blur();
diff --git a/WebCore/dom/Node.cpp b/WebCore/dom/Node.cpp
index 6a16b3c..214a19e 100644
--- a/WebCore/dom/Node.cpp
+++ b/WebCore/dom/Node.cpp
@@ -1876,8 +1876,8 @@ void Node::showTreeAndMark(const Node* markedNode1, const char* markedLabel1, co
#else
for (const Node* tmpNode = node; tmpNode && tmpNode != rootNode; tmpNode = tmpNode->parentNode())
fprintf(stderr, "\t");
-#endif
node->showNode();
+#endif
}
}
diff --git a/WebCore/history/HistoryItem.cpp b/WebCore/history/HistoryItem.cpp
index d7cc311..d4e58e4 100644
--- a/WebCore/history/HistoryItem.cpp
+++ b/WebCore/history/HistoryItem.cpp
@@ -414,13 +414,6 @@ FormData* HistoryItem::formData()
return m_formData.get();
}
-#ifdef ANDROID_FIX
-const FormData* HistoryItem::formData() const
-{
- return m_formData.get();
-}
-#endif
-
bool HistoryItem::isCurrentDocument(Document* doc) const
{
// FIXME: We should find a better way to check if this is the current document.
diff --git a/WebCore/history/HistoryItem.h b/WebCore/history/HistoryItem.h
index cc131dd..839f47d 100644
--- a/WebCore/history/HistoryItem.h
+++ b/WebCore/history/HistoryItem.h
@@ -109,9 +109,6 @@ public:
bool isTargetItem() const;
FormData* formData();
-#ifdef ANDROID_FIX
- const FormData* formData() const;
-#endif
String formContentType() const;
String formReferrer() const;
String rssFeedReferrer() const;
diff --git a/WebCore/html/HTMLAreaElement.cpp b/WebCore/html/HTMLAreaElement.cpp
index 7c6d65f..a865122 100644
--- a/WebCore/html/HTMLAreaElement.cpp
+++ b/WebCore/html/HTMLAreaElement.cpp
@@ -29,10 +29,6 @@
#include "Length.h"
#include "RenderObject.h"
-#ifdef ANDROID_NAVIGATE_AREAMAPS
-#include "RenderImage.h"
-#endif
-
using namespace std;
namespace WebCore {
@@ -45,9 +41,6 @@ HTMLAreaElement::HTMLAreaElement(Document *doc)
, m_coordsLen(0)
, m_lastSize(-1, -1)
, m_shape(Unknown)
-#ifdef ANDROID_NAVIGATE_AREAMAPS
- , m_map(0)
-#endif
{
}
@@ -231,15 +224,4 @@ void HTMLAreaElement::setTarget(const String& value)
setAttribute(targetAttr, value);
}
-#ifdef ANDROID_NAVIGATE_AREAMAPS
-IntRect HTMLAreaElement::getAreaRect() const
-{
- if (m_map) {
- if (isDefault())
- return m_map->absoluteBoundingBoxRect();
- return getRect(m_map);
- }
- return IntRect();
-}
-#endif
}
diff --git a/WebCore/html/HTMLAreaElement.h b/WebCore/html/HTMLAreaElement.h
index 2cce901..986116b 100644
--- a/WebCore/html/HTMLAreaElement.h
+++ b/WebCore/html/HTMLAreaElement.h
@@ -29,14 +29,6 @@
namespace WebCore {
-#ifdef ANDROID_NAVIGATE_AREAMAPS
- // in android, we have no pointer, so we can't access area elements
- // via mapMouseEvent. instead, we store the RenderImage here so we
- // can use it to find its dimensions to focus on it and draw a ring
- // around it
- class RenderImage;
-#endif
-
class HitTestResult;
class HTMLAreaElement : public HTMLAnchorElement {
@@ -78,11 +70,6 @@ public:
virtual String target() const;
void setTarget(const String&);
-#ifdef ANDROID_NAVIGATE_AREAMAPS
- IntRect getAreaRect() const;
- void setMap(RenderImage* map) { m_map = map; }
-#endif
-
private:
enum Shape { Default, Poly, Rect, Circle, Unknown };
Path getRegion(const IntSize&) const;
@@ -91,9 +78,6 @@ private:
int m_coordsLen;
IntSize m_lastSize;
Shape m_shape;
-#ifdef ANDROID_NAVIGATE_AREAMAPS
- RenderImage* m_map;
-#endif
};
} //namespace
diff --git a/WebCore/html/HTMLElement.cpp b/WebCore/html/HTMLElement.cpp
index 3f8a983..572a7a5 100644
--- a/WebCore/html/HTMLElement.cpp
+++ b/WebCore/html/HTMLElement.cpp
@@ -241,10 +241,6 @@ void HTMLElement::parseMappedAttribute(MappedAttribute *attr)
String HTMLElement::innerHTML() const
{
-#ifdef ANDROID_NO_BODY_INNER_HTML
- if (id()==bodyTag || id()==htmlTag)
- return "fastinnerhtml!";
-#endif
return createMarkup(this, ChildrenOnly);
}
diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp
index cebfb51..c5c55fd 100644
--- a/WebCore/html/HTMLInputElement.cpp
+++ b/WebCore/html/HTMLInputElement.cpp
@@ -58,7 +58,7 @@
#if USE(LOW_BANDWIDTH_DISPLAY)
#include "FrameLoader.h"
#endif
-#ifdef ANDROID // multiple additions: see below
+#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
#include "WebViewCore.h"
#endif
#include "TextIterator.h"
@@ -197,7 +197,6 @@ bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const
if (name().isEmpty())
return false;
-#ifndef ANDROID_KEYBOARD_NAVIGATION
// Never allow keyboard tabbing to leave you in the same radio group. Always
// skip any other elements in the group.
Node* currentFocusedNode = document()->focusedNode();
@@ -207,7 +206,6 @@ bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const
focusedInput->name() == name())
return false;
}
-#endif
// Allow keyboard focus if we're checked or if nothing in the group is checked.
return checked() || !checkedRadioButtons(this).checkedButtonForGroup(name());
@@ -1297,11 +1295,6 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
clickElement = true;
break;
case RADIO:
-#ifdef ANDROID_KEYBOARD_NAVIGATION
-// allow enter to change state of radio
- if (!checked())
- clickElement = true;
-#endif
break; // Don't do anything for enter on a radio button.
}
} else if (charCode == ' ') {
@@ -1348,7 +1341,6 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
}
}
-#ifndef ANDROID_KEYBOARD_NAVIGATION
// allow enter to change state of radio
if (inputType() == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) {
// Left and up mean "previous radio button".
@@ -1384,7 +1376,6 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
}
}
}
-#endif
}
if (evt->type() == eventNames().keyupEvent && evt->isKeyboardEvent()) {
diff --git a/WebCore/html/HTMLSelectElement.cpp b/WebCore/html/HTMLSelectElement.cpp
index 44e7fe4..e95bfd3 100644
--- a/WebCore/html/HTMLSelectElement.cpp
+++ b/WebCore/html/HTMLSelectElement.cpp
@@ -586,12 +586,10 @@ void HTMLSelectElement::dispatchFocusEvent()
void HTMLSelectElement::dispatchBlurEvent()
{
-#ifndef ANDROID_NAVIGATE_LISTBOX
// We only need to fire onChange here for menu lists, because we fire onChange for list boxes whenever the selection change is actually made.
// This matches other browsers' behavior.
if (usesMenuList())
menuListOnChange();
-#endif
HTMLFormControlElementWithState::dispatchBlurEvent();
}
diff --git a/WebCore/loader/CachedCSSStyleSheet.cpp b/WebCore/loader/CachedCSSStyleSheet.cpp
index ace938b..9059f25 100644
--- a/WebCore/loader/CachedCSSStyleSheet.cpp
+++ b/WebCore/loader/CachedCSSStyleSheet.cpp
@@ -76,7 +76,7 @@ void CachedCSSStyleSheet::data(PassRefPtr<SharedBuffer> data, bool allDataReceiv
if (m_data.get()) {
m_sheet = m_decoder->decode(m_data->data(), encodedSize());
m_sheet += m_decoder->flush();
-#ifdef ANDROID_FIX
+#ifdef ANDROID_FIX // FIXME Newer webkit makes decode temporary; remove on webkit update
// report decoded size too
setDecodedSize(m_sheet.length() * sizeof(UChar));
#endif
diff --git a/WebCore/loader/CachedScript.cpp b/WebCore/loader/CachedScript.cpp
index 9666eea..c8caea8 100644
--- a/WebCore/loader/CachedScript.cpp
+++ b/WebCore/loader/CachedScript.cpp
@@ -79,7 +79,7 @@ void CachedScript::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
setEncodedSize(m_data.get() ? m_data->size() : 0);
if (m_data.get())
m_script = m_encoding.decode(m_data->data(), encodedSize());
-#ifdef ANDROID_FIX
+#ifdef ANDROID_FIX // FIXME Newer webkit calls setDecodedSize in CachedScript::script(); remove on webkit update
// report decoded size too
setDecodedSize(m_script.length() * sizeof(UChar));
#endif
diff --git a/WebCore/loader/icon/IconDatabase.cpp b/WebCore/loader/icon/IconDatabase.cpp
index a47fb08..72e57fe 100644
--- a/WebCore/loader/icon/IconDatabase.cpp
+++ b/WebCore/loader/icon/IconDatabase.cpp
@@ -1356,28 +1356,14 @@ void* IconDatabase::syncThreadMainLoop()
bool didAnyWork = true;
while (didAnyWork) {
-#ifdef ANDROID_FIX
- // We should write the pending icons to the database before trying
- // to read any requested icons to ensure that a requested icon has
- // the correct data.
bool didWrite = writeToDatabase();
if (shouldStopThreadActivity())
break;
-
- didAnyWork = readFromDatabase();
- if (shouldStopThreadActivity())
- break;
-#else
+
didAnyWork = readFromDatabase();
if (shouldStopThreadActivity())
break;
-
- bool didWrite = writeToDatabase();
- if (shouldStopThreadActivity())
- break;
-#endif
-
-
+
// Prune unretained icons after the first time we sync anything out to the database
// This way, pruning won't be the only operation we perform to the database by itself
// We also don't want to bother doing this if the thread should be terminating (the user is quitting)
diff --git a/WebCore/page/android/DragControllerAndroid.cpp b/WebCore/page/android/DragControllerAndroid.cpp
index a56411d..eee0cdd 100644
--- a/WebCore/page/android/DragControllerAndroid.cpp
+++ b/WebCore/page/android/DragControllerAndroid.cpp
@@ -42,7 +42,7 @@ DragOperation DragController::dragOperation(DragData* dragData)
{
//FIXME: This logic is incomplete
ASSERT(0);
- if (dragData->containsURL())
+ if (dragData->containsURL())
return DragOperationCopy;
return DragOperationNone;
diff --git a/WebCore/page/android/EventHandlerAndroid.cpp b/WebCore/page/android/EventHandlerAndroid.cpp
index aa522a3..e594482 100644
--- a/WebCore/page/android/EventHandlerAndroid.cpp
+++ b/WebCore/page/android/EventHandlerAndroid.cpp
@@ -42,8 +42,6 @@
namespace WebCore {
-// using namespace EventNames;
-
unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::AltKey;
bool EventHandler::tabsToAllControls(KeyboardEvent* ) const
@@ -86,10 +84,10 @@ bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
return false;
}
-// This function is called for mouse events by FrameView::handleMousePressEvent()
-// It is used to ensure that events are sync. correctly between frames, for example
+// This function is called for mouse events by FrameView::handleMousePressEvent().
+// It is used to ensure that events are sync'ed correctly between frames. For example
// if the user presses down in one frame and up in another frame, this function will
-// return true if that is the case, and pass the event to the correct frame
+// returns true, and pass the event to the correct frame.
bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event,
Frame* subframe, HitTestResult* hoveredNode)
{
@@ -97,8 +95,8 @@ bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& eve
return false;
}
-// This is called to route Wheel Events to child widgets when they are a RenderWidget
-// as the parent usually gets Wheel Event. Don't have a mouse with a wheel to confirm
+// This is called to route wheel events to child widgets when they are RenderWidget
+// as the parent usually gets wheel event. Don't have a mouse with a wheel to confirm
// the operation of this function.
bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& , Widget* widget)
{
@@ -127,6 +125,6 @@ class Clipboard : public RefCounted<Clipboard> {};
PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const { return PassRefPtr<Clipboard>(NULL); }
- // new as of SVN change 36269, Sept 8, 2008
+// new as of SVN change 36269, Sept 8, 2008
const double EventHandler::TextDragDelay = 0.0;
}
diff --git a/WebCore/page/android/InspectorControllerAndroid.cpp b/WebCore/page/android/InspectorControllerAndroid.cpp
index c3b88b7..befcf4a 100644
--- a/WebCore/page/android/InspectorControllerAndroid.cpp
+++ b/WebCore/page/android/InspectorControllerAndroid.cpp
@@ -21,13 +21,12 @@
#include "Node.h"
#include "Profile.h"
-/*
// This stub file was created to avoid building and linking in all the
// Inspector codebase. If you would like to enable the Inspector, do the
// following steps:
-// 1. Replace this file in WebCore/Makefile.android with the common
+// 1. Replace this file in WebCore/Android.mk with the common
// implementation, ie page/InsepctorController.cpp
-// 2. Add the JS API files to JavaScriptCore/Makefile.android:
+// 2. Add the JS API files to JavaScriptCore/Android.mk:
// ? API/JSBase.cpp \
// API/JSCallbackConstructor.cpp \
// API/JSCallbackFunction.cpp \
@@ -37,14 +36,13 @@
// API/JSObjectRef.cpp \
// API/JSStringRef.cpp \
// API/JSValueRef.cpp
-// 3. Add the following LOCAL_C_INCLUDES to JavaScriptCore/Makefile.android:
+// 3. Add the following LOCAL_C_INCLUDES to JavaScriptCore/Android.mk:
// ?$(LOCAL_PATH)/API \
// $(LOCAL_PATH)/ForwardingHeaders \
// $(LOCAL_PATH)/../../WebKit \
// 4. Rebuild WebKit
//
-// Note, for a functional Inspector, you must implement InspectorClientAndroid
-*/
+// Note, for a functional Inspector, you must implement InspectorClientAndroid.
namespace WebCore {
@@ -54,8 +52,11 @@ struct InspectorResource : public RefCounted<InspectorResource> {
struct InspectorDatabaseResource : public RefCounted<InspectorDatabaseResource> {
};
-InspectorController::InspectorController(Page*, InspectorClient*) :
- m_startProfiling(this, NULL) {}
+InspectorController::InspectorController(Page*, InspectorClient*)
+ : m_startProfiling(this, NULL)
+{
+}
+
InspectorController::~InspectorController() {}
void InspectorController::windowScriptObjectAvailable() {}
diff --git a/WebCore/platform/android/KeyEventAndroid.cpp b/WebCore/platform/android/KeyEventAndroid.cpp
index 6a59e58..302f6fe 100644
--- a/WebCore/platform/android/KeyEventAndroid.cpp
+++ b/WebCore/platform/android/KeyEventAndroid.cpp
@@ -205,13 +205,13 @@ PlatformKeyboardEvent::PlatformKeyboardEvent(int keyCode, UChar32 unichar,
, m_keyIdentifier(keyIdentifierForAndroidKeyCode(keyCode))
, m_autoRepeat(repeatCount > 0)
, m_windowsVirtualKeyCode(windowsKeyCodeForKeyEvent(keyCode))
+ , m_nativeVirtualKeyCode(keyCode)
, m_isKeypad(false)
, m_shiftKey((mods & ShiftKey) != 0)
, m_ctrlKey((mods & CtrlKey) != 0)
, m_altKey((mods & AltKey) != 0)
, m_metaKey((mods & MetaKey) != 0)
// added for android
- , m_nativeVirtualKeyCode(keyCode)
, m_repeatCount(repeatCount)
, m_unichar(unichar)
{
diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp
index a78d27b..138e322 100644
--- a/WebCore/platform/graphics/Font.cpp
+++ b/WebCore/platform/graphics/Font.cpp
@@ -417,9 +417,6 @@ void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const Fl
WidthIterator it(this, run);
it.advance(from);
float beforeWidth = it.m_runWidthSoFar;
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
- bool adjustedWidths =
-#endif
it.advance(to, &glyphBuffer);
// We couldn't generate any glyphs for the run. Give up.
@@ -432,9 +429,6 @@ void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const Fl
float finalRoundingWidth = it.m_finalRoundingWidth;
it.advance(run.length());
startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
- adjustedWidths = true; // give up on simple/fast case
-#endif
} else
startX += beforeWidth;
@@ -443,11 +437,6 @@ void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const Fl
for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
glyphBuffer.swap(i, end);
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
- // mark the GlyphBuffer as having adjusted widths or not
- // used by drawGlyph as an optimization hint
- glyphBuffer.setHasAdjustedWidths(adjustedWidths);
-#endif
// Calculate the starting point of the glyphs to be displayed by adding
// all the advances up to the first glyph.
FloatPoint startPoint(startX, point.y());
diff --git a/WebCore/platform/graphics/GlyphBuffer.h b/WebCore/platform/graphics/GlyphBuffer.h
index 110b3c2..18957d5 100644
--- a/WebCore/platform/graphics/GlyphBuffer.h
+++ b/WebCore/platform/graphics/GlyphBuffer.h
@@ -61,10 +61,6 @@ typedef FloatSize GlyphBufferAdvance;
class GlyphBuffer {
public:
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
- GlyphBuffer() : m_hasAdjustedWidths(true) {}
-#endif
-
bool isEmpty() const { return m_fontData.isEmpty(); }
int size() const { return m_fontData.size(); }
@@ -159,18 +155,6 @@ public:
#endif
}
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
- void setHasAdjustedWidths(bool adjustedWidths) {
- m_hasAdjustedWidths = adjustedWidths;
- }
- /** Returns true in the general case, which means that one or more of the
- glyphs may have a width or height that has been changed from the raw
- value returned by the font. If this returns false, then the drawing
- code can use that as a hint if it means it can draw the run faster.
- */
- bool hasAdjustedWidths() const { return m_hasAdjustedWidths; }
-#endif
-
void add(Glyph glyph, const SimpleFontData* font, GlyphBufferAdvance advance)
{
m_fontData.append(font);
@@ -192,12 +176,6 @@ private:
#if PLATFORM(WIN)
Vector<FloatSize, 2048> m_offsets;
#endif
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
- // defaults to true for general case. Set to false sometimes in
- // drawSimpleText as a hint to drawGlphs that the widths are exactly those
- // from the font (i.e. no tweaks for rounding or CSS styling
- bool m_hasAdjustedWidths;
-#endif
};
}
diff --git a/WebCore/platform/graphics/WidthIterator.cpp b/WebCore/platform/graphics/WidthIterator.cpp
index a66b234..a16d739 100644
--- a/WebCore/platform/graphics/WidthIterator.cpp
+++ b/WebCore/platform/graphics/WidthIterator.cpp
@@ -65,13 +65,7 @@ WidthIterator::WidthIterator(const Font* font, const TextRun& run)
}
}
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
-#define SIGNAL_ADJUSTED_WIDTHS() adjustedWidths = true
-bool WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
-#else
-#define SIGNAL_ADJUSTED_WIDTHS()
void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
-#endif
{
if (offset > m_end)
offset = m_end;
@@ -85,9 +79,6 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
float runWidthSoFar = m_runWidthSoFar;
float lastRoundingWidth = m_finalRoundingWidth;
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
- bool adjustedWidths = false;
-#endif
while (currentCharacter < offset) {
UChar32 c = *cp;
unsigned clusterLength = 1;
@@ -129,26 +120,21 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
if (c == '\t' && m_run.allowTabs()) {
float tabWidth = m_font->tabWidth();
width = tabWidth - fmodf(m_run.xPos() + runWidthSoFar, tabWidth);
- SIGNAL_ADJUSTED_WIDTHS();
} else {
width = fontData->widthForGlyph(glyph);
-#ifndef ANDROID_NEVER_ROUND_FONT_METRICS
// We special case spaces in two ways when applying word rounding.
// First, we round spaces to an adjusted width in all fonts.
// Second, in fixed-pitch fonts we ensure that all characters that
// match the width of the space character have the same width as the space character.
if (width == fontData->m_spaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding()) {
width = fontData->m_adjustedSpaceWidth;
- SIGNAL_ADJUSTED_WIDTHS();
}
-#endif
}
if (hasExtraSpacing) {
// Account for letter-spacing.
if (width && m_font->letterSpacing()) {
width += m_font->letterSpacing();
- SIGNAL_ADJUSTED_WIDTHS();
}
if (Font::treatAsSpace(c)) {
@@ -163,14 +149,12 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
width += m_padPerSpace;
m_padding -= m_padPerSpace;
}
- SIGNAL_ADJUSTED_WIDTHS();
}
// Account for word spacing.
// We apply additional space between "words" by adding width to the space character.
if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing()) {
width += m_font->wordSpacing();
- SIGNAL_ADJUSTED_WIDTHS();
}
}
}
@@ -186,12 +170,10 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
float oldWidth = width;
-#ifndef ANDROID_NEVER_ROUND_FONT_METRICS
// Force characters that are used to determine word boundaries for the rounding hack
// to be integer width, so following words will start on an integer boundary.
if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c)) {
width = ceilf(width);
- SIGNAL_ADJUSTED_WIDTHS();
}
// Check to see if the next character is a "rounding hack character", if so, adjust
@@ -200,9 +182,7 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
|| (m_run.applyRunRounding() && currentCharacter >= m_end)) {
float totalWidth = runWidthSoFar + width;
width += ceilf(totalWidth) - totalWidth;
- SIGNAL_ADJUSTED_WIDTHS();
}
-#endif
runWidthSoFar += width;
@@ -215,10 +195,6 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
m_currentCharacter = currentCharacter;
m_runWidthSoFar = runWidthSoFar;
m_finalRoundingWidth = lastRoundingWidth;
-
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
- return adjustedWidths;
-#endif
}
bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer)
diff --git a/WebCore/platform/graphics/WidthIterator.h b/WebCore/platform/graphics/WidthIterator.h
index a0eb26d..5706d1e 100644
--- a/WebCore/platform/graphics/WidthIterator.h
+++ b/WebCore/platform/graphics/WidthIterator.h
@@ -33,11 +33,7 @@ class TextRun;
struct WidthIterator {
WidthIterator(const Font*, const TextRun&);
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
- bool advance(int to, GlyphBuffer* = 0);
-#else
void advance(int to, GlyphBuffer* = 0);
-#endif
bool advanceOneCharacter(float& width, GlyphBuffer* = 0);
const Font* m_font;
diff --git a/WebCore/platform/graphics/android/AffineTransformAndroid.cpp b/WebCore/platform/graphics/android/AffineTransformAndroid.cpp
index 6c5abae..712dea5 100644
--- a/WebCore/platform/graphics/android/AffineTransformAndroid.cpp
+++ b/WebCore/platform/graphics/android/AffineTransformAndroid.cpp
@@ -195,8 +195,7 @@ bool AffineTransform::operator==(const AffineTransform &m2) const
AffineTransform &AffineTransform::operator*= (const AffineTransform &m2)
{
- // is this the correct order???
- m_transform.setConcat(m_transform, m2.m_transform);
+ m_transform.setConcat(m2.m_transform, m_transform);
return *this;
}
@@ -204,8 +203,7 @@ AffineTransform AffineTransform::operator* (const AffineTransform &m2)
{
AffineTransform cat;
- // is this the correct order???
- cat.m_transform.setConcat(m_transform, m2.m_transform);
+ cat.m_transform.setConcat(m2.m_transform, m_transform);
return cat;
}
diff --git a/WebCore/platform/graphics/android/FontAndroid.cpp b/WebCore/platform/graphics/android/FontAndroid.cpp
index d53c3ea..569e8db 100644
--- a/WebCore/platform/graphics/android/FontAndroid.cpp
+++ b/WebCore/platform/graphics/android/FontAndroid.cpp
@@ -107,35 +107,31 @@ static bool setupForText(SkPaint* paint, GraphicsContext* gc,
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
const GlyphBuffer& glyphBuffer, int from, int numGlyphs,
const FloatPoint& point) const {
- SkPaint paint;
+ SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
+ SkPaint paint;
if (!setupForText(&paint, gc, font)) {
return;
}
- SkCanvas* canvas = gc->platformContext()->mCanvas;
-
- SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
-
- const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
SkScalar x = SkFloatToScalar(point.x());
SkScalar y = SkFloatToScalar(point.y());
+ const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
+ const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
+ SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
+ SkPoint* pos = storage.get();
+
+ /* We need an array of [x,y,x,y,x,y,...], but webkit is giving us
+ point.xy + [width, height, width, height, ...], so we have to convert
+ */
+ for (int i = 0; i < numGlyphs; i++) {
+ pos[i].set(x, y);
+ x += SkFloatToScalar(adv[i].width());
+ y += SkFloatToScalar(adv[i].height());
+ }
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
- if (glyphBuffer.hasAdjustedWidths()) {
- const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
- SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
- SkPoint* pos = storage.get();
-
- for (int i = 0; i < numGlyphs; i++) {
- pos[i].set(x, y);
- x += SkFloatToScalar(adv[i].width());
- y += SkFloatToScalar(adv[i].height());
- }
- canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
- } else
-#endif
- canvas->drawText(glyphs, numGlyphs << 1, x, y, paint);
+ SkCanvas* canvas = gc->platformContext()->mCanvas;
+ canvas->drawPosText(glyphs, numGlyphs * sizeof(*glyphs), pos, paint);
}
FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int, int) const
diff --git a/WebCore/rendering/RenderImage.cpp b/WebCore/rendering/RenderImage.cpp
index 3a25990..604c407 100644
--- a/WebCore/rendering/RenderImage.cpp
+++ b/WebCore/rendering/RenderImage.cpp
@@ -39,9 +39,6 @@
#ifdef ANDROID_LAYOUT
#include "Settings.h"
#endif
-#ifdef ANDROID_NAVIGATE_AREAMAPS
-#include "HTMLAreaElement.h"
-#endif
#include "SystemTime.h"
@@ -188,11 +185,6 @@ RenderImage::RenderImage(Node* node)
RenderImage::~RenderImage()
{
-#ifdef ANDROID_NAVIGATE_AREAMAPS
- // Set area elements' RenderImage to null, so they do not reference
- // the deleted RenderImage.
- setAreaElements(NULL);
-#endif
if (m_cachedImage)
m_cachedImage->removeClient(this);
RenderImageScaleObserver::imageDestroyed(this);
@@ -598,18 +590,4 @@ Image* RenderImage::nullImage()
return Image::nullImage();
}
-#ifdef ANDROID_NAVIGATE_AREAMAPS
-void RenderImage::setAreaElements(RenderImage* image)
-{
- HTMLMapElement* map = imageMap();
- if (map) {
- for (Node* current = map->firstChild(); current; current = current->traverseNextNode(map)) {
- if (current->hasTagName(WebCore::HTMLNames::areaTag)) {
- HTMLAreaElement* area = static_cast<HTMLAreaElement*>(current);
- area->setMap(image);
- }
- }
- }
-}
-#endif
} // namespace WebCore
diff --git a/WebCore/rendering/RenderImage.h b/WebCore/rendering/RenderImage.h
index 15d7aa1..477fdeb 100644
--- a/WebCore/rendering/RenderImage.h
+++ b/WebCore/rendering/RenderImage.h
@@ -71,15 +71,6 @@ public:
void highQualityRepaintTimerFired(Timer<RenderImage>*);
-#ifdef ANDROID_NAVIGATE_AREAMAPS
- // If this RenderImage has an imagemap, set its area elements to point to it so they
- // can know its bounds for focus navigation and drawing the focus ring.
- void setImageForAreaElements() { setAreaElements(this); }
-private:
- // Helper function, also used to set the area elements to have no RenderImage in the
- // destructor, so they do not reference the deleted image.
- void setAreaElements(RenderImage* image);
-#endif
protected:
virtual Image* image(int w = 0, int h = 0) { return m_cachedImage ? m_cachedImage->image() : nullImage(); }
virtual bool errorOccurred() const { return m_cachedImage && m_cachedImage->errorOccurred(); }
diff --git a/WebCore/rendering/RenderObject.cpp b/WebCore/rendering/RenderObject.cpp
index 8384a98..56fb7df 100644
--- a/WebCore/rendering/RenderObject.cpp
+++ b/WebCore/rendering/RenderObject.cpp
@@ -533,7 +533,12 @@ int RenderObject::offsetTop() const
RenderObject* offsetPar = offsetParent();
if (!offsetPar)
return 0;
+#ifdef ANDROID_FIX
+ // This is to fix https://bugs.webkit.org/show_bug.cgi?id=23178.
+ int y = yPos() - borderTopExtra() + offsetPar->borderTopExtra() - offsetPar->borderTop();
+#else
int y = yPos() - borderTopExtra() - offsetPar->borderTop();
+#endif
if (!isPositioned()) {
if (isRelPositioned())
y += static_cast<const RenderBox*>(this)->relativePositionOffsetY();
diff --git a/WebKit/Android.mk b/WebKit/Android.mk
index ea4abed..14bb359 100644
--- a/WebKit/Android.mk
+++ b/WebKit/Android.mk
@@ -59,4 +59,8 @@ LOCAL_SRC_FILES := \
android/plugins/PluginViewAndroid.cpp \
android/plugins/PluginViewBridgeAndroid.cpp \
android/plugins/PluginWidgetAndroid.cpp \
- android/plugins/SkANP.cpp
+ android/plugins/SkANP.cpp \
+ \
+ android/wds/Command.cpp \
+ android/wds/Connection.cpp \
+ android/wds/DebugServer.cpp
diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp
index 9f55134..a173305 100644
--- a/WebKit/android/jni/WebCoreFrameBridge.cpp
+++ b/WebKit/android/jni/WebCoreFrameBridge.cpp
@@ -70,6 +70,7 @@
#include "WebIconDatabase.h"
#include "WebFrameView.h"
#include "WebViewCore.h"
+#include "wds/DebugServer.h"
#include <runtime_root.h>
#include <runtime_object.h>
@@ -736,6 +737,9 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss
// Create a Frame and the page holds its reference
WebCore::Frame* frame = WebCore::Frame::create(page, NULL, loaderC).get();
loaderC->setFrame(frame);
+#if ENABLE(WDS)
+ WDS::server()->addFrame(frame);
+#endif
// Create a WebViewCore to access the Java WebViewCore associated with this page
WebViewCore* webViewCore = new WebViewCore(env, javaview, frame);
@@ -793,6 +797,9 @@ static void DestroyFrame(JNIEnv* env, jobject obj)
view->deref();
SET_NATIVE_FRAME(env, obj, 0);
+#if ENABLE(WDS)
+ WDS::server()->removeFrame(pFrame);
+#endif
}
static void LoadUrl(JNIEnv *env, jobject obj, jstring url)
diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp
index 363f2be..42a0043 100644
--- a/WebKit/android/jni/WebViewCore.cpp
+++ b/WebKit/android/jni/WebViewCore.cpp
@@ -1156,10 +1156,22 @@ bool WebViewCore::finalKitFocus(WebCore::Frame* frame, WebCore::Node* node,
}
if (!node->isTextNode())
static_cast<WebCore::Element*>(node)->focus(false);
- //setFocus on things that WebCore doesn't recognize as supporting focus
- //for instance, if there is an onclick element that does not support focus
+ if (node->document()->focusedNode() != node) {
+ // This happens when Element::focus() fails as we may try to set the
+ // focus to a node which WebCore doesn't recognize as a focusable node.
+ // So we need to do some extra work, as it does in Element::focus(),
+ // besides calling Document::setFocusedNode.
+ if (oldFocusNode) {
+ // copied from clearSelectionIfNeeded in FocusController.cpp
+ WebCore::SelectionController* s = oldDoc->frame()->selection();
+ if (!s->isNone())
+ s->clear();
+ }
+ //setFocus on things that WebCore doesn't recognize as supporting focus
+ //for instance, if there is an onclick element that does not support focus
+ node->document()->setFocusedNode(node);
+ }
DBG_NAV_LOGD("setFocusedNode node=%p", node);
- node->document()->setFocusedNode(node);
m_lastFocused = node;
m_lastFocusedBounds = node->getRect();
return true;
@@ -1527,7 +1539,7 @@ public:
WebCore::HTMLOptionElement* option;
for (int i = 0; i < count; i++) {
option = static_cast<WebCore::HTMLOptionElement*>(
- m_select->item(array[m_select->listToOptionIndex(i)]));
+ m_select->item(m_select->listToOptionIndex(array[i])));
option->setSelected(true);
}
m_viewImpl->contentInvalidate(m_select->getRect());
@@ -1609,78 +1621,40 @@ void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, s
m_popupReply = reply;
}
-bool WebViewCore::keyUp(KeyCode keyCode, int keyVal)
+bool WebViewCore::key(int keyCode, UChar32 unichar, int repeatCount, bool isShift, bool isAlt, bool isDown)
{
- DBG_NAV_LOGD("keyCode=%d", keyCode);
- bool keyHandled = false;
+ DBG_NAV_LOGD("key: keyCode=%d", keyCode);
+
+ WebCore::EventHandler* eventHandler = m_mainFrame->eventHandler();
WebCore::Node* focusNode = m_mainFrame->getCacheBuilder().currentFocus();
if (focusNode) {
- WebCore::Frame* focusFrame = focusNode->document()->frame();
- switch (keyCode) {
- case kKeyCodeNewline:
- case kKeyCodeDpadCenter: {
- focusFrame->loader()->resetMultipleFormSubmissionProtection();
- WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame);
- webFrame->setUserInitiatedClick(true);
- if ((focusNode->hasTagName(WebCore::HTMLNames::inputTag) &&
- ((WebCore::HTMLInputElement*)focusNode)->isTextField()) ||
- focusNode->hasTagName(WebCore::HTMLNames::textareaTag)) {
- // Create the key down event.
- WebCore::PlatformKeyboardEvent keydown(keyCode, keyVal,
- WebCore::PlatformKeyboardEvent::KeyDown, 0,
- NO_MODIFIER_KEYS);
- // Create the key up event.
- WebCore::PlatformKeyboardEvent keyup(keyCode, keyVal,
- WebCore::PlatformKeyboardEvent::KeyUp, 0,
- NO_MODIFIER_KEYS);
- // Send both events.
- keyHandled = focusFrame->eventHandler()->keyEvent(keydown);
- keyHandled |= focusFrame->eventHandler()->keyEvent(keyup);
- } else {
- keyHandled = handleMouseClick(focusFrame, focusNode);
- }
- webFrame->setUserInitiatedClick(false);
- break;
- }
- default:
- keyHandled = false;
- }
+ eventHandler = focusNode->document()->frame()->eventHandler();
}
- m_blockFocusChange = false;
- return keyHandled;
+
+ int mods = 0; // PlatformKeyboardEvent::ModifierKey
+ if (isShift) {
+ mods |= WebCore::PlatformKeyboardEvent::ShiftKey;
+ }
+ if (isAlt) {
+ mods |= WebCore::PlatformKeyboardEvent::AltKey;
+ }
+ WebCore::PlatformKeyboardEvent evt(keyCode, unichar,
+ isDown ? WebCore::PlatformKeyboardEvent::KeyDown : WebCore::PlatformKeyboardEvent::KeyUp,
+ repeatCount, static_cast<WebCore::PlatformKeyboardEvent::ModifierKey> (mods));
+ return eventHandler->keyEvent(evt);
}
-bool WebViewCore::sendKeyToFocusNode(int keyCode, UChar32 unichar,
- int repeatCount, bool isShift, bool isAlt, KeyAction action) {
+bool WebViewCore::click() {
+ bool keyHandled = false;
WebCore::Node* focusNode = m_mainFrame->getCacheBuilder().currentFocus();
if (focusNode) {
- WebCore::Frame* focusFrame = focusNode->document()->frame();
- WebCore::PlatformKeyboardEvent::Type type;
- switch (action) {
- case DownKeyAction:
- type = WebCore::PlatformKeyboardEvent::KeyDown;
- break;
- case UpKeyAction:
- type = WebCore::PlatformKeyboardEvent::KeyUp;
- break;
- default:
- SkDebugf("---- unexpected KeyAction %d\n", action);
- return false;
- }
-
- int mods = 0; // PlatformKeyboardEvent::ModifierKey
- if (isShift) {
- mods |= WebCore::PlatformKeyboardEvent::ShiftKey;
- }
- if (isAlt) {
- mods |= WebCore::PlatformKeyboardEvent::AltKey;
- }
-
- WebCore::PlatformKeyboardEvent evt(keyCode, unichar, type, repeatCount,
- static_cast<WebCore::PlatformKeyboardEvent::ModifierKey>(mods));
- return focusFrame->eventHandler()->keyEvent(evt);
+ WebFrame::getWebFrame(m_mainFrame)->setUserInitiatedClick(true);
+ keyHandled = handleMouseClick(focusNode->document()->frame(), focusNode);
+ WebFrame::getWebFrame(m_mainFrame)->setUserInitiatedClick(false);
}
- return false;
+ // match in setFinalFocus()
+ m_blockFocusChange = false;
+ return keyHandled;
}
bool WebViewCore::handleTouchEvent(int action, int x, int y)
@@ -2008,29 +1982,27 @@ static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h,
viewImpl->setGlobalBounds(x, y, h, v);
}
-static jboolean KeyUp(JNIEnv *env, jobject obj, jint key, jint val)
+static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar,
+ jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isDown)
{
#ifdef ANDROID_INSTRUMENT
TimeCounterWV counter;
#endif
-// LOGV("webviewcore::nativeKeyUp(%u)\n", (unsigned)key);
WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in nativeKeyUp");
- return viewImpl->keyUp((KeyCode)key, val);
+ LOG_ASSERT(viewImpl, "viewImpl not set in Key");
+
+ return viewImpl->key(keyCode, unichar, repeatCount, isShift, isAlt, isDown);
}
-static bool SendKeyToFocusNode(JNIEnv *env, jobject jwebviewcore,
- jint keyCode, jint unichar, jint repeatCount,
- jboolean isShift, jboolean isAlt, jint action)
+static jboolean Click(JNIEnv *env, jobject obj)
{
#ifdef ANDROID_INSTRUMENT
TimeCounterWV counter;
#endif
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in Click");
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, jwebviewcore);
- LOG_ASSERT(viewImpl, "viewImpl not set in SendKeyToFocusNode");
- return viewImpl->sendKeyToFocusNode((KeyCode)keyCode, unichar, repeatCount,
- isShift, isAlt, static_cast<WebViewCore::KeyAction>(action));
+ return viewImpl->click();
}
static void DeleteSelection(JNIEnv *env, jobject obj,
@@ -2390,9 +2362,10 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
(void*) CopyContentToPicture },
{ "nativeDrawContent", "(Landroid/graphics/Canvas;I)Z",
(void*) DrawContent } ,
- { "nativeKeyUp", "(II)Z",
- (void*) KeyUp },
- { "nativeSendKeyToFocusNode", "(IIIZZI)Z", (void*) SendKeyToFocusNode },
+ { "nativeKey", "(IIIZZZ)Z",
+ (void*) Key },
+ { "nativeClick", "()Z",
+ (void*) Click },
{ "nativeSendListBoxChoices", "([ZI)V",
(void*) SendListBoxChoices },
{ "nativeSendListBoxChoice", "(I)V",
diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h
index 8a073c2..a6c44f8 100644
--- a/WebKit/android/jni/WebViewCore.h
+++ b/WebKit/android/jni/WebViewCore.h
@@ -189,24 +189,15 @@ namespace android {
void setSizeScreenWidthAndScale(int width, int height, int screenWidth, int scale);
/**
- * Handle keyDown events from Java.
- * @param keyCode The key pressed.
+ * Handle key events from Java.
* @return Whether keyCode was handled by this class.
*/
- bool keyUp(KeyCode keyCode, int keyValue);
+ bool key(int keyCode, UChar32 unichar, int repeatCount, bool isShift, bool isAlt, bool isDown);
- // These need to be lock-step with the KEY_ACTION values in
- // WebViewCore.java
- enum KeyAction {
- DownKeyAction = 0,
- UpKeyAction = 1
- };
/**
- * Send the key event to the focus node (if there is one). Return true
- * if there is a node, and it claims to have handled the event.
+ * Handle (mouse) click event from Java
*/
- bool sendKeyToFocusNode(int code, UChar32 unichar, int repeatCount,
- bool isShift, bool isAlt, KeyAction);
+ bool click();
/**
* Handle touch event
diff --git a/WebKit/android/nav/CacheBuilder.cpp b/WebKit/android/nav/CacheBuilder.cpp
index da32898..69d0a06 100644
--- a/WebKit/android/nav/CacheBuilder.cpp
+++ b/WebKit/android/nav/CacheBuilder.cpp
@@ -27,6 +27,7 @@
#include "HTMLAreaElement.h"
#include "HTMLImageElement.h"
#include "HTMLInputElement.h"
+#include "HTMLMapElement.h"
#include "HTMLNames.h"
#include "HTMLOptionElement.h"
#include "HTMLSelectElement.h"
@@ -398,7 +399,7 @@ void CacheBuilder::Debug::groups() {
properties.truncate(properties.length() - 3);
IntRect rect = node->getRect();
if (node->hasTagName(HTMLNames::areaTag))
- rect = static_cast<HTMLAreaElement*>(node)->getAreaRect();
+ rect = Builder(frame)->getAreaRect(static_cast<HTMLAreaElement*>(node));
char buffer[DEBUG_BUFFER_SIZE];
memset(buffer, 0, sizeof(buffer));
mBuffer = buffer;
@@ -1004,12 +1005,20 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
RenderStyle* style = nodeRenderer->style();
if (style->visibility() == HIDDEN)
continue;
-#ifdef ANDROID_NAVIGATE_AREAMAPS
if (nodeRenderer->isImage()) { // set all the area elements to have a link to their images
RenderImage* image = static_cast<RenderImage*>(nodeRenderer);
- image->setImageForAreaElements();
+ HTMLMapElement* map = image->imageMap();
+ if (map) {
+ Node* node;
+ for (node = map->firstChild(); node;
+ node = node->traverseNextNode(map)) {
+ if (!node->hasTagName(HTMLNames::areaTag))
+ continue;
+ HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node);
+ m_areaBoundsMap.set(area, image);
+ }
+ }
}
-#endif
isTransparent = style->hasBackground() == false;
#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
hasFocusRing = style->tapHighlightColor().alpha() > 0;
@@ -1043,10 +1052,9 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
IntRect absBounds;
Node* lastChild = node->lastChild();
WTF::Vector<IntRect>* columns = NULL;
-#ifdef ANDROID_NAVIGATE_AREAMAPS
if (isArea) {
HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node);
- bounds = area->getAreaRect();
+ bounds = getAreaRect(area);
bounds.move(globalOffsetX, globalOffsetY);
absBounds = bounds;
isUnclipped = true; // FIXME: areamaps require more effort to detect
@@ -1054,7 +1062,6 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
takesFocus = true;
goto keepNode;
}
-#endif
if (nodeRenderer == NULL)
continue;
@@ -1183,6 +1190,9 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
if (isFocusable == false) {
if (node->isEventTargetNode() == false)
continue;
+ EventTargetNode* eventTargetNode = (EventTargetNode*) node;
+ if (eventTargetNode->disabled())
+ continue;
bool overOrOut = HasOverOrOut(node);
bool hasTrigger = HasTriggerEvent(node);
if (overOrOut == false && hasTrigger == false)
@@ -1233,9 +1243,6 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
else
clip.intersect(parentClip);
hasClip = true;
- DBG_NAV_LOGD("absBounds={%d,%d,%d,%d} parentClip={%d,%d,%d,%d}\n",
- absBounds.x(), absBounds.y(), absBounds.width(), absBounds.height(),
- parentClip.x(), parentClip.y(), parentClip.width(), parentClip.height());
}
if (hasClip && cachedNode.clip(clip) == false) {
cachedNode.setBounds(clip);
@@ -2365,6 +2372,16 @@ void CacheBuilder::FindResetNumber(FindState* state)
state->mStorePtr = state->mStore;
}
+IntRect CacheBuilder::getAreaRect(const HTMLAreaElement* area) const
+{
+ RenderImage* map = m_areaBoundsMap.get(area);
+ if (!map)
+ return IntRect();
+ if (area->isDefault())
+ return map->absoluteBoundingBoxRect();
+ return area->getRect(map);
+}
+
void CacheBuilder::GetGlobalOffset(Node* node, int* x, int * y)
{
GetGlobalOffset(node->document()->frame(), x, y);
@@ -2459,13 +2476,11 @@ Node* CacheBuilder::findByCenter(int x, int y) const
if (node->isTextNode())
continue;
IntRect bounds;
-#ifdef ANDROID_NAVIGATE_AREAMAPS
if (node->hasTagName(HTMLNames::areaTag)) {
HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node);
- bounds = area->getAreaRect();
+ bounds = getAreaRect(area);
bounds.move(globalOffsetX, globalOffsetY);
} else
-#endif
bounds = node->getRect();
if (bounds.isEmpty())
continue;
@@ -2775,12 +2790,8 @@ bool CacheBuilder::validNode(void* matchFrame, void* matchNode) const
Node* node = frame->document();
while (node != NULL) {
if (node == matchNode) {
-#ifdef ANDROID_NAVIGATE_AREAMAPS
const IntRect& rect = node->hasTagName(HTMLNames::areaTag) ?
- static_cast<HTMLAreaElement*>(node)->getAreaRect() : node->getRect();
-#else
- const IntRect& rect = node->getRect();
-#endif
+ getAreaRect(static_cast<HTMLAreaElement*>(node)) : node->getRect();
// Consider nodes with empty rects that are not at the origin
// to be valid, since news.google.com has valid nodes like this
if (rect.x() == 0 && rect.y() == 0 && rect.isEmpty())
diff --git a/WebKit/android/nav/CacheBuilder.h b/WebKit/android/nav/CacheBuilder.h
index 075042e..4a424a9 100644
--- a/WebKit/android/nav/CacheBuilder.h
+++ b/WebKit/android/nav/CacheBuilder.h
@@ -37,10 +37,12 @@ namespace WebCore {
class Document;
class Frame;
+class HTMLAreaElement;
class InlineTextBox;
class Node;
class PlatformGraphicsContext;
class RenderFlow;
+class RenderImage;
class RenderObject;
class RenderLayer;
class Text;
@@ -193,6 +195,7 @@ private:
static Frame* FrameAnd(CacheBuilder* focusNav);
static Frame* FrameAnd(const CacheBuilder* focusNav);
static CacheBuilder* Builder(Frame* );
+ IntRect getAreaRect(const HTMLAreaElement* area) const;
static Frame* HasFrame(Node* );
static bool HasOverOrOut(Node* );
static bool HasTriggerEvent(Node* );
@@ -208,6 +211,7 @@ private:
Node* mLastKnownFocus;
IntRect mLastKnownFocusBounds;
android::CachedNodeType mAllowableTypes;
+ WTF::HashMap<const HTMLAreaElement* , RenderImage* > m_areaBoundsMap;
#if DUMP_NAV_CACHE
public:
class Debug {
diff --git a/WebKit/android/nav/FindCanvas.cpp b/WebKit/android/nav/FindCanvas.cpp
index 5b6978c..60a7486 100644
--- a/WebKit/android/nav/FindCanvas.cpp
+++ b/WebKit/android/nav/FindCanvas.cpp
@@ -19,6 +19,31 @@
#include "SkRect.h"
+// MatchInfo methods
+////////////////////////////////////////////////////////////////////////////////
+
+MatchInfo::MatchInfo() {
+ m_picture = 0;
+}
+
+MatchInfo::~MatchInfo() {
+ m_picture->safeUnref();
+}
+
+MatchInfo::MatchInfo(const MatchInfo& src) {
+ m_location = src.m_location;
+ m_picture = src.m_picture;
+ m_picture->safeRef();
+}
+
+void MatchInfo::set(const SkRegion& region, SkPicture* pic) {
+ m_picture->safeUnref();
+ m_location = region;
+ m_picture = pic;
+ SkASSERT(pic);
+ pic->ref();
+}
+
// GlyphSet methods
////////////////////////////////////////////////////////////////////////////////
@@ -81,33 +106,17 @@ FindCanvas::FindCanvas(int width, int height, const UChar* lower,
setBounder(&mBounder);
mOutset = -SkIntToScalar(2);
- mRegions = new WTF::Vector<SkRegion>();
-#if RECORD_MATCHES
- mPicture = new SkPicture();
- mRecordingCanvas = mPicture->beginRecording(width, height);
-#endif
+ mMatches = new WTF::Vector<MatchInfo>();
mWorkingIndex = 0;
+ mWorkingCanvas = 0;
+ mWorkingPicture = 0;
}
FindCanvas::~FindCanvas() {
setBounder(NULL);
/* Just in case getAndClear was not called. */
- delete mRegions;
-#if RECORD_MATCHES
- mPicture->unref();
-#endif
-}
-
-// SkPaint.measureText is used to get a rectangle surrounding the specified
-// text. It is a tighter bounds than we want. We want the height to account
-// for the ascent and descent of the font, so that the rectangles will line up,
-// regardless of the characters contained in them.
-static void correctSize(const SkPaint& paint, SkRect& rect)
-{
- SkPaint::FontMetrics fontMetrics;
- paint.getFontMetrics(&fontMetrics);
- rect.fTop = fontMetrics.fAscent;
- rect.fBottom = fontMetrics.fDescent;
+ delete mMatches;
+ mWorkingPicture->safeUnref();
}
// Each version of addMatch returns a rectangle for a match.
@@ -117,21 +126,24 @@ SkRect FindCanvas::addMatchNormal(int index,
const SkScalar pos[], SkScalar y) {
const uint16_t* lineStart = glyphs - index;
/* Use the original paint, since "text" is in glyphs */
- SkScalar before = paint.measureText(lineStart, index * sizeof(uint16_t),
- NULL);
+ SkScalar before = paint.measureText(lineStart, index * sizeof(uint16_t), 0);
SkRect rect;
- int countInBytes = count << 1;
- paint.measureText(glyphs, countInBytes, &rect);
- correctSize(paint, rect);
- rect.offset(pos[0] + before, y);
- getTotalMatrix().mapRect(&rect);
+ rect.fLeft = pos[0] + before;
+ int countInBytes = count * sizeof(uint16_t);
+ rect.fRight = paint.measureText(glyphs, countInBytes, 0) + rect.fLeft;
+ SkPaint::FontMetrics fontMetrics;
+ paint.getFontMetrics(&fontMetrics);
+ SkScalar baseline = y;
+ rect.fTop = baseline + fontMetrics.fAscent;
+ rect.fBottom = baseline + fontMetrics.fDescent;
+ const SkMatrix& matrix = getTotalMatrix();
+ matrix.mapRect(&rect);
// Add the text to our picture.
-#if RECORD_MATCHES
- mRecordingCanvas->setMatrix(getTotalMatrix());
- SkPoint point;
- matrix.mapXY(pos[0] + before, y, &point);
- mRecordingCanvas->drawText(glyphs, countInBytes, point.fX, point.fY, paint);
-#endif
+ SkCanvas* canvas = getWorkingCanvas();
+ int saveCount = canvas->save();
+ canvas->concat(matrix);
+ canvas->drawText(glyphs, countInBytes, pos[0] + before, y, paint);
+ canvas->restoreToCount(saveCount);
return rect;
}
@@ -140,27 +152,31 @@ SkRect FindCanvas::addMatchPos(int index,
const SkScalar xPos[], SkScalar /* y */) {
SkRect r;
r.setEmpty();
- const SkScalar* pos = &xPos[index << 1];
- int countInBytes = count << 1;
+ const SkPoint* temp = reinterpret_cast<const SkPoint*> (xPos);
+ const SkPoint* points = &temp[index];
+ int countInBytes = count * sizeof(uint16_t);
SkPaint::FontMetrics fontMetrics;
paint.getFontMetrics(&fontMetrics);
- for (int j = 0; j < countInBytes; j += 2) {
+ // Need to check each character individually, since the heights may be
+ // different.
+ for (int j = 0; j < count; j++) {
SkRect bounds;
- paint.getTextWidths(&(glyphs[j >> 1]), 2, NULL, &bounds);
- bounds.fTop = fontMetrics.fAscent;
- bounds.fBottom = fontMetrics.fDescent;
- bounds.offset(pos[j], pos[j+1]);
- /* Accumulate and then add the resulting rect to mRegions */
+ bounds.fLeft = points[j].fX;
+ bounds.fRight = bounds.fLeft +
+ paint.measureText(&glyphs[j], sizeof(uint16_t), 0);
+ SkScalar baseline = points[j].fY;
+ bounds.fTop = baseline + fontMetrics.fAscent;
+ bounds.fBottom = baseline + fontMetrics.fDescent;
+ /* Accumulate and then add the resulting rect to mMatches */
r.join(bounds);
}
- getTotalMatrix().mapRect(&r);
- // Add the text to our picture.
-#if RECORD_MATCHES
- mRecordingCanvas->setMatrix(getTotalMatrix());
- // FIXME: Need to do more work to get xPos and constY in the proper
- // coordinates.
- //mRecordingCanvas->drawPosText(glyphs, countInBytes, positions, paint);
-#endif
+ SkMatrix matrix = getTotalMatrix();
+ matrix.mapRect(&r);
+ SkCanvas* canvas = getWorkingCanvas();
+ int saveCount = canvas->save();
+ canvas->concat(matrix);
+ canvas->drawPosText(glyphs, countInBytes, points, paint);
+ canvas->restoreToCount(saveCount);
return r;
}
@@ -168,24 +184,28 @@ SkRect FindCanvas::addMatchPosH(int index,
const SkPaint& paint, int count, const uint16_t* glyphs,
const SkScalar position[], SkScalar constY) {
SkRect r;
- r.setEmpty();
+ // We only care about the positions starting at the index of our match
const SkScalar* xPos = &position[index];
- for (int j = 0; j < count; j++) {
- SkRect bounds;
- paint.getTextWidths(&glyphs[j], 1, NULL, &bounds);
- bounds.offset(xPos[j], constY);
- /* Accumulate and then add the resulting rect to mRegions */
- r.join(bounds);
- }
- correctSize(paint, r);
- getTotalMatrix().mapRect(&r);
- // Add the text to our picture.
-#if RECORD_MATCHES
- mRecordingCanvas->setMatrix(getTotalMatrix());
- // FIXME: Need to do more work to get xPos and constY in the proper
- // coordinates.
- //mRecordingCanvas->drawPosTextH(glyphs, count << 1, xPos, constY, paint);
-#endif
+ // This assumes that the position array is monotonic increasing
+ // The left bounds will be the position of the left most character
+ r.fLeft = xPos[0];
+ // The right bounds will be the position of the last character plus its
+ // width
+ int lastIndex = count - 1;
+ r.fRight = paint.measureText(&glyphs[lastIndex], sizeof(uint16_t), 0)
+ + xPos[lastIndex];
+ // Grab font metrics to determine the top and bottom of the bounds
+ SkPaint::FontMetrics fontMetrics;
+ paint.getFontMetrics(&fontMetrics);
+ r.fTop = constY + fontMetrics.fAscent;
+ r.fBottom = constY + fontMetrics.fDescent;
+ const SkMatrix& matrix = getTotalMatrix();
+ matrix.mapRect(&r);
+ SkCanvas* canvas = getWorkingCanvas();
+ int saveCount = canvas->save();
+ canvas->concat(matrix);
+ canvas->drawPosTextH(glyphs, count * sizeof(uint16_t), xPos, constY, paint);
+ canvas->restoreToCount(saveCount);
return r;
}
@@ -236,10 +256,7 @@ void FindCanvas::findHelper(const void* text, size_t byteLength,
const uint16_t* glyphs,
const SkScalar positions[], SkScalar y)) {
SkASSERT(paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
- SkASSERT(mRegions);
-#if RECORD_MATCHES
- SkASSERT(mRecordingCanvas);
-#endif
+ SkASSERT(mMatches);
GlyphSet* glyphSet = getGlyphs(paint);
const int count = glyphSet->getCount();
int numCharacters = byteLength >> 1;
@@ -249,7 +266,8 @@ void FindCanvas::findHelper(const void* text, size_t byteLength,
if (mWorkingIndex) {
SkPoint newY;
getTotalMatrix().mapXY(0, y, &newY);
- if (mWorkingRegion.getBounds().fBottom < SkScalarRound(newY.fY)) {
+ SkIRect bounds = mWorkingRegion.getBounds();
+ if (bounds.fBottom < SkScalarRound(newY.fY)) {
// Now we know that this line is lower than our partial match.
SkPaint clonePaint(paint);
clonePaint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
@@ -260,14 +278,16 @@ void FindCanvas::findHelper(const void* text, size_t byteLength,
if (mWorkingIndex == count) {
// We already know that it is not clipped out because we
// checked for that before saving the working region.
- mNumFound++;
- mRegions->append(mWorkingRegion);
+ insertMatchInfo(mWorkingRegion);
+
+ resetWorkingCanvas();
mWorkingIndex = 0;
mWorkingRegion.setEmpty();
// We have found a match, so continue on this line from
// scratch.
}
} else {
+ resetWorkingCanvas();
mWorkingIndex = 0;
mWorkingRegion.setEmpty();
}
@@ -288,7 +308,6 @@ void FindCanvas::findHelper(const void* text, size_t byteLength,
}
// The last count characters match, so we found the entire
// search string.
- mNumFound++;
int remaining = count - mWorkingIndex;
int matchIndex = index - remaining + 1;
// Set up a pointer to the matching text in 'chars'.
@@ -325,7 +344,7 @@ void FindCanvas::findHelper(const void* text, size_t byteLength,
// the previous line(s).
regionToAdd.op(mWorkingRegion, SkRegion::kUnion_Op);
}
- mRegions->append(regionToAdd);
+ insertMatchInfo(regionToAdd);
#if INCLUDE_SUBSTRING_MATCHES
// Reset index to the location of the match and reset j to the
// beginning, so that on the next iteration of the loop, index
@@ -338,6 +357,9 @@ void FindCanvas::findHelper(const void* text, size_t byteLength,
// character from our hidden match
index = matchIndex;
}
+ // Whether the clip contained it or not, we need to start over
+ // with our recording canvas
+ resetWorkingCanvas();
} else {
// Index needs to be set to index - j + 1.
// This is a ridiculous case, but imagine the situation where the
@@ -389,6 +411,14 @@ void FindCanvas::findHelper(const void* text, size_t byteLength,
mWorkingIndex = 0;
}
+SkCanvas* FindCanvas::getWorkingCanvas() {
+ if (!mWorkingPicture) {
+ mWorkingPicture = new SkPicture;
+ mWorkingCanvas = mWorkingPicture->beginRecording(0,0);
+ }
+ return mWorkingCanvas;
+}
+
GlyphSet* FindCanvas::getGlyphs(const SkPaint& paint) {
SkTypeface* typeface = paint.getTypeface();
GlyphSet* end = mGlyphSets.end();
@@ -402,3 +432,18 @@ GlyphSet* FindCanvas::getGlyphs(const SkPaint& paint) {
*mGlyphSets.append() = set;
return &(mGlyphSets.top());
}
+
+void FindCanvas::insertMatchInfo(const SkRegion& region) {
+ mNumFound++;
+ mWorkingPicture->endRecording();
+ MatchInfo matchInfo;
+ mMatches->append(matchInfo);
+ mMatches->last().set(region, mWorkingPicture);
+}
+
+void FindCanvas::resetWorkingCanvas() {
+ mWorkingPicture->unref();
+ mWorkingPicture = 0;
+ // Do not need to reset mWorkingCanvas itself because we only access it via
+ // getWorkingCanvas.
+}
diff --git a/WebKit/android/nav/FindCanvas.h b/WebKit/android/nav/FindCanvas.h
index fe1e3d2..5558c8b 100644
--- a/WebKit/android/nav/FindCanvas.h
+++ b/WebKit/android/nav/FindCanvas.h
@@ -17,23 +17,37 @@
#ifndef Find_Canvas_h
#define Find_Canvas_h
-// The code marked with this is used to record the draw calls into an SkPicture,
-// which is passed to the caller to draw the matches on top of the opaque green
-// rectangles. The code is a checkpoint.
-#define RECORD_MATCHES 0
-
#include "SkBounder.h"
#include "SkCanvas.h"
+#include "SkPicture.h"
#include "SkRegion.h"
#include "SkTDArray.h"
#include "icu/unicode/umachine.h"
-#if RECORD_MATCHES
-class SkPicture;
-#endif
class SkRect;
class SkTypeface;
+// Stores both region information and an SkPicture of the match, so that the
+// region can be drawn, followed by drawing the matching text on top of it.
+// This class owns its SkPicture
+class MatchInfo {
+public:
+ MatchInfo();
+ ~MatchInfo();
+ MatchInfo(const MatchInfo& src);
+ const SkRegion& getLocation() const { return m_location; }
+ // Return a pointer to our picture, representing the matching text. Does
+ // not transfer ownership of the picture.
+ SkPicture* getPicture() const { return m_picture; }
+ // This will make a copy of the region, and increase the ref count on the
+ // SkPicture. If this MatchInfo already had one, unref it.
+ void set(const SkRegion& region, SkPicture* pic);
+private:
+ MatchInfo& operator=(MatchInfo& src);
+ SkRegion m_location;
+ SkPicture* m_picture;
+};
+
// A class containing a typeface for reference, the length in glyphs, and
// the upper and lower case representations of the search string.
class GlyphSet {
@@ -113,20 +127,14 @@ public:
int found() const { return mNumFound; }
- // This method detaches our array of regions and passes ownership to
+ // This method detaches our array of matches and passes ownership to
// the caller, who is then responsible for deleting them.
- WTF::Vector<SkRegion>* detachRegions() {
- WTF::Vector<SkRegion>* array = mRegions;
- mRegions = NULL;
+ WTF::Vector<MatchInfo>* detachMatches() {
+ WTF::Vector<MatchInfo>* array = mMatches;
+ mMatches = NULL;
return array;
}
-#if RECORD_MATCHES
- // This SkPicture contains only draw calls for the drawn text. This is
- // used to draw over the highlight rectangle so that it can be seen.
- SkPicture* getDrawnMatches() const { return mPicture; }
-#endif
-
private:
// These calls are made by findHelper to store information about each match
// that is found. They return a rectangle which is used to highlight the
@@ -144,7 +152,7 @@ private:
SkRect addMatchPosH(int index,
const SkPaint& paint, int count, const uint16_t* glyphs,
const SkScalar position[], SkScalar constY);
-
+
// Helper for each of our draw calls
void findHelper(const void* text, size_t byteLength, const SkPaint& paint,
const SkScalar xPos[], SkScalar y,
@@ -152,14 +160,25 @@ private:
const SkPaint& paint, int count, const uint16_t* glyphs,
const SkScalar pos[], SkScalar y));
+ // If we already have a working canvas, grab it. Otherwise, create a new
+ // one.
+ SkCanvas* getWorkingCanvas();
+
// Return the set of glyphs and its count for the text being searched for
// and the parameter paint. If one has already been created and cached
// for this paint, use it. If not, create a new one and cache it.
GlyphSet* getGlyphs(const SkPaint& paint);
+ // Store all the accumulated info about a match in our vector.
+ void insertMatchInfo(const SkRegion& region);
+
+ // Throw away our cumulative information about our working SkCanvas. After
+ // this call, next call to getWorkingCanvas will create a new one.
+ void resetWorkingCanvas();
+
// Since we may transfer ownership of this array (see detachRects()), we
// hold a pointer to the array instead of just the array itself.
- WTF::Vector<SkRegion>* mRegions;
+ WTF::Vector<MatchInfo>* mMatches;
const UChar* mLowerText;
const UChar* mUpperText;
size_t mLength;
@@ -167,11 +186,9 @@ private:
int mNumFound;
SkScalar mOutset;
SkTDArray<GlyphSet> mGlyphSets;
-#if RECORD_MATCHES
- SkPicture* mPicture;
- SkCanvas* mRecordingCanvas;
-#endif
+ SkPicture* mWorkingPicture;
+ SkCanvas* mWorkingCanvas;
SkRegion mWorkingRegion;
int mWorkingIndex;
};
diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp
index 7af96d7..63c6aeb 100644
--- a/WebKit/android/nav/WebView.cpp
+++ b/WebKit/android/nav/WebView.cpp
@@ -419,10 +419,6 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl)
m_matches = 0;
m_hasCurrentLocation = false;
m_isFindPaintSetUp = false;
-// RECORD_MATCHES is defined in FindCanvas.h
-#if RECORD_MATCHES
- m_matchesPicture = 0;
-#endif
}
~WebView()
@@ -437,10 +433,6 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl)
delete m_navPictureUI;
if (m_matches)
delete m_matches;
-// RECORD_MATCHES is defined in FindCanvas.h
-#if RECORD_MATCHES
- m_matchesPicture->safeUnref();
-#endif
}
void clearFocus(int x, int y, bool inval)
@@ -548,9 +540,7 @@ void setUpFindPaint()
const SkScalar roundiness = SkIntToScalar(2);
SkCornerPathEffect* cornerEffect = new SkCornerPathEffect(roundiness);
m_findPaint.setPathEffect(cornerEffect);
- // FIXME: Would like this to be opaque, but then the user cannot see the
- // text behind it. We will then need to redraw the text on top of it.
- m_findPaint.setARGB(204, 132, 190, 0);
+ m_findPaint.setARGB(255, 132, 190, 0);
// Set up the background blur paint.
m_findBlurPaint.setAntiAlias(true);
@@ -583,26 +573,34 @@ void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused)
// Offset the path for a blurred shadow
SkPath blurPath;
matchPath.offset(SK_Scalar1, SkIntToScalar(2), &blurPath);
+ int saveCount = 0;
+ if (!focused) {
+ saveCount = canvas->save();
+ canvas->clipPath(matchPath, SkRegion::kDifference_Op);
+ }
// Draw the blurred background
canvas->drawPath(blurPath, m_findBlurPaint);
+ if (!focused) {
+ canvas->restoreToCount(saveCount);
+ }
// Draw the foreground
canvas->drawPath(matchPath, m_findPaint);
}
+// Put a cap on the number of matches to draw. If the current page has more
+// matches than this, only draw the focused match.
+#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101
+
void drawMatches(SkCanvas* canvas)
{
- if (!m_matches || !m_matches->size()
-// RECORD_MATCHES is defined in FindCanvas.h
-#if RECORD_MATCHES
- || !m_matchesPicture
-#endif
- ) {
+ if (!m_matches || !m_matches->size()) {
return;
}
if (m_findIndex >= m_matches->size()) {
m_findIndex = 0;
}
- const SkRegion& currentMatchRegion = (*m_matches)[m_findIndex];
+ const MatchInfo& matchInfo = (*m_matches)[m_findIndex];
+ const SkRegion& currentMatchRegion = matchInfo.getLocation();
const SkIRect& currentMatchBounds = currentMatchRegion.getBounds();
int left = currentMatchBounds.fLeft;
int top = currentMatchBounds.fTop;
@@ -636,36 +634,29 @@ void drawMatches(SkCanvas* canvas)
setUpFindPaint();
// Draw the current match
- drawMatch(currentMatchRegion, canvas, true);
+ drawMatch(currentMatchRegion, canvas, true);
+ // Now draw the picture, so that it shows up on top of the rectangle
+ canvas->drawPicture(*matchInfo.getPicture());
// Draw the rest
unsigned numberOfMatches = m_matches->size();
- int saveCount = 0;
- if (numberOfMatches > 1) {
+ if (numberOfMatches > 1
+ && numberOfMatches < MAX_NUMBER_OF_MATCHES_TO_DRAW) {
+ SkIRect visibleIRect;
+ android_setrect(&visibleIRect, visible);
for(unsigned i = 0; i < numberOfMatches; i++) {
// The current match has already been drawn
if (i == m_findIndex)
continue;
- const SkRegion& region = (*m_matches)[i];
- // Do not draw matches which intersect the current one
- if (currentMatchRegion.intersects(region))
+ const SkRegion& region = (*m_matches)[i].getLocation();
+ // Do not draw matches which intersect the current one, or if it is
+ // offscreen
+ if (currentMatchRegion.intersects(region)
+ || !region.intersects(visibleIRect))
continue;
drawMatch(region, canvas, false);
}
-// RECORD_MATCHES is defined in FindCanvas.h
-#if RECORD_MATCHES
- // Set a clip so we do not draw the text for the other matches.
- saveCount = canvas->save(SkCanvas::kClip_SaveFlag);
- canvas->clipRect(currentMatch);
-#endif
}
-// RECORD_MATCHES is defined in FindCanvas.h
-#if RECORD_MATCHES
- canvas->drawPicture(*m_matchesPicture);
- if (numberOfMatches > 1) {
- canvas->restoreToCount(saveCount);
- }
-#endif
}
void drawFocusRing(SkCanvas* canvas)
@@ -1112,6 +1103,18 @@ bool moveFocus(int keyCode, int count, bool ignoreScroll, bool inval,
void notifyFocusSet(FrameCachePermission inEditingMode)
{
+ CachedRoot* root = getFrameCache(DontAllowNewer);
+ if (root) {
+ // make sure the mFocusData in WebView.java is in sync with WebView.cpp
+ const CachedFrame* frame = 0;
+ const CachedNode* node = root->currentFocus(&frame);
+ const WebCore::IntPoint& focusLocation = root->focusLocation();
+ setFocusData(root->generation(),
+ frame ? (WebCore::Frame*) frame->framePointer() : 0,
+ node ? (WebCore::Node*) node->nodePointer() : 0,
+ focusLocation.x(), focusLocation.y(), false);
+ }
+
if (focusIsTextArea(inEditingMode))
updateTextEntry();
else if (inEditingMode)
@@ -1608,8 +1611,8 @@ void setFocusData(int buildGeneration, WebCore::Frame* framePtr,
// m_currentMatchLocation.
void inline storeCurrentMatchLocation()
{
- SkASSERT(m_findIndex < m_matches->size() && m_findIndex >= 0);
- const SkIRect& bounds = (*m_matches)[m_findIndex].getBounds();
+ SkASSERT(m_findIndex < m_matches->size());
+ const SkIRect& bounds = (*m_matches)[m_findIndex].getLocation().getBounds();
m_currentMatchLocation.set(bounds.fLeft, bounds.fTop);
m_hasCurrentLocation = true;
}
@@ -1635,12 +1638,7 @@ void findNext(bool forward)
// With this call, WebView takes ownership of matches, and is responsible for
// deleting it.
-void setMatches(WTF::Vector<SkRegion>* matches
-// RECORD_MATCHES is defined in FindCanvas.h
-#if RECORD_MATCHES
- , SkPicture* pic
-#endif
- )
+void setMatches(WTF::Vector<MatchInfo>* matches)
{
if (m_matches)
delete m_matches;
@@ -1648,7 +1646,7 @@ void setMatches(WTF::Vector<SkRegion>* matches
if (m_matches->size()) {
if (m_hasCurrentLocation) {
for (unsigned i = 0; i < m_matches->size(); i++) {
- const SkIRect& rect = (*m_matches)[i].getBounds();
+ const SkIRect& rect = (*m_matches)[i].getLocation().getBounds();
if (rect.fLeft == m_currentMatchLocation.fX
&& rect.fTop == m_currentMatchLocation.fY) {
m_findIndex = i;
@@ -1664,12 +1662,6 @@ void setMatches(WTF::Vector<SkRegion>* matches
} else {
m_hasCurrentLocation = false;
}
-// RECORD_MATCHES is defined in FindCanvas.h
-#if RECORD_MATCHES
- m_matchesPicture->safeUnref();
- m_matchesPicture = pic;
- m_matchesPicture->ref();
-#endif
viewInvalidate();
}
@@ -1778,7 +1770,7 @@ private: // local state for WebView
bool m_heightCanMeasure;
int m_lastDx;
SkMSec m_lastDxTime;
- WTF::Vector<SkRegion>* m_matches;
+ WTF::Vector<MatchInfo>* m_matches;
// Stores the location of the current match.
SkIPoint m_currentMatchLocation;
// Tells whether the value in m_currentMatchLocation is valid.
@@ -1789,10 +1781,6 @@ private: // local state for WebView
SkPaint m_findPaint;
// Paint used for the background of our Find matches.
SkPaint m_findBlurPaint;
-// RECORD_MATCHES is defined in FindCanvas.h
-#if RECORD_MATCHES
- SkPicture* m_matchesPicture;
-#endif
unsigned m_findIndex;
}; // end of WebView class
@@ -2096,14 +2084,9 @@ static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
canvas.setBitmapDevice(bitmap);
canvas.drawPicture(*(root->getPicture()));
- WTF::Vector<SkRegion>* matches = canvas.detachRegions();
+ WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
// With setMatches, the WebView takes ownership of matches
- view->setMatches(matches
-// RECORD_MATCHES is defined in FindCanvas.h
-#if RECORD_MATCHES
- , canvas.getDrawnMatches()
-#endif
- );
+ view->setMatches(matches);
env->ReleaseStringChars(findLower, findLowerChars);
env->ReleaseStringChars(findUpper, findUpperChars);
diff --git a/WebKit/android/plugins/sample/main.cpp b/WebKit/android/plugins/sample/main.cpp
index 5d2b0b8..5bb8ea0 100644
--- a/WebKit/android/plugins/sample/main.cpp
+++ b/WebKit/android/plugins/sample/main.cpp
@@ -349,6 +349,7 @@ int16 NPP_HandleEvent(NPP instance, void* event)
evt->data.key.modifiers);
if (evt->data.key.action == kDown_ANPKeyAction) {
obj->mUnichar = evt->data.key.unichar;
+ browser->invalidaterect(instance, NULL);
}
return 1;
diff --git a/WebKit/android/wds/Command.cpp b/WebKit/android/wds/Command.cpp
new file mode 100644
index 0000000..132b8e5
--- /dev/null
+++ b/WebKit/android/wds/Command.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "wds"
+#include "config.h"
+
+#include "AndroidLog.h"
+#include "CString.h"
+#include "Command.h"
+#include "Connection.h"
+#include "DebugServer.h"
+#include "Frame.h"
+#include "RenderTreeAsText.h"
+#include "RenderView.h"
+#include "WebViewCore.h"
+#include <utils/Log.h>
+
+#if ENABLE(WDS)
+
+using namespace WebCore;
+
+namespace android {
+
+namespace WDS {
+
+//------------------------------------------------------------------------------
+// Actual commands -- XXX should be moved somewhere else
+//------------------------------------------------------------------------------
+static bool callDumpRenderTree(const Frame* frame, const Connection* conn) {
+ CString str = externalRepresentation(frame->contentRenderer()).latin1();
+ conn->write(str.data(), str.length());
+ return true;
+}
+
+static bool callDumpDomTree(const Frame* frame, const Connection* conn) {
+ WebViewCore::getWebViewCore(frame->view())->dumpDomTree(true);
+
+ FILE* f = fopen(DOM_TREE_LOG_FILE, "r");
+ if (!f) {
+ conn->write("Dom tree written to logcat\n");
+ } else {
+ char buf[512];
+ while (true) {
+ int nread = fread(buf, 1, sizeof(buf), f);
+ if (nread <= 0)
+ break;
+ conn->write(buf, nread);
+ }
+ fclose(f);
+ }
+ return true;
+}
+
+class WebCoreHandler : public Handler {
+public:
+ virtual void post(TargetThreadFunction func, void* v) const {
+ callOnMainThread(func, v);
+ }
+};
+static WebCoreHandler s_webcoreHandler;
+
+//------------------------------------------------------------------------------
+// End command section
+//------------------------------------------------------------------------------
+
+class InternalCommand : public Command {
+public:
+ InternalCommand(const Command* comm, const Frame* frame,
+ const Connection* connection)
+ : Command(*comm)
+ , m_frame(frame)
+ , m_connection(connection) {}
+ virtual ~InternalCommand() { delete m_connection; }
+
+ void doCommand() const {
+ LOGD("Executing command '%s' (%s)", m_name, m_description);
+ if (!m_dispatch(m_frame, m_connection))
+ // XXX: Have useful failure messages
+ m_connection->write("EPIC FAIL!\n", 11);
+ }
+
+private:
+ const Frame* m_frame;
+ const Connection* m_connection;
+};
+
+static void commandDispatcher(void* v) {
+ InternalCommand* c = static_cast<InternalCommand*>(v);
+ c->doCommand();
+ delete c;
+}
+
+void Command::dispatch() {
+ m_handler.post(commandDispatcher, this);
+}
+
+Vector<const Command*>* Command::s_commands;
+
+void Command::Init() {
+ // Do not initialize twice.
+ if (s_commands)
+ return;
+ // XXX: Move this somewhere else.
+ s_commands = new Vector<const Command*>();
+ s_commands->append(new Command("DDOM", "Dump Dom Tree",
+ callDumpDomTree, s_webcoreHandler));
+ s_commands->append(new Command("DDRT", "Dump Render Tree",
+ callDumpRenderTree, s_webcoreHandler));
+}
+
+Command* Command::Find(const Connection* conn) {
+ char buf[COMMAND_LENGTH];
+ if (conn->read(buf, sizeof(buf)) != COMMAND_LENGTH)
+ return NULL;
+
+ // Linear search of commands. TODO: binary search when more commands are
+ // added.
+ Vector<const Command*>::const_iterator i = s_commands->begin();
+ Vector<const Command*>::const_iterator end = s_commands->end();
+ while (i != end) {
+ if (strncmp(buf, (*i)->name(), sizeof(buf)) == 0)
+ return new InternalCommand(*i, server()->getFrame(0), conn);
+ i++;
+ }
+ return NULL;
+}
+
+} // end namespace WDS
+
+} // end namespace android
+
+#endif
diff --git a/WebKit/android/wds/Command.h b/WebKit/android/wds/Command.h
new file mode 100644
index 0000000..df45b2b
--- /dev/null
+++ b/WebKit/android/wds/Command.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WDS_COMMAND_H
+#define WDS_COMMAND_H
+
+#include "wtf/MainThread.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+class Frame;
+}
+
+using namespace WTF;
+using namespace WebCore;
+
+namespace android {
+
+// WebCore Debug Server
+namespace WDS {
+
+class Connection;
+
+// Command identifier length
+#define COMMAND_LENGTH 4
+
+// The dispatcher function called with a Frame for context and the established
+// connection to the client. The connection can be used to read and write to the
+// client application. Return true on successful completion of the command,
+// return false to indicate failure.
+typedef bool (*DispatchFunction)(const Frame*, const Connection*);
+
+// Note: Although the type is named MainThreadFunction, it may not always be
+// the main thread. The type is generic enough to reuse here but named
+// something more appropriate.
+typedef MainThreadFunction TargetThreadFunction;
+
+// Helper class to dipatch functions on a particular thread.
+class Handler {
+public:
+ virtual ~Handler() {}
+ virtual void post(TargetThreadFunction, void*) const = 0;
+};
+
+// Class for containing information about particular commands.
+class Command {
+public:
+ Command(const char* name, const char* desc, const DispatchFunction func,
+ const Handler& handler)
+ : m_name(name)
+ , m_description(desc)
+ , m_dispatch(func)
+ , m_handler(handler) {}
+ Command(const Command& comm)
+ : m_name(comm.m_name)
+ , m_description(comm.m_description)
+ , m_dispatch(comm.m_dispatch)
+ , m_handler(comm.m_handler) {}
+ virtual ~Command() {}
+
+ // Initialize the debug server commands
+ static void Init();
+
+ // Find the command specified by the client request.
+ static Command* Find(const Connection* conn);
+
+ // Dispatch this command
+ void dispatch();
+
+ const char* name() const { return m_name; }
+
+protected:
+ const char* m_name;
+ const char* m_description;
+ const DispatchFunction m_dispatch;
+
+private:
+ const Handler& m_handler;
+ static Vector<const Command*>* s_commands;
+};
+
+} // end namespace WDS
+
+} // end namespace android
+
+#endif
diff --git a/WebKit/android/wds/Connection.cpp b/WebKit/android/wds/Connection.cpp
new file mode 100644
index 0000000..b6ebd75
--- /dev/null
+++ b/WebKit/android/wds/Connection.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "wds"
+#include "config.h"
+
+#include "DebugServer.h" // used for ENABLE_WDS
+#include "Connection.h"
+#include <arpa/inet.h>
+#include <string.h>
+#include <utils/Log.h>
+
+#if ENABLE(WDS)
+
+#define MAX_CONNECTION_QUEUE 5
+#define log_errno(x) LOGE("%s: %d", x, strerror(errno))
+
+namespace android {
+
+namespace WDS {
+
+bool Socket::open() {
+ m_fd = socket(PF_INET, SOCK_STREAM, 0);
+ if (m_fd < 0) {
+ log_errno("Failed to create file descriptor");
+ return false;
+ }
+ return true;
+}
+
+bool ConnectionServer::connect(short port) {
+ if (!m_socket.open())
+ return false;
+ int fd = m_socket.fd();
+
+ // Build our sockaddr_in structure use to listen to incoming connections
+ sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_port = htons(port);
+
+ // Try to bind to the given port
+ if (bind(fd, (sockaddr*) &addr, sizeof(addr)) < 0) {
+ log_errno("Failed to bind to local host");
+ return false;
+ }
+
+ // Try to listen
+ if (listen(fd, MAX_CONNECTION_QUEUE) < 0) {
+ log_errno("Failed to listen");
+ return false;
+ }
+
+ return true;
+}
+
+Connection* ConnectionServer::accept() const {
+ int conn = ::accept(m_socket.fd(), NULL, NULL);
+ if (conn < 0) {
+ log_errno("Accept failed");
+ return NULL;
+ }
+ return new Connection(conn);
+}
+
+} // end namespace WDS
+
+} // end namespace android
+
+#endif
diff --git a/WebKit/android/wds/Connection.h b/WebKit/android/wds/Connection.h
new file mode 100644
index 0000000..f7fa21b
--- /dev/null
+++ b/WebKit/android/wds/Connection.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WDS_CONNECTION_H
+#define WDS_CONNECTION_H
+
+#include <sys/socket.h>
+
+namespace android {
+
+namespace WDS {
+
+class Socket {
+public:
+ Socket(): m_fd(-1) {}
+ Socket(int fd): m_fd(fd) {}
+ ~Socket() {
+ if (m_fd != -1) {
+ shutdown(m_fd, SHUT_RDWR);
+ close(m_fd);
+ }
+ }
+ // Open a new socket using PF_INET and SOCK_STREAM
+ bool open();
+ int fd() const { return m_fd; }
+private:
+ int m_fd;
+};
+
+class Connection {
+public:
+ Connection(int conn): m_socket(conn) {}
+ int read(char buf[], size_t length) const {
+ return recv(m_socket.fd(), buf, length, 0);
+ }
+ int write(const char buf[], size_t length) const {
+ return send(m_socket.fd(), buf, length, 0);
+ }
+ int write(const char buf[]) const {
+ return write(buf, strlen(buf));
+ }
+private:
+ Socket m_socket;
+};
+
+class ConnectionServer {
+public:
+ ConnectionServer() {}
+
+ // Establish a connection to the local host on the given port.
+ bool connect(short port);
+
+ // Blocks on the established socket until a new connection arrives.
+ Connection* accept() const;
+private:
+ Socket m_socket;
+};
+
+} // end namespace WDS
+
+} // end namespace android
+
+#endif
diff --git a/WebKit/android/wds/DebugServer.cpp b/WebKit/android/wds/DebugServer.cpp
new file mode 100644
index 0000000..8581680
--- /dev/null
+++ b/WebKit/android/wds/DebugServer.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "wds"
+#include "config.h"
+
+#include "Command.h"
+#include "Connection.h"
+#include "DebugServer.h"
+#include "wtf/MainThread.h"
+#include "wtf/Threading.h"
+#include <arpa/inet.h>
+#include <cutils/properties.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#if ENABLE(WDS)
+
+#define DEFAULT_PORT 9999
+#define log_errno(x) LOGE("%s: %d", x, strerror(errno))
+
+namespace android {
+
+namespace WDS {
+
+static DebugServer* s_server = NULL;
+
+// Main thread function for createThread
+static void* mainThread(void* v) {
+ DebugServer* server = static_cast<DebugServer*>(v);
+ server->start();
+ delete server;
+ s_server = NULL;
+ return NULL;
+}
+
+DebugServer* server() {
+ if (s_server == NULL)
+ s_server = new DebugServer();
+ return s_server;
+}
+
+DebugServer::DebugServer() {
+ // Read webcore.wds.enable to determine if the debug server should run
+ char buf[PROPERTY_VALUE_MAX];
+ int ret = property_get("webcore.wds.enable", buf, NULL);
+ if (ret != -1 && strcmp(buf, "1") == 0) {
+ LOGD("WDS Enabled");
+ m_threadId = createThread(mainThread, this, "WDS");
+ }
+ // Initialize the available commands.
+ Command::Init();
+}
+
+void DebugServer::start() {
+ LOGD("DebugServer thread started");
+
+ ConnectionServer cs;
+ if (!cs.connect(DEFAULT_PORT)) {
+ LOGE("Failed to start the server socket connection");
+ return;
+ }
+
+ while (true ) {
+ LOGD("Waiting for incoming connections...");
+ Connection* conn = cs.accept();
+ if (!conn) {
+ log_errno("Failed to accept new connections");
+ return;
+ }
+ LOGD("...Connection established");
+
+ Command* c = Command::Find(conn);
+ if (!c) {
+ LOGE("Could not find matching command");
+ delete conn;
+ } else {
+ // Dispatch the command, it will handle cleaning up the connection
+ // when finished.
+ c->dispatch();
+ }
+ }
+
+ LOGD("DebugServer thread finished");
+}
+
+} // end namespace WDS
+
+} // end namespace android
+
+#endif
diff --git a/WebKit/android/wds/DebugServer.h b/WebKit/android/wds/DebugServer.h
new file mode 100644
index 0000000..64db031
--- /dev/null
+++ b/WebKit/android/wds/DebugServer.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DEBUGSERVER_H
+#define DEBUGSERVER_H
+
+// Turn on the wds feature in webkit
+#define ENABLE_WDS 0
+
+#include "wtf/Threading.h"
+#include "wtf/Vector.h"
+
+// Forward declarations.
+namespace WebCore {
+ class Frame;
+}
+
+using namespace WTF;
+using namespace WebCore;
+
+namespace android {
+
+// WebCore Debug Server
+namespace WDS {
+
+class DebugServer : WTFNoncopyable::Noncopyable {
+public:
+ void start();
+ void addFrame(Frame* frame) {
+ m_frames.append(frame);
+ }
+ void removeFrame(Frame* frame) {
+ size_t i = m_frames.find(frame);
+ if (i != notFound)
+ m_frames.remove(i);
+ }
+ Frame* getFrame(unsigned idx) {
+ if (idx < m_frames.size())
+ return m_frames.at(idx);
+ return NULL;
+ }
+private:
+ DebugServer();
+ Vector<Frame*> m_frames;
+ ThreadIdentifier m_threadId;
+ friend DebugServer* server();
+};
+
+DebugServer* server();
+
+} // end namespace WDS
+
+} // end namespace android
+
+#endif
diff --git a/WebKit/android/wds/client/AdbConnection.cpp b/WebKit/android/wds/client/AdbConnection.cpp
new file mode 100644
index 0000000..79b49d7
--- /dev/null
+++ b/WebKit/android/wds/client/AdbConnection.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "wdsclient"
+
+#include "AdbConnection.h"
+#include "ClientUtils.h"
+#include "Device.h"
+#include <arpa/inet.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+void AdbConnection::close() {
+ if (m_fd != -1) {
+ shutdown(m_fd, SHUT_RDWR);
+ ::close(m_fd);
+ m_fd = -1;
+ }
+}
+
+// Default adb port
+#define ADB_PORT 5037
+
+bool AdbConnection::connect() {
+ // Some commands (host:devices for example) close the connection so we call
+ // connect after the response.
+ close();
+
+ m_fd = socket(PF_INET, SOCK_STREAM, 0);
+ if (m_fd < 0) {
+ log_errno("Failed to create socket for connecting to adb");
+ return false;
+ }
+
+ // Create the socket address struct
+ sockaddr_in adb;
+ createTcpSocket(adb, ADB_PORT);
+
+ // Connect to adb
+ if (::connect(m_fd, (sockaddr*) &adb, sizeof(adb)) < 0) {
+ log_errno("Failed to connect to adb");
+ return false;
+ }
+
+ // Connected
+ return true;
+}
+
+// Adb protocol stuff
+#define MAX_COMMAND_LENGTH 1024
+#define PAYLOAD_LENGTH 4
+#define PAYLOAD_FORMAT "%04X"
+
+bool AdbConnection::sendRequest(const char* fmt, ...) const {
+ if (m_fd == -1) {
+ LOGE("Connection is closed");
+ return false;
+ }
+
+ // Build the command (service)
+ char buf[MAX_COMMAND_LENGTH];
+ va_list args;
+ va_start(args, fmt);
+ int res = vsnprintf(buf, MAX_COMMAND_LENGTH, fmt, args);
+ va_end(args);
+
+ LOGV("Sending command: %04X%.*s", res, res, buf);
+
+ // Construct the payload length
+ char payloadLen[PAYLOAD_LENGTH + 1];
+ snprintf(payloadLen, sizeof(payloadLen), PAYLOAD_FORMAT, res);
+
+ // First, send the payload length
+ if (send(m_fd, payloadLen, PAYLOAD_LENGTH, 0) < 0) {
+ log_errno("Failure when sending payload");
+ return false;
+ }
+
+ // Send the actual command
+ if (send(m_fd, buf, res, 0) < 0) {
+ log_errno("Failure when sending command");
+ return false;
+ }
+
+ // Check for the OKAY from adb
+ return checkOkayResponse();
+}
+
+static void printFailureMessage(int fd) {
+ // Grab the payload length
+ char lenStr[PAYLOAD_LENGTH + 1];
+ int payloadLen = recv(fd, lenStr, sizeof(lenStr) - 1, 0);
+ LOG_ASSERT(payloadLen == PAYLOAD_LENGTH, "Incorrect payload size");
+ lenStr[PAYLOAD_LENGTH] = 0;
+
+ // Parse the hex payload
+ payloadLen = strtol(lenStr, NULL, 16);
+ if (payloadLen < 0)
+ return;
+
+ // Grab the message
+ char* msg = new char[payloadLen + 1]; // include null-terminator
+ int res = recv(fd, msg, payloadLen, 0);
+ if (res < 0) {
+ log_errno("Failure reading failure message from adb");
+ return;
+ } else if (res != payloadLen) {
+ LOGE("Incorrect payload length %d - expected %d", res, payloadLen);
+ return;
+ }
+ msg[res] = 0;
+
+ // Tell somebody about it
+ LOGE("Received failure from adb: %s", msg);
+
+ // Cleanup
+ delete[] msg;
+}
+
+#define ADB_RESPONSE_LENGTH 4
+
+bool AdbConnection::checkOkayResponse() const {
+ LOG_ASSERT(m_fd != -1, "Connection has been closed!");
+
+ char buf[ADB_RESPONSE_LENGTH];
+ int res = recv(m_fd, buf, sizeof(buf), 0);
+ if (res < 0) {
+ log_errno("Failure reading response from adb");
+ return false;
+ }
+
+ // Check for a response other than OKAY/FAIL
+ if ((res == ADB_RESPONSE_LENGTH) && (strncmp(buf, "OKAY", res) == 0)) {
+ LOGV("Command OKAY");
+ return true;
+ } else if (strncmp(buf, "FAIL", ADB_RESPONSE_LENGTH) == 0) {
+ // Something happened, print out the reason for failure
+ printFailureMessage(m_fd);
+ return false;
+ }
+ LOGE("Incorrect response from adb - '%.*s'", res, buf);
+ return false;
+}
+
+void AdbConnection::clearDevices() {
+ for (unsigned i = 0; i < m_devices.size(); i++)
+ delete m_devices.editItemAt(i);
+ m_devices.clear();
+}
+
+const DeviceList& AdbConnection::getDeviceList() {
+ // Clear the current device list
+ clearDevices();
+
+ if (m_fd == -1) {
+ LOGE("Connection is closed");
+ return m_devices;
+ }
+
+ // Try to send the device list request
+ if (!sendRequest("host:devices")) {
+ LOGE("Failed to get device list from adb");
+ return m_devices;
+ }
+
+ // Get the payload length
+ char lenStr[PAYLOAD_LENGTH + 1];
+ int res = recv(m_fd, lenStr, sizeof(lenStr) - 1, 0);
+ if (res < 0) {
+ log_errno("Failure to read payload size of device list");
+ return m_devices;
+ }
+ lenStr[PAYLOAD_LENGTH] = 0;
+
+ // Parse the hex payload
+ int payloadLen = strtol(lenStr, NULL, 16);
+ if (payloadLen < 0)
+ return m_devices;
+
+ // Grab the list of devices. The format is as follows:
+ // <serialno><tab><state><newline>
+ char* msg = new char[payloadLen + 1];
+ res = recv(m_fd, msg, payloadLen, 0);
+ if (res < 0) {
+ log_errno("Failure reading the device list");
+ return m_devices;
+ } else if (res != payloadLen) {
+ LOGE("Incorrect payload length %d - expected %d", res, payloadLen);
+ return m_devices;
+ }
+ msg[res] = 0;
+
+ char serial[32];
+ char state[32];
+ int numRead;
+ char* ptr = msg;
+ while (sscanf(ptr, "%31s\t%31s\n%n", serial, state, &numRead) > 1) {
+ Device::DeviceType t = Device::DEVICE;
+ static const char emulator[] = "emulator-";
+ if (strncmp(serial, emulator, sizeof(emulator) - 1) == 0)
+ t = Device::EMULATOR;
+ LOGV("Adding device %s (%s)", serial, state);
+ m_devices.add(new Device(serial, t, this));
+
+ // Reset for the next line
+ ptr += numRead;
+ }
+ // Cleanup
+ delete[] msg;
+
+ return m_devices;
+}
diff --git a/WebKit/android/wds/client/AdbConnection.h b/WebKit/android/wds/client/AdbConnection.h
new file mode 100644
index 0000000..0b5419f
--- /dev/null
+++ b/WebKit/android/wds/client/AdbConnection.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WDS_ADB_CONNECTION_H
+#define WDS_ADB_CONNECTION_H
+
+#include "DeviceList.h"
+
+class AdbConnection {
+public:
+ AdbConnection() : m_fd(-1) {}
+ ~AdbConnection() { clearDevices(); }
+ void close();
+ bool connect();
+ bool sendRequest(const char* fmt, ...) const;
+ const DeviceList& getDeviceList();
+
+private:
+ bool checkOkayResponse() const;
+ void clearDevices();
+ DeviceList m_devices;
+ int m_fd;
+};
+
+#endif
diff --git a/WebKit/android/wds/client/Android.mk b/WebKit/android/wds/client/Android.mk
new file mode 100644
index 0000000..5d07a31
--- /dev/null
+++ b/WebKit/android/wds/client/Android.mk
@@ -0,0 +1,32 @@
+##
+##
+## Copyright 2008, The Android Open Source Project
+##
+## Licensed under the Apache License, Version 2.0 (the "License");
+## you may not use this file except in compliance with the License.
+## You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+##
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ AdbConnection.cpp \
+ ClientUtils.cpp \
+ Device.cpp \
+ main.cpp
+
+LOCAL_STATIC_LIBRARIES := liblog libutils libcutils
+
+LOCAL_MODULE:= wdsclient
+
+include $(BUILD_HOST_EXECUTABLE)
+
diff --git a/WebKit/android/wds/client/ClientUtils.cpp b/WebKit/android/wds/client/ClientUtils.cpp
new file mode 100644
index 0000000..067775e
--- /dev/null
+++ b/WebKit/android/wds/client/ClientUtils.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ClientUtils.h"
+#include <arpa/inet.h>
+#include <string.h>
+
+void createTcpSocket(sockaddr_in& addr, short port) {
+ memset(&addr, 0, sizeof(sockaddr_in));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
+}
diff --git a/WebKit/android/wds/client/ClientUtils.h b/WebKit/android/wds/client/ClientUtils.h
new file mode 100644
index 0000000..dc8b23f
--- /dev/null
+++ b/WebKit/android/wds/client/ClientUtils.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WDS_CLIENT_UTILS_H
+#define WDS_CLIENT_UTILS_H
+
+#include <arpa/inet.h>
+
+// Callers need to include Log.h and errno.h to use this macro
+#define log_errno(str) LOGE("%s: %s", str, strerror(errno))
+
+// Fill in the sockaddr_in structure for binding to the localhost on the given
+// port
+void createTcpSocket(sockaddr_in& addr, short port);
+
+#endif
diff --git a/WebKit/android/wds/client/Device.cpp b/WebKit/android/wds/client/Device.cpp
new file mode 100644
index 0000000..03b4507
--- /dev/null
+++ b/WebKit/android/wds/client/Device.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AdbConnection.h"
+#include "Device.h"
+
+bool Device::sendRequest(const char* req) const {
+ return m_connection->sendRequest("host-serial:%s:%s", m_name, req);
+}
diff --git a/WebKit/android/wds/client/Device.h b/WebKit/android/wds/client/Device.h
new file mode 100644
index 0000000..c6d77f3
--- /dev/null
+++ b/WebKit/android/wds/client/Device.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WDS_DEVICE_H
+#define WDS_DEVICE_H
+
+#include <stdlib.h>
+
+class AdbConnection;
+
+class Device {
+public:
+ // Type of device.
+ // TODO: Add simulator support
+ enum DeviceType {
+ NONE = -1,
+ EMULATOR,
+ DEVICE
+ };
+
+ // Takes ownership of name
+ Device(char* name, DeviceType type, const AdbConnection* conn)
+ : m_connection(conn)
+ , m_name(strdup(name))
+ , m_type(type) {}
+ ~Device() { free(m_name); }
+
+ const char* name() const { return m_name; }
+ DeviceType type() const { return m_type; }
+
+ // Send a request to this device.
+ bool sendRequest(const char* req) const;
+
+private:
+ const AdbConnection* m_connection;
+ char* m_name;
+ DeviceType m_type;
+};
+
+#endif
diff --git a/WebKit/android/wds/client/DeviceList.h b/WebKit/android/wds/client/DeviceList.h
new file mode 100644
index 0000000..9139238
--- /dev/null
+++ b/WebKit/android/wds/client/DeviceList.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WDS_DEVICE_LIST_H
+#define WDS_DEVICE_LIST_H
+
+#include <utils/Vector.h>
+
+class Device;
+
+typedef android::Vector<Device*> DeviceList;
+
+#endif
diff --git a/WebKit/android/wds/client/main.cpp b/WebKit/android/wds/client/main.cpp
new file mode 100644
index 0000000..5899b16
--- /dev/null
+++ b/WebKit/android/wds/client/main.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "wdsclient"
+
+#include "AdbConnection.h"
+#include "ClientUtils.h"
+#include "Device.h"
+#include <arpa/inet.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#define DEFAULT_WDS_PORT 9999
+#define STR(x) #x
+#define XSTR(x) STR(x)
+#define PORT_STR XSTR(DEFAULT_WDS_PORT)
+
+int wds_open() {
+ // Create the structure for connecting to the forwarded 9999 port
+ sockaddr_in addr;
+ createTcpSocket(addr, DEFAULT_WDS_PORT);
+
+ // Create our socket
+ int fd = socket(PF_INET, SOCK_STREAM, 0);
+ if (fd < 0) {
+ log_errno("Failed to create file descriptor");
+ return -1;
+ }
+ // Connect to the remote wds server thread
+ if (connect(fd, (sockaddr*)&addr, sizeof(addr)) < 0) {
+ log_errno("Failed to connect to remote debug server");
+ return -1;
+ }
+ return fd;
+}
+
+// Clean up the file descriptor and connections
+void wds_close(int fd) {
+ if (fd != -1) {
+ shutdown(fd, SHUT_RDWR);
+ close(fd);
+ }
+}
+
+int main(int argc, char** argv) {
+
+ Device::DeviceType type = Device::NONE;
+
+ if (argc <= 1) {
+ LOGE("wdsclient takes at least 1 argument");
+ return 1;
+ } else {
+ // Parse the options, look for -e or -d to choose a device.
+ while (true) {
+ int c = getopt(argc, argv, "ed");
+ if (c == -1)
+ break;
+ switch (c) {
+ case 'e':
+ type = Device::EMULATOR;
+ break;
+ case 'd':
+ type = Device::DEVICE;
+ break;
+ default:
+ break;
+ }
+ }
+ if (optind == argc) {
+ LOGE("No command specified");
+ return 1;
+ }
+ }
+
+ // Do the initial connection.
+ AdbConnection conn;
+ conn.connect();
+
+ const DeviceList& devices = conn.getDeviceList();
+ // host:devices closes the connection, reconnect
+ conn.connect();
+
+ // No device specified and more than one connected, bail
+ if (type == Device::NONE && devices.size() > 1) {
+ LOGE("More than one device/emulator, please specify with -e or -d");
+ return 1;
+ } else if (devices.size() == 0) {
+ LOGE("No devices connected");
+ return 1;
+ }
+
+ // Find the correct device
+ const Device* device = NULL;
+ if (type == Device::NONE)
+ device = devices[0]; // grab the only one
+ else {
+ // Search for a matching device type
+ for (unsigned i = 0; i < devices.size(); i++) {
+ if (devices[i]->type() == type) {
+ device = devices[i];
+ break;
+ }
+ }
+ }
+
+ if (!device) {
+ LOGE("No device found!");
+ return 1;
+ }
+
+ // Forward tcp:9999
+ if (!device->sendRequest("forward:tcp:" PORT_STR ";tcp:" PORT_STR)) {
+ LOGE("Failed to send forwarding request");
+ return 1;
+ }
+
+ LOGV("Connecting to localhost port " PORT_STR);
+
+ const char* command = argv[optind];
+ int commandLen = strlen(command);
+#define WDS_COMMAND_LENGTH 4
+ if (commandLen != WDS_COMMAND_LENGTH) {
+ LOGE("Commands must be 4 characters '%s'", command);
+ return 1;
+ }
+
+ // Open the wds connection
+ int wdsFd = wds_open();
+ if (wdsFd == -1)
+ return 1;
+
+ // Send the command specified
+ send(wdsFd, command, WDS_COMMAND_LENGTH, 0); // commands are 4 bytes
+
+ // Read and display the response
+ char response[256];
+ int res = 0;
+ while ((res = recv(wdsFd, response, sizeof(response), 0)) > 0)
+ printf("%.*s", res, response);
+ printf("\n\n");
+
+ // Shutdown
+ wds_close(wdsFd);
+
+ return 0;
+}