当前位置:首页 > > 充电吧
[导读]一、概述       之前有介绍过chromium的界面层的相关知识,这篇文章则是重点介绍chromium中书签这一个模块,不仅有界面层的知识,还会较多的介绍逻辑层的一些内容。接下来会详细介绍chro

一、概述
       之前有介绍过chromium的界面层的相关知识,这篇文章则是重点介绍chromium中书签这一个模块,不仅有界面层的知识,还会较多的介绍逻辑层的一些内容。接下来会详细介绍chromium中书签功能的详细实现。主要问题有:
              1、书签数据在硬盘和内存中存储结构;
              2、初始化过程;
              3、相关操作的实现步骤;
              4、线程模型;
              5、书签同步。

二、书签结构综述
        Bookmark界面层在..srcchromebrowseruiviewsbookmarks中实现。Bookmark逻辑层在..srcchromebrowserbookmarks 中实现,包括读写书签文件,书签导入导出等。
       书签在整个工程中是chrome特色功能,它包括三种类型,书签栏、其他、和“mobile”。书签栏管理用户创建的所有书签
       作为chromium拓展中心的一个功能,整体流程图如图:
 
    图1 书签整体流程图

       在书签模块中,其中主要的两个模块是底层数据处理和界面显示,具体实现分别在BookmarkModel和BookmarkBarView中,它们之间采用的是observer设计模式,BookmarkModel(具体目标),BookmarkBarView(具体观察者)。

