*
* Then the initial styles for that will look like so:
*
* Styles:
* ```
* StylingContext[InitialStylesIndex] = [
* null, null, 'width', '100px', height, '200px'
* ]
* ```
*
* Classes:
* ```
* StylingContext[InitialClassesIndex] = [
* null, null, 'foo', true, 'bar', true, 'baz', true
* ]
* ```
*
* Initial style and class entries have their own arrays. This is because
* it's easier to add to the end of one array and not then have to update
* every context entries' pointer index to the newly offseted values.
*
* When property bindinds are added to a context then initial style/class
* values will also be inserted into the array. This is to create a space
* in the situation when a follow-up directive inserts static styling into
* the array. By default, style values are `null` and class values are
* `false` when inserted by property bindings.
*
* For example:
* ```
*
* ```
*
* Will construct initial styling values that look like:
*
* Styles:
* ```
* StylingContext[InitialStylesIndex] = [
* null, null, 'width', '100px', height, '200px', 'opacity', null
* ]
* ```
*
* Classes:
* ```
* StylingContext[InitialClassesIndex] = [
* null, null, 'foo', true, 'bar', true, 'baz', true, 'car', false
* ]
* ```
*
* Now if a directive comes along and introduces `car` as a static
* class value or `opacity` then those values will be filled into
* the initial styles array.
*
* For example:
*
* ```
* @Directive({
* selector: 'opacity-car-directive',
* host: {
* 'style': 'opacity:0.5',
* 'class': 'car'
* }
* })
* class OpacityCarDirective {}
* ```
*
* This will render itself as:
*
* Styles:
* ```
* StylingContext[InitialStylesIndex] = [
* null, null, 'width', '100px', height, '200px', 'opacity', '0.5'
* ]
* ```
*
* Classes:
* ```
* StylingContext[InitialClassesIndex] = [
* null, null, 'foo', true, 'bar', true, 'baz', true, 'car', true
* ]
* ```
*/
export const enum InitialStylingValuesIndex {
/**
* The first value is always `null` so that `styles[0] == null` for unassigned values
*/
DefaultNullValuePosition = 0,
/**
* Used for non-styling code to examine what the style or className string is:
* styles: ['width', '100px', 0, 'opacity', null, 0, 'height', '200px', 0]
* => initialStyles[CachedStringValuePosition] = 'width:100px;height:200px';
* classes: ['foo', true, 0, 'bar', false, 0, 'baz', true, 0]
* => initialClasses[CachedStringValuePosition] = 'foo bar';
*
* Note that this value is `null` by default and it will only be populated
* once `getInitialStyleStringValue` or `getInitialClassNameValue` is executed.
*/
CachedStringValuePosition = 1,
/**
* Where the style or class values start in the tuple
*/
KeyValueStartPosition = 2,
/**
* The offset value (index + offset) for the property value for each style/class entry
*/
PropOffset = 0,
/**
* The offset value (index + offset) for the style/class value for each style/class entry
*/
ValueOffset = 1,
/**
* The offset value (index + offset) for the style/class directive owner for each style/class
entry
*/
DirectiveOwnerOffset = 2,
/**
* The first bit set aside to mark if the initial style was already rendere
*/
AppliedFlagBitPosition = 0b0,
AppliedFlagBitLength = 1,
/**
* The total size for each style/class entry (prop + value + directiveOwner)
*/
Size = 3
}
/**
* An array located in the StylingContext that houses all directive instances and additional
* data about them.
*
* Each entry in this array represents a source of where style/class binding values could
* come from. By default, there is always at least one directive here with a null value and
* that represents bindings that live directly on an element in the template (not host bindings).
*
* Each successive entry in the array is an actual instance of a directive as well as some
* additional info about that entry.
*
* An entry within this array has the following values:
* [0] = The instance of the directive (the first entry is null because its reserved for the
* template)
* [1] = The pointer that tells where the single styling (stuff like [class.foo] and [style.prop])
* offset values are located. This value will allow for a binding instruction to find exactly
* where a style is located.
* [2] = Whether or not the directive has any styling values that are dirty. This is used as
* reference within the `renderStyling` function to decide whether to skip iterating
* through the context when rendering is executed.
* [3] = The styleSanitizer instance that is assigned to the directive. Although it's unlikely,
* a directive could introduce its own special style sanitizer and for this reach each
* directive will get its own space for it (if null then the very first sanitizer is used).
*
* Each time a new directive is added it will insert these four values at the end of the array.
* When this array is examined then the resulting directiveIndex will be resolved by dividing the
* index value by the size of the array entries (so if DirA is at spot 8 then its index will be 2).
*/
export interface DirectiveRegistryValues extends Array
{
[DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset]: number;
[DirectiveRegistryValuesIndex.StyleSanitizerOffset]: StyleSanitizeFn|null;
}
/**
* An enum that outlines the offset/position values for each directive entry and its data
* that are housed inside of [DirectiveRegistryValues].
*/
export const enum DirectiveRegistryValuesIndex {
SinglePropValuesIndexOffset = 0,
StyleSanitizerOffset = 1,
Size = 2
}
/**
* An array that contains the index pointer values for every single styling property
* that exists in the context and for every directive. It also contains the total
* single styles and single classes that exists in the context as the first two values.
*
* Let's say we have the following template code:
*
*
* directive-with-foo-bar-classes>
*
* We have two directive and template-binding sources,
* 2 + 1 styles and 1 + 1 classes. When the bindings are
* registered the SinglePropOffsets array will look like so:
*
* s_0/c_0 = template directive value
* s_1/c_1 = directive one (directive-with-opacity)
* s_2/c_2 = directive two (directive-with-foo-bar-classes)
*
* [3, 2, 2, 1, s_00, s01, c_01, 1, 0, s_10, 0, 1, c_20
*/
export interface SinglePropOffsetValues extends Array
{
[SinglePropOffsetValuesIndex.StylesCountPosition]: number;
[SinglePropOffsetValuesIndex.ClassesCountPosition]: number;
}
/**
* An enum that outlines the offset/position values for each single prop/class entry
* that are housed inside of [SinglePropOffsetValues].
*/
export const enum SinglePropOffsetValuesIndex {
StylesCountPosition = 0,
ClassesCountPosition = 1,
ValueStartPosition = 2
}
/**
* Used a reference for all multi styling values (values that are assigned via the
* `[style]` and `[class]` bindings).
*
* Single-styling properties (things set via `[style.prop]` and `[class.name]` bindings)
* are not handled using the same approach as multi-styling bindings (such as `[style]`
* `[class]` bindings).
*
* Multi-styling bindings rely on a diffing algorithm to figure out what properties have been added,
* removed and modified. Multi-styling properties are also evaluated across directives--which means
* that Angular supports having multiple directives all write to the same `[style]` and `[class]`
* bindings (using host bindings) even if the `[style]` and/or `[class]` bindings are being written
* to on the template element.
*
* All multi-styling values that are written to an element (whether it be from the template or any
* directives attached to the element) are all written into the `MapBasedOffsetValues` array. (Note
* that there are two arrays: one for styles and another for classes.)
*
* This array is shaped in the following way:
*
* [0] = The total amount of unique multi-style or multi-class entries that exist currently in the
* context.
* [1+] = Contains an entry of four values ... Each entry is a value assigned by a
* `[style]`/`[class]`
* binding (we call this a **source**).
*
* An example entry looks like so (at a given `i` index):
* [i + 0] = Whether or not the value is dirty
*
* [i + 1] = The index of where the map-based values
* (for this **source**) start within the context
*
* [i + 2] = The untouched, last set value of the binding
*
* [i + 3] = The total amount of unqiue binding values that were
* extracted and set into the context. (Note that this value does
* not reflect the total amount of values within the binding
* value (since it's a map), but instead reflects the total values
* that were not used by another directive).
*
* Each time a directive (or template) writes a value to a `[class]`/`[style]` binding then the
* styling diffing algorithm code will decide whether or not to update the value based on the
* following rules:
*
* 1. If a more important directive (either the template or a directive that was registered
* beforehand) has written a specific styling value into the context then any follow-up styling
* values (set by another directive via its `[style]` and/or `[class]` host binding) will not be
* able to set it. This is because the former directive has priorty.
* 2. Only if a former directive has set a specific styling value to null (whether by actually
* setting it to null or not including it in is map value) then a less imporatant directive can
* set its own value.
*
* ## How the map-based styling algorithm updates itself
*/
export interface MapBasedOffsetValues extends Array {
[MapBasedOffsetValuesIndex.EntriesCountPosition]: number;
}
export const enum MapBasedOffsetValuesIndex {
EntriesCountPosition = 0,
ValuesStartPosition = 1,
DirtyFlagOffset = 0,
PositionStartOffset = 1,
ValueOffset = 2,
ValueCountOffset = 3,
Size = 4
}
/**
* Used to set the context to be dirty or not both on the master flag (position 1)
* or for each single/multi property that exists in the context.
*/
export const enum StylingFlags {
// Implies no configurations
None = 0b00000,
// Whether or not the entry or context itself is dirty
Dirty = 0b00001,
// Whether or not this is a class-based assignment
Class = 0b00010,
// Whether or not a sanitizer was applied to this property
Sanitize = 0b00100,
// Whether or not any player builders within need to produce new players
PlayerBuildersDirty = 0b01000,
// The max amount of bits used to represent these configuration values
BindingAllocationLocked = 0b10000,
BitCountSize = 5,
// There are only five bits here
BitMask = 0b11111
}
/** Used as numeric pointer values to determine what cells to update in the `StylingContext` */
export const enum StylingIndex {
// Position of where the initial styles are stored in the styling context
// This index must align with HOST, see interfaces/view.ts
ElementPosition = 0,
// Index of location where the start of single properties are stored. (`updateStyleProp`)
MasterFlagPosition = 1,
// Position of where the registered directives exist for this styling context
DirectiveRegistryPosition = 2,
// Position of where the initial styles are stored in the styling context
InitialStyleValuesPosition = 3,
InitialClassValuesPosition = 4,
// Index of location where the class index offset value is located
SinglePropOffsetPositions = 5,
// Position of where the last string-based CSS class value was stored (or a cached version of the
// initial styles when a [class] directive is present)
CachedMultiClasses = 6,
// Position of where the last string-based CSS class value was stored
CachedMultiStyles = 7,
// Multi and single entries are stored in `StylingContext` as: Flag; PropertyName; PropertyValue
// Position of where the initial styles are stored in the styling context
HostInstructionsQueue = 8,
PlayerContext = 9,
// Location of single (prop) value entries are stored within the context
SingleStylesStartPosition = 10,
FlagsOffset = 0,
PropertyOffset = 1,
ValueOffset = 2,
PlayerBuilderIndexOffset = 3,
// Size of each multi or single entry (flag + prop + value + playerBuilderIndex)
Size = 4,
// Each flag has a binary digit length of this value
BitCountSize = 14, // (32 - 4) / 2 = ~14
// The binary digit value as a mask
BitMask = 0b11111111111111, // 14 bits
}
/**
* An enum that outlines the bit flag data for directive owner and player index
* values that exist within en entry that lives in the StylingContext.
*
* The values here split a number value into two sets of bits:
* - The first 16 bits are used to store the directiveIndex that owns this style value
* - The other 16 bits are used to store the playerBuilderIndex that is attached to this style
*/
export const enum DirectiveOwnerAndPlayerBuilderIndex {
BitCountSize = 16,
BitMask = 0b1111111111111111
}
/**
* The default directive styling index value for template-based bindings.
*
* All host-level bindings (e.g. `hostStyleProp` and `hostClassMap`) are
* assigned a directive styling index value based on the current directive
* uniqueId and the directive super-class inheritance depth. But for template
* bindings they always have the same directive styling index value.
*/
export const DEFAULT_TEMPLATE_DIRECTIVE_INDEX = 0;