For Developers‎ > ‎Design Documents‎ > ‎

Conventions and patterns for multi-platform development

Chromium is a large and complex cross-platform product. We try to share as much code as possible between platforms, while implementing the UI and OS integration in the most appropriate way for each. While this gives a better user experience, it adds extra complexity to the code. This document describes the recommended practices for keeping such cross-platform code clean.
We use a variety of different file naming suffixes to indicate when a file should be used:
  • Mac files use the _mac suffix for lower-level files and Cocoa (Mac UI) files use the _cocoa suffix.
  • iOS files use the _ios suffix (although iOS also uses some specific _mac files).
  • Linux files use _linux suffix for lower-level files, _gtk for GTK-specific files, and _x for X Windows (with no GTK) specific files.
  • Windows files use the _win suffix.
  • Posix files shared between Mac, iOS, and Linux use the _posix suffix.
  • Files for Chrome's "Views" UI (on Windows and experimental GTK) layout system use the _views suffix.
The separate front-ends of the browser are contained in their own directories:
  • Mac Cocoa: chrome/browser/ui/cocoa
  • Linux GTK: chrome/browser/ui/gtk
  • Windows Views (and the experimental GTK-views): chrome/browser/ui/views
The Coding Style page lists some stylistic rules affecting platform-specific defines.

How to separate platform-specific code

Small platform differences: #ifdefs

When you have a class with many shared functions or data members, but a few differences, use #ifdefs around the platform-specific parts. If there are no significant differences, it's easier for everybody to keep everything in one place.

Small platform differences in the header, larger ones in the implementation: split the implementation

There may be cases where there are few header file differences, but significant implementation differences for parts of the implementation. For example, base/waitable_event.h defines a common API with a couple of platform differences.
With significant implementation differences, the implementation files can be split. The prevents you from having to do a lot of #ifdefs for the includes necessary for each platform and also makes it easier to follow (three versions each of a set of functions in a file can get confusing). There can be different .cc files for each platform, as in base/waitable_event_posix.cc that implements posix-specific functions. If there were cross-platform functions in this class, they would be put in a file called base/waitable_event.cc.

Complete platform implementations and callers: separate implementations

When virtually none of the implementation is shared, implement the class separately for each platform in separate files.
If all implementations are in a cross-platform directory such as base, they should be named with the platform name, such as FooBarWin in base/foo_bar_win.h. This case will generally be rare since files in these cross-platform files are normally designed to be used by cross-platform code, and separate header files makes this impossible. In some places we've defined a commonly named class in different files, so PlatformDevice is defined in skia/ext/platform_device_win.h, skia/ext/platform_device_linux.h, and skia/ext/platform_device_mac.h. This is OK if you really need to refer to this class in cross-platform code. But generally, cases like this will fall into the following rule.
If the implementations live in platform-specific directories such as chrome/browser/ui/cocoa or chrome/browser/ui/views, there is no chance that the class will be used by cross-platform code. In this case, the classes and filenames should omit the platform name since it would be redundant. So you would have FooBar implemented in chrome/browser/ui/cocoa/foo_bar.h.
Don't create different classes with different names for each platform and typedef it to a shared name. We used to have this for PlatformCanvas, where it was a typedef of PlatformCanvasMac, PlatformCanvasLinux, or PlatformCanvasWin depending on the platform. This makes it impossible to forward-declare the class, which is an important tool for reducing dependencies.

When to use virtual interfaces

In general, virtual interfaces and factories should not be used for the sole purpose of separating platform differences. Instead, it should be be used to separate interfaces from implementations to make the code better designed. This comes up mostly when implementing the view as separate from the model, as in TabContentsView or RenderWidgetHostView. In these cases, it's desirable for the model not to depend on implementation details of the view. In many cases, there will only be one implementation of the view for each platform, but gives cleaner separation and more flexibility in the future.
In some places like TabContentsView, the virtual interface has non-virtual functions that do things shared between platforms. Avoid this. If the code is always the same regardless of the view, it probably shouldn't be in the view in the first place.