三、书签存储结构
       书签的存储结构需要从配置文件中结构及内存中存储结构两方面分析。
       书签配置文件中存储在本地Bookmarks中,以JSON的格式存储。并在书签模块启动的时候load文件中的书签数据。本地JSON书签数据如下:
         "children": [ {
            "date_added": "12994954482846617",
            "id": "7",
            "name": "Google",
            "type": "url",
            "url": "http://www.google.com.hk/"
         },
       在内存中每个节点对应一个BookmarkNode。其中包含了favicon, id and type等节点信息。
       在BookmarkModel中定义了如下几个节点:
         BookmarkNode root_;
         BookmarkPermanentNode* bookmark_bar_node_;
         BookmarkPermanentNode* other_node_;
         BookmarkPermanentNode* mobile_node_;
       root_作为根节点,是书签栏中节点和“其他”文件夹中节点的父节点。BookmarkPermanentNode只是BookmarkNode一个简单的封装,用来管理书签栏及“其他”等这种固定的文件夹。

四、书签初始化及释放
       书签功能的初始化:可以分为两个部分,数据逻辑层和界面层。从上面的主流程图中我们可以看出,数据逻辑层先于界面层初始化,具体初始化流程如下:
       数据逻辑层:
       初始化流程,拓展中心统一初始化,在ExtensionService::InitEventRouters()中调用
       bookmark_event_router_.reset(new BookmarkExtensionEventRouter(
             BookmarkModelFactory::GetForProfile(profile_)));
             bookmark_event_router_->Init();
       最终在BookmarkModelFactory完成BookmarkModel的创建。另外,BookmarkExtensionEventRouter继承自BookmarkModelObserver,是BookmarkModel的一个具体观察者。会将bookmark中的修改通知装换成event传给extension system
       逻辑层初始化执行顺序如下图:

 
图2 书签数据逻辑层执行
       为防止阻塞UI线程,书签文件的加载是在一个后台进程中完成的,chromium启动的时候,主线程Post出一个文件加载的Task,同时传入了一个回调函数的指针参数,当消息中心处理这个Task时会调用之前传入的回调,并完成书签文件的加载接JSON数据的解析。注意这个步骤是在File加载线程中完成的。加载解析完成后,File加载线程会POST出一个Task,并将操作权交还给主线程,去完成后需初始化工作。
        书签文件的解析是在JSONFileValueSerializer中完成的,在这个里面会将JSON文件反序列化。并将其内容存入BookmarkLoadDetails中,供接下来的调用。

       界面层:
       BookmarkBarView类是BookmarkModel的具体观察者,负责书签数据的渲染布局等,与书签界面层相关的操作主要在这里面实现。
       BookmarkBarView由BrowserView统一管理,BrowserView不会主动创建BookmarkBarView,而是在之后执行需要书签的操作中,如UpdateUIForContents,若书签界面层尚未创建,则执行创建操作,否则跳过。

       书签模块的释放:同样重点完成数据逻辑层和界面层的释放。释放的过程和创建相反。先delete 管理界面模块的BookmarkBarView,这部分功能由BrowserView统一管理释放。之后再进一步delete管理逻辑层的模块BookmarkModel,这部分释放工作在配置文件管理中心统一释放。

五、书签操作执行流程
       书签界面层与逻辑层的类关系图如下。

 
   图3 界面层、逻辑层类关系图
    
       BookmarkModel继承自PofileDeyedService,因而可以实现在配置文件管理中心统一释放
       BookmarkBarView继承自DetachableToolbarView,是一个与Chrome frame分离的view控件。
       BookmarkModel与BookmarkBarView均继承自消息中心NotificationObserver,并会通过registrar_注册自己需要接受的通知。

       BookmarkModel类中的实现。它是是observer模式中的具体目标及数据逻辑层的核心实现。BookmarkModel对象需要通过 BookmarkModelFactory才能创建,而不能直接创建。
       BookmarkModel类管理者内存中的书签数据,也向外提供了很多的操作接口,如AddNode、RemoveAndDeleteNode、RemoveNode等。用户操作书签时,都会通过调用这些接口来修改书签内容。
       在BookmarkModel中通过定义一个BookmarkStorage的对象来操作书签的磁盘读写,上面提到的文件加载就是通过这个对象来执行的。另外,当书签数据与磁盘同步也在   这个里面完成,当用户修改了书签内容时,会调用其中的ScheduleSave()函数写回磁盘。
       书签磁盘读写的类图如下:
 

  图4 书签磁盘读写类图
       其中BookmarkLoadDetails是用来临时存储书签数据的对象。

       BookmarkBarView类派生自BookmarkModelObserver,是observer模式中一个具体的观察者。中完成书签界面展示以及部分用户操作。

       另外,书签栏内部的子文件夹显示也存在菜单栏的弹出,包括点击文件夹及拖动书签节点至文件夹都会弹出。BookmarkBarView中定义了两个菜单对书签栏的子菜单进行管理:
         BookmarkMenuController* bookmark_menu_;
         BookmarkMenuController* bookmark_drop_menu_;
       其中bookmark_menu_用于管理用户点击BookmarkBarView中的文件夹时弹出的菜单(BookmarkBarView是MenuButtonListener的子类,可以收听到这个事件)。bookmark_drop_menu_是用户拖拽一个node到文件夹上时弹出的菜单。


 
图5 书签右键菜单实现类图

       Chromium中书签最基本的操作有添加、删除、修改等。同时,用户操作书签的方式也有很多,如快捷键,主菜单,书签右键菜单等。书签操作的执行顺序基本如下。

 

图6 书签操作执行顺序


       书签的显示实现
       在chromium的代码中,每次调用网页时都会调用void Browser::UpdateBookmarkBarState(BookmarkBarStateChangeReason reason),用以判断是否需要显示书签,书签有三种状态,SHOW(显示与地址栏不分离)、DETACHED(显示与地址栏分离)、HIDDEN(不显示)。
[cpp] view plaincopy void Browser::UpdateBookmarkBarState(BookmarkBarStateChangeReason reason) {     BookmarkBar::State state;     // The bookmark bar is hidden in fullscreen mode, unless on the new tab page.     if (browser_defaults::bookmarks_enabled &&         profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar) &&         (!window_ || !window_->IsFullscreen())) {       state = BookmarkBar::SHOW;     } else {       WebContents* web_contents = chrome::GetActiveWebContents(this);       BookmarkTabHelper* bookmark_tab_helper =           web_contents ? BookmarkTabHelper::FromWebContents(web_contents) : NULL;       if (bookmark_tab_helper && bookmark_tab_helper->ShouldShowBookmarkBar())         state = BookmarkBar::DETACHED;       else         state = BookmarkBar::HIDDEN;     }        // Only allow the bookmark bar to be shown in default mode.     if (!search_model_->mode().is_default())       state = BookmarkBar::HIDDEN;        if (state == bookmark_bar_state_)       return;        bookmark_bar_state_ = state;        if (!window_)       return;  // This is called from the constructor when window_ is NULL.        if (reason == BOOKMARK_BAR_STATE_CHANGE_TAB_SWITCH) {       // Don't notify BrowserWindow on a tab switch as at the time this is invoked       // BrowserWindow hasn't yet switched tabs. The BrowserWindow implementations       // end up querying state once they process the tab switch.       return;     }        BookmarkBar::AnimateChangeType animate_type =         (reason == BOOKMARK_BAR_STATE_CHANGE_PREF_CHANGE) ?         BookmarkBar::ANIMATE_STATE_CHANGE :         BookmarkBar::DONT_ANIMATE_STATE_CHANGE;     window_->BookmarkBarStateChanged(animate_type);   }  
       在这个函数中最终会调用window_->BookmarkBarStateChanged(animate_type),其中会调用到BrowserView的实现中,再由其中的bookmark_bar_view_来统一接手管理界面的工作。

       书签栏中点击打开网页
       当从书签栏中点击打开网页时,先会调用void BookmarkBarView::ButtonPressed函数,并在此函数中会调用page_navigator_->OpenURL(params);进一步调用WebContentsImple相应的方法来实现。

       当前页直接添加书签
       将当前页添加到书签则会调用void BookmarkCurrentPage(Browser* browser)(browser_commands.cc中的全局函数),再调用void BrowserView::ShowBookmarkBubble(const GURL& url, bool already_bookmarked)最终是在BookmarkBubbleView中完成。

六、书签线程模型
       在整个书签模块中,除了文件读取是在后台File线程中完成外,其余操作均在主线程中执行,线程执行方法与整个chromium的线程模型保持一致。
       为了保证书签文件在加载是不出现线程安全问题,chromium中设计了一个BookmarkStorage的中间层来读写书签文件,并在BookmarkStorage中定义了一个BookmarkLoadDetails,通过操作它来加载书签文件中的详细信息。加载完成后回调到主线程,并把所有权交还给BookmarkModel。但BookmarkModel中没有对BookmarkLoadDetails的引用,不能直接操作其中的内容,这样就确保解决了线程可能带来的问题。

七、登陆后书签同步
       用户登陆成功后,数据同步中心会对相关数据进行同步,书签也包括在内。在Chromium中会由browser_sync同步中心统一管理用户同步相关操作。BookmarkModelAssociator负责实现bookmark model 和sync model之间的联系算法、为sync node 及bookmark node之间的相互获取提供方法。同步完成后最终会调用BookmarkModel的相关方法来实现书签的更新。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