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。

目录
相关文章
|
8天前
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
1194 4
|
7天前
|
机器学习/深度学习 人工智能 前端开发
通义DeepResearch全面开源!同步分享可落地的高阶Agent构建方法论
通义研究团队开源发布通义 DeepResearch —— 首个在性能上可与 OpenAI DeepResearch 相媲美、并在多项权威基准测试中取得领先表现的全开源 Web Agent。
957 12
|
6天前
|
机器学习/深度学习 物联网
Wan2.2再次开源数字人:Animate-14B!一键实现电影角色替换和动作驱动
今天,通义万相的视频生成模型又又又开源了!Wan2.2系列模型家族新增数字人成员Wan2.2-Animate-14B。
538 11
|
17天前
|
人工智能 运维 安全
|
8天前
|
弹性计算 Kubernetes jenkins
如何在 ECS/EKS 集群中有效使用 Jenkins
本文探讨了如何将 Jenkins 与 AWS ECS 和 EKS 集群集成,以构建高效、灵活且具备自动扩缩容能力的 CI/CD 流水线,提升软件交付效率并优化资源成本。
341 0
|
8天前
|
消息中间件 Java Apache
SpringBoot集成RocketMq
RocketMQ 是一款开源的分布式消息中间件,采用纯 Java 编写,支持事务消息、顺序消息、批量消息、定时消息及消息回溯等功能。其优势包括去除对 ZooKeeper 的依赖、支持异步和同步刷盘、高吞吐量及消息过滤等特性。RocketMQ 具备高可用性和高可靠性,适用于大规模分布式系统,能有效保障消息传输的一致性和顺序性。
463 2
|
15天前
|
人工智能 异构计算
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!
|
8天前
|
云栖大会
阿里云云栖大会2025年9月24日开启,免费申请大会门票,速度领取~
2025云栖大会将于9月24-26日举行,官网免费预约畅享票,审核后短信通知,持证件入场
1571 12