Project Fission/BrowsingContext: Difference between revisions
(Add notes on SetWithoutSyncing and Transaction::Commit) |
(Clarify when the ContentParent is passed to CanSet()) |
||
| (One intermediate revision by one other user not shown) | |||
| Line 48: | Line 48: | ||
field. <syntaxhighlight lang="C++" inline>CanSet</syntaxhighlight> takes three arguments: | field. <syntaxhighlight lang="C++" inline>CanSet</syntaxhighlight> takes three arguments: | ||
# The | # The field index that names it (for overloading) | ||
# The value being set | # The value being set | ||
# | # A <syntaxhighlight lang="C++" inline>ContentParent</syntaxhighlight>, if and when it is receiving a transaction from its <syntaxhighlight lang="C++" inline>ContentChild</syntaxhighlight>. | ||
Finally, there will also be field setter callbacks available as <syntaxhighlight lang="C++" inline>DidSet</syntaxhighlight> methods. <syntaxhighlight lang="C++" inline>DidSet</syntaxhighlight> 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 | Here, 3 will only be non-null if in the parent process, and if the field | ||
| Line 56: | Line 58: | ||
With this we know everything needed to add synced state to a class, so | With this we know everything needed to add synced state to a class, so | ||
we will show a small | we will show a small contrived example: | ||
<syntaxhighlight lang="C++"> | <syntaxhighlight lang="C++"> | ||
| Line 95: | Line 97: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
(Again note that the returning <syntaxhighlight lang="C++" inline>nsresult</syntaxhighlight> isn't actually in tree yet). | (Again note that the returning <syntaxhighlight lang="C++" inline>nsresult</syntaxhighlight> isn't actually in tree yet). | ||
== Browsing Contexts == | == Browsing Contexts == | ||
Latest revision as of 07:02, 23 March 2021
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
- the name of the class that owns the synced state.
- 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:
- The field index that names it (for overloading)
- The value being set
- A
ContentParent, if and when it is receiving a transaction from itsContentChild.
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).