Implementing platform-specific UI

In general, construct platform specific user interface elements from other platform-specific user interface elements. For instance, the views-specific class BrowserView is responsible for constructing many of the browser dialog boxes. The alternative is to wrap the UI element in a platform-independent interface and construct it from a model via a factory. This is significantly less desirable as it confuses ownership: in most cases of construction by factory, the UI element returned ends up being owned by the model that created it. However in many cases the UI element is most easily managed by the UI framework to which it belongs. For example, a views::View is owned by its view hierarchy and is automatically deleted when its containing window is destroyed. If you have a dialog box views::View that implements a platform independent interface that is then owned by another object, the views::View instance now needs to explicitly tell its view hierarchy not to try and manage its lifetime.
e.g. prefer this:

// browser.cc:

Browser::ExecuteCommand(..) {
  ...
  case IDC_COMMAND_EDIT_FOO:
    window()->ShowFooDialog();
    break;
  ...
}

// browser_window.h:

class BrowserWindow {
...
  virtual void ShowFooDialog() = 0;
...
};

// browser_view.cc:

BrowserView::ShowFooDialog() {
  views::Widget::CreateWindow(new FooDialogView)->Show();
}

// foo_dialog_view.cc:

// FooDialogView and FooDialogController are automatically cleaned up when the window is closed.
class FooDialogView : public views::View {
  ...
 private:
  scoped_ptr<FooDialogController> controller_; // Cross-platform state/control logic
  ...
}

to this:

// browser.cc:

Browser::ExecuteCommand(..) {
  ...
  case IDC_COMMAND_EDIT_FOO: {
    FooDialogController::instance()->ShowUI();
    break;
  }
  ...
}

// foo_dialog_controller.h:

class FooDialog {
 public:
  static FooDialog* CreateFooDialog(FooDialogController* controller);
  virtual void Show() = 0;
  virtual void Bar() = 0;
};

class FooDialogController {
 public:
  ...
  static FooDialogController* instance() {
    static FooDialogController* instance = NULL;
    if (!instance)
      instance = Singleton<FooDialogController>::get();
    return instance;
  }
  ...
 private:
  ...
  void ShowUI() {
    if (!dialog_.get())
      dialog_.reset(FooDialog::CreateFooDialog(this));
    dialog_->Show();
  }

// Why bother keeping FooDialog or even FooDialogController around?
  // Most dialogs are very seldom used.
  scoped_ptr<FooDialog> dialog_;
};

// foo_dialog_win.cc:

class FooDialogView : public views::View,
                      public FooDialogController {
 public:
  ...
  explicit FooDialogView(FooDialogController* controller) {
    set_parent_owned(false); // Now necessary due to scoped_ptr in FooDialogController.
  }
  ...
};

FooDialog* FooDialog::CreateFooDialog(FooDialogController* controller) {
  return new FooDialogView(controller);
}

Sometimes this latter pattern is necessary, but these occasions are rare, and very well understood by the frontend team. When porting, consider converting cases of the latter model to the former model if the UI element is something simple like a dialog box.

转载于:https://www.cnblogs.com/huangguanyuan/p/9673863.html

