WebCore::Widget浅探

简介: 研究方法:WebKit的xcode工程里以Widget为关键字全局搜索,查看相关函数名与注释新建一个使用了UIWebView的工程,运行时lldb里image lookup与Widget有关的类探寻:Widget.

研究方法:

  • WebKit的xcode工程里以Widget为关键字全局搜索,查看相关函数名与注释
  • 新建一个使用了UIWebView的工程,运行时lldb里image lookup与Widget有关的类

探寻:

Widget.h里有以下注释:

// The Widget class serves as a base class for three kinds of objects: 
// (1) Scrollable areas (ScrollView) 
// (2) Scrollbars (Scrollbar) 
// (3) Plugins (PluginView) 
// 
// A widget may or may not be backed by a platform-specific object (e.g., HWND on Windows, NSView on Mac, QWidget on Qt). 
// 
// Widgets are connected in a hierarchy, with the restriction that plugins and scrollbars are always leaves of the 
// tree.  Only ScrollViews can have children (and therefore the Widget class has no concept of children). 
// 
// The rules right now for which widgets get platform-specific objects are as follows: 
// ScrollView - Mac 
// Scrollbar - Mac, Gtk 
// Plugin - Mac, Windows (windowed only), Qt (windowed only, widget is an HWND on windows), Gtk (windowed only) 

我是这么理解:
Widget类是对不同平台的系统控件的封装,能成为Widget的东西有三种:可滚动区域、滚动条、插件。这三种东西在不同平台(甚至不同的浏览器)可以有不同的实现。更直观地说,这些Widget的外观都可以不同,例如chrome在windows和OS X的右侧滚动条就不同。

在Widget的构造函数就能看出一些端倪:

#if PLATFORM(MAC) 
OBJC_CLASS NSView; 
OBJC_CLASS NSWindow; 
typedef NSView *PlatformWidget; 
#endif 
 
#if PLATFORM(WIN) 
typedef struct HWND__* HWND; 
typedef HWND PlatformWidget; 
#endif 
 
class Widget : public RefCounted<Widget> { 
public: 
    explicit Widget(PlatformWidget = 0); 

在lldb搜索,会有:

WebCore::Widget::Widget(WAKView*) 
WebCore::Widget::setPlatformWidget(WAKView*)

可见在iOS是用WAKView是代替了NSView。下面是WAKView的继承关系图:


WAKView是一个NSObject,并不是UIView。WAKView的成员变量声明:

@interface WAKView : WAKResponder 
{ 
    struct _WKViewContext viewContext; 
    struct WKView *viewRef; 
    NSMutableSet *subviewReferences; 
    BOOL _isHidden; 
    BOOL _drawsOwnDescendants; 
} 

其中的两个结构体为:

struct _WKViewContext { 
    void *notificationCallback; 
    void *notificationUserInfo; 
    void *responderCallback; 
    void *responderUserInfo; 
    void *willRemoveSubviewCallback; 
    void *invalidateGStateCallback; 
}; 
struct WKView { 
    struct _WKObject _field1; 
    struct _WKViewContext *_field2; 
    struct WKWindow *_field3; 
    struct WKView *_field4; 
    struct __CFArray *_field5; 
    struct CGPoint _field6; 
    struct CGRect _field7; 
    unsigned int _field8; 
    float _field9; 
    void *_field10; 
}; 

WAKView有77个函数,大部分是NSView也有的函数,如addSubview,setFrame等。对应NSView,在iOS有UIView,但UIView没有NSView那么多函数与功能。

而WAKView的父类WAKResponder则和NSResponder类似。对应NSResponder,在iOS有UIResponder,但UIResponder没有NSResponder那么多函数与功能;WAKResponder就像是删减了UIResponder没有的函数的NSResponder,例如WAKResponder和NSResponder会有以下几个相同的但UIResponder没有的函数:

- (void)mouseDown:(id)arg1; 
- (void)mouseUp:(id)arg1; 
- (void)moveUpAndModifySelection:(id)arg1; 
- (void)moveUp:(id)arg1; 
- (void)moveRightAndModifySelection:(id)arg1; 
- (void)moveRight:(id)arg1; 
- (void)moveLeftAndModifySelection:(id)arg1; 
- (void)moveLeft:(id)arg1; 
- (void)moveDownAndModifySelection:(id)arg1; 
- (void)moveDown:(id)arg1; 

WKView在WebKit2工程里的声明:

WK_EXPORT 
@interface WKView : NSView <NSTextInputClient> { 
@private 
    WKViewData *_data; 
    unsigned _unused; 
} 

可见WKView在Mac和iOS的表示是不同的,一个是Objective-C类,一个是结构体。

在iOS运行UIWebView,lldb搜索WKView

(lldb) image lookup -r -s WKView 

会得到44个结果,几乎全是C函数。即在iOS上操作WKView都是C的方式。

搜索webkit的wiki http://trac.webkit.org/wiki/WebKit2,得到如下信息:

 Why is it named WebKit2?

The somewhat pedestrian reason is that it's an incompatible API change from the original WebKit, so it will probably be installed as something like /System/Library/WebKit2.framework on Mac.

C API

WebKit2 will provide a stable C-based non-blocking API that is mostly platform agnostic. In order to achieve the goal of a non-blocking API, several techniques are used to make the API usable while still providing a comprehensive set of features to the embedder. These techniques include:

  • Notification style client callbacks (e.g. didFinishLoadForFrame) These inform the embedder that something has happened, but do not give them the chance to do anything about it.
  • Policy style clients callbacks (e.g. decidePolicyForNavigationAction) These allow the embedder to decide on an action at their leisure, notifying the page through a listener object.
  • Policy settings (e.g. WKContextSetCacheModel, WKContextSetPopupPolicy) These allow the embedder to opt into a predefined policy without any callbacks into the UIProcess. These can either be an enumerated set of specific policies, or something more fine-grained, such as a list of strings with wildcards.
  • Injected code (e.g. WebBundle) Code can be loaded into the WebProcess for cases where all the other options fail. This can useful when access to the DOM is required. [Planned, but not currently implemented]

The major API classes are:

WKContextRef

  • Encapsulates all pages related to specific use of WebKit. All pages in this context share the same visited link set, local storage set, and preferences.

WKPageNamespaceRef

  • Encapsulates all pages that can script each other.

WKPageRef

  • Basic unit of browsing. Stays the same as the main frame changes.

WKView[Ref]

  • Native view that hooks into the platform's toolkit. On Windows, this wraps a HWND. On the Mac, it inherits from NSView.

Note that the requirement to be fully non-blocking requires an incompatible API break - many features of most existing WebKit APIs cannot be fulfilled in a non-blocking manner. Since we needed the API break anyway, we also took advantage of the opportunity to clean up and simplify the API.

综合以上信息,应该可以推断出以下结论:

1. Widget封装平台控件,外部可通过Widget获取到平台控件的信息(主要是大小),并由平台控件传递用户事件信息(如mouseDown)到Widget。

2. iOS的UIWebView采用双线程架构,其实现是模仿了Mac Safari的双进程架构,并做了很多的适配,WAKView是为了在iOS上模仿NSView的替代品,从而令部分代码在Mac和iOS上复用。WAK应该是Web App Kit的缩写,因为对应iOS上UIView所属的UIKit,在Mac上是NSView所属的AppKit。这一层是线程间通信的中间层,主要起到状态信息保存和中转消息的作用。


另外,在调试实践中,还有以下的信息:

1. 当Plugin由系统控件来实现,并禁止其自行接收和处理事件时,如禁用视频的控制面板MPMoviePlayerController.controlStyle =MPMovieControlStyleNone,即会把mouse/key事件直接传递到该Plugin所属的HTMLElement

2. drag and drop 里,plugin有特殊行为,如视频可能支持拖动。当然,iOS也不支持。

3. WebCore对Widget能有统一管理,如attach和dettach,widget本身还有树结构

4. EventHandler内的处理逻辑,当发现是点击在widget上,可以另外传递事件,不产生click。 对Widget focus,widget可能会有特别的行为,例如进入模态

    // Many AppKit widgets run their own event loops and consume events while the mouse is down. 
    // When they finish, currentEvent is the mouseUp that they exited on.  We need to update 
    // the EventHandler state with this mouseUp, which we never saw. 
    // If this event isn't a mouseUp, we assume that the mouseUp will be coming later.  There 
    // is a hole here if the widget consumes both the mouseUp and subsequent events. 

长按菜单就是例子,由WebThread发起同步消息, WebSheet会显示成模态,新起一个EventLoop。

5. Widget在Mac上会有特别的逻辑,这些会和iOS不同。如下是例子。

/* 
 A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus 
 eats all subsequent events after it is starts its modal tracking loop.  After the interaction 
 is done, this routine is used to fix things up.  When a mouse down started us tracking in 
 the widget, we post a fake mouse up to balance the mouse down we started with. When a  
 key down started us tracking in the widget, we post a fake key up to balance things out. 
 In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to  
 be over after the tracking is done. 
 */ 
void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent) 

6. HTMLMediaElement的PLUGIN_PROXY_FOR_VIDEO宏会让media由plugin作为widget打开。这些标签也会建立Widget:HTMLObjectElement, HTMLEmbedElement,HTMLAppletElement。

目录
相关文章
|
容器
使用 AspectRatio Widget
使用 AspectRatio Widget
70 0
使用 AspectRatio Widget
【布局 widget】ConstrainedBox 与 UnconstrainedBox
【布局 widget】ConstrainedBox 与 UnconstrainedBox
97 0
【布局 widget】ConstrainedBox 与 UnconstrainedBox
|
前端开发 容器
【布局 widget】OverflowBox 与 SizedOverflowBox
【布局 widget】OverflowBox 与 SizedOverflowBox
102 0
【布局 widget】OverflowBox 与 SizedOverflowBox
RecyclerView与CardView的使用(二)
RecyclerView与CardView的使用(二)
102 0
RecyclerView与CardView的使用(二)
|
开发工具 Android开发
RecyclerView与CardView的使用(一)
RecyclerView与CardView的使用(一)
126 0
RecyclerView与CardView的使用(一)
|
缓存 Dart
Flutter一切皆widget但是不要将所有东西放入一个widget
当我们在widgets目录中,我们可以看到很多小部件,如Padding,Align,SizedBox,等。我们通过组合它们来创建其他小部件,我发现这种方法可扩展、强大且易于理解。 但是当我阅读 一些我在互联网上找到的或由新采用者编写的源代码时,有一件让我震惊的事情:拥有大量build ` 方法的趋势,实例化很多小部件!我发现这很难阅读、理解和维护。
72 0
|
XML Android开发 数据安全/隐私保护
Android Widget开发详解
  本文和大家重点学习一下Widget开发的概念,本例是为了实现一个手机Android平台的Widget开发,该Widget中的内容是根据输入账号从叽歪网站上获得得。当然,这个过程需要叽歪的API,得到信息后进行处理并显示出来。
1059 0
|
Android开发 数据格式 XML
Android dialog Activity 使用
尖角 dialog 弹窗使用很方便,我们都知道 Activity 也能搞成 dialog 形式,更加方便,下面我们下一个 dialog 样式的Activity 吧: 1、在 value/style.
1700 0