Project Fission/BrowsingContext

From MozillaWiki
Jump to: navigation, search

Synced Contexts

Using the base class SyncedContex, classes that need to replicate state across content processes can do so. SyncedContex is not intended to be modified in the general case, but only for improving the behavior of synced contexts in general. SyncedContex isn't inherited, but is declared as a has-a in a class that needs to keep state synced.

State is kept in "synced fields". A synced field is basically a named piece of state. It is important that the value stored in a synced field is immutable, so that the syncing framework can make sure that the value is actually synced. Synced fields are accessed through getters and setters exposed on the owning class, where the setters ensure that the state is synced.

To add content process synced state to a class you use MOZ_DECL_SYNCED_CONTEXT defiend in SyncedContex.h. MOZ_DECL_SYNCED_CONTEXT takes two arguments

  1. the name of the class that owns the synced state.
  2. a macro that lists all the data that should be synced.

The macro listing all synced fields in turn should take one argument, which is used to do the actual field declaration. A field declaration consists of a name and a type. Remember, that type should denote an immutable value, and needs to be default initializable.

This way MOZ_DECL_SYNCED_CONTEXT will declare and define the setters and getters, and type indices used to access the synced state by name.

Getters will be of the form:

type GetFieldName() const;

Setters will be of the form:

MOZ_MUST_USE nsresult SetFieldName(type&& value)

Note that setters can fail, and you need to handle failure! (This isn't currently true, but will be soon!)

It also defines CanSet method for every field that you need to implement in the owning class to decide if it is OK to modify a field. CanSet takes three arguments:

  1. The field index that names it (for overloading)
  2. The value being set
  3. A ContentParent, if and when it is receiving a transaction from its ContentChild.

Finally, there will also be field setter callbacks available as DidSet methods. DidSet is supposed to be overridden, and can either take only the field index that names it, or the field index and the previous value.

Here, 3 will only be non-null if in the parent process, and if the field change originated in a child process.

With this we know everything needed to add synced state to a class, so we will show a small contrived example:

#define MOZ_EACH_FOO_FIELD(FIELD) \
  FIELD(First, int)               \
  FIELD(Second, double)           \
  FIELD(Third, Maybe<bool>)

class Foo {
  MOZ_DECL_SYNCED_CONTEXT(Foo, MOZ_EACH_FOO_FIELD)
public:
  bool CanSet(FieldIndex<IDX_First>, const int& value);
  bool CanSet(FieldIndex<IDX_Second>, const double& value);
  bool CanSet(FieldIndex<IDX_Third>, const Maybe<bool>& value);
};

This adds three fields, First, Second, Third with declared types. Foo will now have the getters and setters GetFirst, SetFirst, etc. To add a new field you need to add a new FIELD line, and a corresponding CanSet.

SyncedContext is currently only available in two classes: BrowsingContext and WindowContext.

Declared fields are default initialized on construction of the owner class. If you need to initialize the fields to something else before first sync, you can use SetWithoutSyncing.

Whenever a field is synced a number of IPC messages will be sent. To keep this number down it is possible to batch field modifications using the underlying framework on which synced fields are built upon. MOZ_DECL_SYNCED_CONTEXT defines Transaction in the owner class which can be used to accomplish this.

Continuing with our contrieved example from before we can do:

nsresult Foo::SetFirstAndSecond() {
  Tranxaction txn;
  txn.SetFirst(42);
  txn.SetSecond(3.14);
  return txt.Commit();
}

(Again note that the returning nsresult isn't actually in tree yet).

Browsing Contexts

Window Contexts

Browsing Context Groups