Conventions and patterns for multi-platform development相关推荐

  1. 在Ubuntu 16.04.1 LTS上安装XnView Multi Platform图片浏览器0.83

    XnView Multi Platform是一个全平台(Windows, Linux, Mac)下的全能图片工具,类似Windows平台的美图看看,阿香婆图片浏览器等等,效果非常赞,是我在Ubuntu ...

  2. API Design for ios 译文

    API Design 译文 译文 本文来源于matt gemmell困于自己英语水平问题, 若有错误见谅. One of the development tasks I do most often i ...

  3. free pascal

    工具: lazarus, codetyphon, fpcupdeluxe 大提纲 https://dubst3pp4.github.io/post/2017-10-03-why-i-use-objec ...

  4. BlackArch-Tools

    BlackArch-Tools 简介安装在ArchLinux之上添加存储库从blackarch存储库安装工具替代安装方法BlackArch Linux Complete Tools List 简介 B ...

  5. implay matlab,matlab free download - SourceForge

    Sync your GitHub Project to SourceForge automatically! Do you have a GitHub project? Now you can syn ...

  6. 《以太坊攻略》,小白如何逆袭成为技术大咖?要学的全在这里了

    作者/ Daniel Que 编译/ kou 昨天,营长一直在劝诫小编,熊市不可怕,小编不能慌,小编也要学技术. 只有这样,天上掉"牛肉味"馅饼的时候,馅饼才能砸到站在第一排的小编 ...

  7. 银河土星_设计师来自土星,开发人员来自木星:或者,为什么沟通很重要

    银河土星 by Albino Tonnina 通过白化Tonnina 设计师来自土星,开发人员来自木星:或者,为什么沟通很重要 (Designers are from Saturn, develope ...

  8. 给自家人做个招聘广告,前后端和移动工程师看过来

    咳咳,从上上期<你该如何证明你是你>漫画,大部分读者可能知道我们漫画的主创 霍炬,现在去 PRESS.one 做CTO了,我也兼职那边产品和设计的工作.厚脸皮替自家人做个招聘广告. 下面列 ...

  9. 系统运维-20-2-openssh和openssl

    0.关于ssh最佳实践的基本认识 1)禁用默认端口,2)禁用版本 version 1,3)限制可登陆用户,使用白名单,4)限制空闲会话时长,5)防火墙设置ssh访问规则,6)限定监听的地址,7)使用强 ...

最新文章

  1. Android Wifi 主动扫描 被动扫描
  2. linux 虚拟网络设备详解(四)
  3. Kubernetes Deployment与Replica Set
  4. mahout 算法集
  5. php 类的数组对象,javascript、php数组对象互转类
  6. Leetcode 844. 比较含退格的字符串 解题思路及C++实现
  7. 线上oom 自动kill 程序
  8. 如何做一个国产数据库(三)
  9. 【Elasticsearch】实用BM25 -第2部分:BM25算法及其变量
  10. 整理了10个行业的30份可视化大屏模板,可直接拿走套用
  11. HCNA-RS笔记-20171105-day03
  12. 职称计算机和英语保留时间,职称计算机考试成绩_职称计算机应用能力考试成绩保留时间是多长?...
  13. 单细胞测序系列之一:测序技术的发展
  14. 【工作小技巧】cmd 批量移动文件
  15. kafka如何创建topic
  16. 【2022 年“SPSSPRO 杯”数学中国数学建模网络挑战赛】A题 人员的紧急疏散-第二阶段23页论文
  17. -webkit-border-radius和-moz-border-radius分析
  18. 学习绘画应该怎么起步?
  19. ThreeJS - 直接设置Fbx模型的某个关节的位移和旋转值
  20. PyScripter中文乱码原因

热门文章

  1. @程序员:Java平均工资再次上涨,光张年限不涨薪的我慌了!
  2. 参与开源项目,结识技术大牛!CSDN “开源加速器计划”招募志愿者啦!
  3. 不是“老赖”是“真还”!罗永浩 6 亿债务还了 4 亿
  4. 腾讯云发布全链路数据开发平台WeData,大数据开发迈入新时代
  5. Python实现前端AES加密方式分析,***密码学必备!
  6. 以太坊智能合约预言机
  7. [转] createObjectURL方法 实现本地图片预览
  8. SQL Server-聚焦sp_executesql执行动态SQL查询性能真的比exec好?
  9. 微信小程序小结02-- 完整的demo
  10. Linux修改/etc/profile配置错误command is not found自救方法