/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html * * 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. */ package com.google.dart.tools.debug.core.webkit; import com.google.dart.tools.debug.core.DartDebugCorePlugin; import com.google.dart.tools.debug.core.webkit.WebkitConnection.Callback; import com.google.dart.tools.debug.core.webkit.WebkitConnection.NotificationHandler; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.xml.bind.DatatypeConverter; /** * A WIP page domain object. * <p> * Actions and events related to the inspected page belong to the page domain. * * @see http://code.google.com/chrome/devtools/docs/protocol/tot/page.html */ public class WebkitPage extends WebkitDomain { public static interface PageListener { public void domContentEventFired(int timestamp); public void frameDetached(String frameId); public void frameNavigated(String frameId, String url); public void frameResized(); public void frameStartedLoading(String frameId); public void frameStoppedLoading(String frameId); public void loadEventFired(int timestamp); } public static abstract class PageListenerAdapter implements PageListener { @Override public void domContentEventFired(int timestamp) { } @Override public void frameDetached(String frameId) { } @Override public void frameNavigated(String frameId, String url) { } @Override public void frameResized() { } @Override public void frameStartedLoading(String frameId) { } @Override public void frameStoppedLoading(String frameId) { } @Override public void loadEventFired(int timestamp) { } } private static final String PAGE_LOADEVENTFIRED = "Page.loadEventFired"; private static final String PAGE_DOMCONTENTEVENTFIRED = "Page.domContentEventFired"; private static final String PAGE_FRAMENAVIGATED = "Page.frameNavigated"; private static final String PAGE_FRAMEDETACHED = "Page.frameDetached"; private static final String PAGE_FRAMERESIZED = "Page.frameResized"; private static final String PAGE_FRAMESTOPPEDLOADING = "Page.frameStoppedLoading"; private static final String PAGE_FRAMESTARTEDLOADING = "Page.frameStartedLoading"; /** * Convert base 64 data into a byte array. This method is provided for use with the * {@link #captureScreenshot(WebkitCallback)} method. * * @param data base64 encoded data * @return */ public static byte[] convertBase64ToBinary(String data) { return DatatypeConverter.parseBase64Binary(data); } private List<PageListener> listeners = new ArrayList<PageListener>(); public WebkitPage(WebkitConnection connection) { super(connection); connection.registerNotificationHandler("Page.", new NotificationHandler() { @Override public void handleNotification(String method, JSONObject params) throws JSONException { handlePageNotification(method, params); } }); } public void addPageListener(PageListener listener) { listeners.add(listener); } /** * Tells if backend supports a FPS counter display. Returns true if the FPS count can be shown. * * @param callback * @throws IOException */ @WebkitUnsupported public void canShowFPSCounter(final WebkitCallback<Boolean> callback) throws IOException { sendSimpleCommand("Page.canShowFPSCounter", new Callback() { @Override public void handleResult(JSONObject result) throws JSONException { callback.handleResult(convertCanShowFPSCounterResult(result)); } }); } /** * Capture page screenshot. Returns base64-encoded image data (PNG). * * @throws IOException * @see {@link #convertBase64ToBinary(String)} */ @WebkitUnsupported public void captureScreenshot(final WebkitCallback<String> callback) throws IOException { sendSimpleCommand("Page.captureScreenshot", new Callback() { @Override public void handleResult(JSONObject result) throws JSONException { callback.handleResult(convertCaptureScreenshotResult(result)); } }); } public void disable() throws IOException { sendSimpleCommand("Page.disable"); } public void enable() throws IOException { sendSimpleCommand("Page.enable"); } public void navigate(String url) throws IOException { try { JSONObject request = new JSONObject(); request.put("method", "Page.navigate"); request.put("params", new JSONObject().put("url", url)); connection.sendRequest(request); } catch (JSONException exception) { throw new IOException(exception); } } public void reload() throws IOException { sendSimpleCommand("Page.reload"); } public void removePageListener(PageListener listener) { listeners.remove(listener); } /** * Requests that backend shows the FPS counter * * @param show True for showing the FPS counter * @throws IOException */ @WebkitUnsupported public void setShowFPSCounter(boolean show) throws IOException { try { JSONObject request = new JSONObject(); request.put("method", "Page.setShowFPSCounter"); request.put("params", new JSONObject().put("show", show)); connection.sendRequest(request); } catch (JSONException exception) { throw new IOException(exception); } } protected WebkitResult<Boolean> convertCanShowFPSCounterResult(JSONObject object) throws JSONException { WebkitResult<Boolean> result = WebkitResult.createFrom(object); if (object.has("result")) { boolean showResult = object.getJSONObject("result").getBoolean("show"); result.setResult(showResult); } return result; } protected WebkitResult<String> convertCaptureScreenshotResult(JSONObject object) throws JSONException { WebkitResult<String> result = WebkitResult.createFrom(object); if (object.has("result")) { String data = object.getJSONObject("result").getString("data"); result.setResult(data); } return result; } protected void handlePageNotification(String method, JSONObject params) throws JSONException { if (method.equals(PAGE_LOADEVENTFIRED)) { // { "timestamp": 12345678 } int timestamp = params.getInt("timestamp"); for (PageListener listener : listeners) { listener.loadEventFired(timestamp); } } else if (method.equals(PAGE_DOMCONTENTEVENTFIRED)) { // { "timestamp": 12345678 } int timestamp = params.getInt("timestamp"); for (PageListener listener : listeners) { listener.domContentEventFired(timestamp); } } else if (method.equals(PAGE_FRAMENAVIGATED)) { // { // "frame": { // "id":"8892.1","loaderId":"8892.2","securityOrigin":"http://www.cheese.com", // "mimeType":"text/html","url":"http://www.cheese.com/" // } // } JSONObject frame = params.getJSONObject("frame"); String frameId = JsonUtils.getString(frame, "frameId"); String url = JsonUtils.getString(frame, "url"); for (PageListener listener : listeners) { listener.frameNavigated(frameId, url); } } else if (method.equals(PAGE_FRAMEDETACHED)) { // {"frameId":"9121.19"} String frameId = params.getString("frameId"); for (PageListener listener : listeners) { listener.frameDetached(frameId); } } else if (method.equals(PAGE_FRAMERESIZED)) { for (PageListener listener : listeners) { listener.frameResized(); } } else if (method.equals(PAGE_FRAMESTOPPEDLOADING)) { // {"method":"Page.frameStoppedLoading","params":{"frameId":"4620.1"}} String frameId = params.getString("frameId"); for (PageListener listener : listeners) { listener.frameStoppedLoading(frameId); } } else if (method.equals(PAGE_FRAMESTARTEDLOADING)) { // {"method":"Page.frameStartedLoading","params":{"frameId":"48490.1"}} connection.getCSS().frameStartedLoading(); String frameId = params.getString("frameId"); for (PageListener listener : listeners) { listener.frameStartedLoading(frameId); } } else { DartDebugCorePlugin.logInfo("unhandled notification: " + method); } } }