webkit Dump Render Tree 工作流程

发布时间:2016-12-8 10:07:56 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"webkit Dump Render Tree 工作流程",主要涉及到webkit Dump Render Tree 工作流程方面的内容,对于webkit Dump Render Tree 工作流程感兴趣的同学可以参考一下。

1.下载一个webkit的版本,目前我使用的版本是webkit-r54749,这个版本正好是android2.2版本对应webkit版本 2.进行编译,这个过程根据自己机器环境qt,gtk,win之类都是可以编译,在这里简单说一下怎么进行编译 切换到WebKit-r54749目录下 ./WebKitTools/Scripts/build-webkit --help 下面罗列出很多的细节:  --help                            Show this help message   --clean                           Cleanup the build directory   --debug                           Compile in debug mode   --cairo-win32                     Build using Cairo (rather than CoreGraphics) on Windows   --chromium                        Build the Chromium port on Mac/Win/Linux   --gtk                             Build the GTK+ port   --qt                              Build the Qt port   --inspector-frontend              Copy changes to the inspector front-end files to the build directory   --makeargs=<arguments>            Optional Makefile flags   --minimal                         No optional features, unless explicitly enabled.   --[no-]3d-canvas                  Toggle 3D canvas support (default: 0)   --[no-]3d-rendering               Toggle 3D rendering support (default: 0)   --[no-]channel-messaging          Toggle MessageChannel and MessagePort support (default: 1)   --[no-]client-based-geolocation   Toggle client-based Geolocation support (default: 1)   --[no-]coverage                   Toggle code coverage support (default: 0)   --[no-]database                   Toggle Database Support (default: 1)   --[no-]datagrid                   Toggle Datagrid Support (default: 0)   --[no-]datalist                   Toggle HTML5 datalist support (default: 1)   --[no-]dom-storage                Toggle DOM Storage Support (default: 1)   --[no-]eventsource                Toggle server-sent events support (default: 1)   --[no-]filters                    Toggle Filters support (default: 1)   --[no-]geolocation                Toggle Geolocation support (default: 1)   --[no-]icon-database              Toggle Icon database support (default: 1)   --[no-]indexed-database           Toggle Indexed Database API support (default: 0)   --[no-]javascript-debugger        Toggle JavaScript Debugger/Profiler support (default: 1)   --[no-]mathml                     Toggle MathML support (default: 0)   --[no-]notifications              Toggle Desktop Notifications Support (default: 0)   --[no-]offline-web-applications   Toggle Offline Web Application Support (default: 1)   --[no-]ruby                       Toggle HTML5 Ruby support (default: 1)   --[no-]shared-workers             Toggle SharedWorkers support (default: 1)   --[no-]svg                        Toggle SVG support (default: 1)   --[no-]svg-animation              Toggle SVG animation support (implies SVG support) (default: 1)   --[no-]svg-as-image               Toggle SVG as Image support (implies SVG support) (default: 1)   --[no-]svg-dom-objc-bindings      Toggle SVG DOM Objective-C bindings support (implies SVG support) (default: 0)   --[no-]svg-fonts                  Toggle SVG fonts support (imples SVG support) (default: 1)   --[no-]svg-foreign-object         Toggle SVG foreign object support (implies SVG support) (default: 1)   --[no-]svg-use                    Toggle SVG use element support (implies SVG support) (default: 1)   --[no-]video                      Toggle Video support (default: 1)   --[no-]web-sockets                Toggle Web Sockets support (default: 1)   --[no-]wml                        Toggle WML support (default: 0)   --[no-]xhtmlmp                    Toggle XHTML-MP support (default: 0)   --[no-]wcss                       Toggle WCSS support (default: 0)   --[no-]workers                    Toggle Web Workers support (default: 1)   --[no-]xpath                      Toggle XPath support (default: 1)   --[no-]xslt                       Toggle XSLT support (default: 1) 这个时候就可以根据自己环境选择 ./WebKitTools/Scripts/build-webkit --gtk --debug 这样就可以编译一个基于gtk的debug版本 我们发现在WebKit-r54749目录下会生成一个WebKitBuild目录 有个Debug目录存在 当然在编译的过程中会有很多的错误,比如缺少某个库,之类的错误,这个时候要根据缺失的进行安装,在这里就不进行详细介绍了 当然最新的webkit版本较之这个版本已经有太多的变化了,但是核心部门的大致逻辑不会有太大的变化,只不过分工更加明细了,结构更加合理了 闲话少说接着来 在Debug目录下有个Programs,然后我们看下里面存在一个 DumpRenderTree  GtkLauncher  jsc  minidom  unittests 这么几个文件,GtkLauncher就是webkit的入口程序 DumpRenderTree这就是我们这节说的重点所在,这个可执行程序对应的源文件就是DumpRenderTree.cpp文件中 我们直接执行 ./DumpRenderTree  http://192.168.1.68/index.html 就可以看到下面的打印 layer at (0,0) size 76x92   RenderView at (0,0) size 76x92 layer at (0,0) size 76x92   RenderBlock {HTML} at (0,0) size 76x92     RenderBody {BODY} at (0,0) size 76x92       RenderTable {TABLE} at (0,0) size 1x1         RenderTableSection {TBODY} at (0,0) size 1x1           RenderTableRow {TR} at (0,0) size 1x1             RenderTableCell {TD} at (0,0) size 1x1 [r=0 c=0 rs=1 cs=1]               RenderImage {IMG} at (0,0) size 1x1 如果是第一次运行有可能会出现这样的错误 ** ERROR **: WEBKIT_TESTFONTS environment variable is not set, but it should point to the directory containing the fonts you can clone from git://gitorious.org/qtwebkit/testfonts.git 这个是需要设置一个fonts的路径 我们只需要这样做下:export WEBKIT_TESTFONTS=/opt/raul/sources/browser/WebKit-r54749/WebKitTools/DumpRenderTree/fonts 就可以了 我们接着看忙活半天的成果 有个这个好工具就非常有助于我们学习webkit的render过程 我们简单的分析一下是如何打印出这个罗列顺序的,熟悉浏览器用法的人都知道浏览器有个最基本的功能,右键查看页面源代码。 这个功能和DumpRenderTree功能很相近,就是把内部Dom tree中的结构给提炼出来 现在简单分析下提炼的过程 int main(int argc, char* argv[]) {     g_thread_init(NULL);     gtk_init(&argc, &argv); #if PLATFORM(X11)     FcInit();     initializeFonts(); #endif     struct option options[] = {         {"notree", no_argument, &dumpTree, false},         {"pixel-tests", no_argument, &dumpPixels, true},         {"tree", no_argument, &dumpTree, true},         {NULL, 0, NULL, 0}     };     int option;     while ((option = getopt_long(argc, (char* const*)argv, "", options, NULL)) != -1)         switch (option) {             case '?':   // unknown or ambiguous option             case ':':   // missing argument                 exit(1);                 break;         }     window = gtk_window_new(GTK_WINDOW_POPUP);     container = GTK_WIDGET(gtk_scrolled_window_new(NULL, NULL));     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(container), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);     gtk_container_add(GTK_CONTAINER(window), container);     gtk_widget_show_all(window);     webView = createWebView();     gtk_container_add(GTK_CONTAINER(container), GTK_WIDGET(webView));     gtk_widget_realize(GTK_WIDGET(webView));     gtk_widget_show_all(container);     gtk_widget_grab_focus(GTK_WIDGET(webView));     mainFrame = webkit_web_view_get_main_frame(webView);     setDefaultsToConsistentStateValuesForTesting();     gcController = new GCController();     axController = new AccessibilityController();     if (argc == optind+1 && strcmp(argv[optind], "-") == 0) {         char filenameBuffer[2048];         printSeparators = true;         while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {             char* newLineCharacter = strchr(filenameBuffer, '\n');             if (newLineCharacter)                 *newLineCharacter = '\0';             if (strlen(filenameBuffer) == 0)                 continue;             runTest(filenameBuffer);         }     } else {         printSeparators = (optind < argc-1 || (dumpPixels && dumpTree));         for (int i = optind; i != argc; ++i)             runTest(argv[i]);     }     delete gcController;     gcController = 0;     delete axController;     axController = 0;     gtk_widget_destroy(window);     return 0; } 下面是基本的main函数,initializeFonts();这个函数的实现包含的就是上面提高的找不到WEBKIT_TESTFONTS环境变量的问题 在这个过程中做的基本的事件就是加载一个页面,然后把这个页面的基本的render tree的结构打印出来,顺便运行一下几个单元测试 我们只是研究下关键代码  webView = createWebView(); 这个函数的实现如下: static WebKitWebView* createWebView() {     WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new());     // From bug 11756: Use a frame group name for all WebViews created by     // DumpRenderTree to allow testing of cross-page frame lookup.     webkit_web_view_set_group_name(view, "org.webkit.gtk.DumpRenderTree");     g_object_connect(G_OBJECT(view),                      "signal::load-started", webViewLoadStarted, 0,                      "signal::load-finished", webViewLoadFinished, 0,                      "signal::window-object-cleared", webViewWindowObjectCleared, 0,                      "signal::console-message", webViewConsoleMessage, 0,                      "signal::script-alert", webViewScriptAlert, 0,                      "signal::script-prompt", webViewScriptPrompt, 0,                      "signal::script-confirm", webViewScriptConfirm, 0,                      "signal::title-changed", webViewTitleChanged, 0,                      "signal::navigation-policy-decision-requested", webViewNavigationPolicyDecisionRequested, 0,                      "signal::status-bar-text-changed", webViewStatusBarTextChanged, 0,                      "signal::create-web-view", webViewCreate, 0,                      "signal::close-web-view", webViewClose, 0,                      "signal::database-quota-exceeded", databaseQuotaExceeded, 0,                      NULL);     WebKitWebInspector* inspector = webkit_web_view_get_inspector(view);     g_object_connect(G_OBJECT(inspector),                      "signal::inspect-web-view", webInspectorInspectWebView, 0,                      "signal::show-window", webInspectorShowWindow, 0,                      "signal::close-window", webInspectorCloseWindow, 0,                      NULL);     if (webView) {         WebKitWebSettings* settings = webkit_web_view_get_settings(webView);         webkit_web_view_set_settings(view, settings);     }     return view; } 最关键的部位是在 "signal::load-finished", webViewLoadFinished, 0, 我们看webViewLoadFinished函数的实现 static void webViewLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*) {     if (!done && !gLayoutTestController->dumpFrameLoadCallbacks()) {         guint pendingFrameUnloadEvents = webkit_web_frame_get_pending_unload_event_count(frame);         if (pendingFrameUnloadEvents) {             char* frameName = getFrameNameSuitableForTestResult(view, frame);             printf("%s - has %u onunload handler(s)\n", frameName, pendingFrameUnloadEvents);             g_free(frameName);         }     }     if (frame != topLoadingFrame)         return;     topLoadingFrame = 0;     WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test     if (gLayoutTestController->waitToDump())         return;     if (WorkQueue::shared()->count())         g_timeout_add(0, processWork, 0);     else         dump(); } 在最后一行找到他的小尾巴了,那么看看到底如何提取出来的那? void dump() {     invalidateAnyPreviousWaitToDumpWatchdog();     bool dumpAsText = gLayoutTestController->dumpAsText();     if (dumpTree) {         char* result = 0;         gchar* responseMimeType = webkit_web_frame_get_response_mime_type(mainFrame);         dumpAsText = g_str_equal(responseMimeType, "text/plain");         g_free(responseMimeType);         // Test can request controller to be dumped as text even         // while test's response mime type is not text/plain.         // Overriding this behavior with dumpAsText being false is a bad idea.         if (dumpAsText)             gLayoutTestController->setDumpAsText(dumpAsText);         if (gLayoutTestController->dumpAsText())             result = dumpFramesAsText(mainFrame);         else             result = webkit_web_frame_dump_render_tree(mainFrame);         if (!result) {             const char* errorMessage;             if (gLayoutTestController->dumpAsText())                 errorMessage = "[documentElement innerText]";             else if (gLayoutTestController->dumpDOMAsWebArchive())                 errorMessage = "[[mainFrame DOMDocument] webArchive]";             else if (gLayoutTestController->dumpSourceAsWebArchive())                 errorMessage = "[[mainFrame dataSource] webArchive]";             else                 errorMessage = "[mainFrame renderTreeAsExternalRepresentation]";             printf("ERROR: nil result from %s", errorMessage);         } else {             printf("%s", result);             g_free(result);             if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive())                 dumpFrameScrollPosition(mainFrame);             if (gLayoutTestController->dumpBackForwardList())                 dumpBackForwardListForAllWebViews();         }         if (printSeparators) {             puts("#EOF"); // terminate the content block             fputs("#EOF\n", stderr);             fflush(stdout);             fflush(stderr);         }     }     if (dumpPixels) {         if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive()) {             // FIXME: Add support for dumping pixels         }     }     // FIXME: call displayWebView here when we support --paint     done = true;     gtk_main_quit(); } 这个函数太长,我们还是截取最关键的代码 result = webkit_web_frame_dump_render_tree(mainFrame); 这个函数执行返回的结果就是我们上面执行打印的结果 看来还需要继续追踪 gchar* webkit_web_frame_dump_render_tree(WebKitWebFrame* frame) {     g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), NULL);     Frame* coreFrame = core(frame);     if (!coreFrame)         return g_strdup("");     FrameView* view = coreFrame->view();     if (view && view->layoutPending())         view->layout();     String string = externalRepresentation(coreFrame);     return g_strdup(string.utf8().data()); } String string = externalRepresentation(coreFrame);这个函数返回的,这位大仙何许人阿,追踪了下,发现是在 RenderTreeAsText.cpp中进行定义的 这个类是render模块专门拿出来处理收集信息 String externalRepresentation(Frame* frame, RenderAsTextBehavior behavior) {     frame->document()->updateLayout();     RenderObject* o = frame->contentRenderer();     if (!o)         return String();     TextStream ts; #if ENABLE(SVG)     writeRenderResources(ts, o->document()); #endif     if (o->hasLayer()) {         RenderLayer* l = toRenderBox(o)->layer();         writeLayers(ts, l, l, IntRect(l->x(), l->y(), l->width(), l->height()), 0, behavior);         writeSelection(ts, o);     }     return ts.release(); } 好了从逻辑上来说,就弄到这边吧,留点自己思考的时间 在android平台上如果要打印render tree 直接通过webview.dumpDomTree(false) 很是方便,前提需要把NDEBUG定义注释掉,留点引子下次继续介绍。

上一篇:Select模型的 单服务器多客户端示范代码
下一篇:c# 读取机器CPU信息,硬盘信息,网卡信息

相关文章

相关评论