1092 lines
26 KiB
C
1092 lines
26 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
/*
|
|
* cl_layer.c - API for the CL_Layer type
|
|
*/
|
|
|
|
|
|
#include "prtypes.h"
|
|
#include "xp_mem.h" /* For XP_NEW_ZAP */
|
|
#include "xpassert.h" /* For XP_ASSERT, et al */
|
|
#include "xp_list.h"
|
|
#include "layers.h"
|
|
#include "cl_priv.h"
|
|
#ifdef XP_MAC
|
|
#include "macstdlibextras.h" /* for strdup */
|
|
#endif
|
|
|
|
static void
|
|
cl_hidden_changed(CL_Layer *layer);
|
|
|
|
/* Allocate and initialize a new layer */
|
|
CL_Layer *
|
|
CL_NewLayer(char *name, int32 x_offset, int32 y_offset,
|
|
XP_Rect *bbox,
|
|
CL_LayerVTable *vtable,
|
|
uint32 flags, void *client_data)
|
|
{
|
|
CL_Layer *new_layer;
|
|
|
|
new_layer = XP_NEW_ZAP(CL_Layer);
|
|
|
|
if (new_layer == NULL)
|
|
return NULL;
|
|
|
|
new_layer->name = name ? strdup(name) : NULL;
|
|
if (bbox)
|
|
new_layer->bbox = *bbox;
|
|
|
|
/* XXX - consider sharing the vtable, instead of copying it */
|
|
if (vtable)
|
|
new_layer->vtable = *vtable;
|
|
|
|
new_layer->x_offset = x_offset;
|
|
new_layer->y_offset = y_offset;
|
|
|
|
new_layer->hidden = !!(flags & CL_HIDDEN);
|
|
new_layer->scrolling = !!(flags & CL_DONT_SCROLL_WITH_DOCUMENT);
|
|
new_layer->clip_children = !!(flags & CL_CLIP_CHILD_LAYERS);
|
|
new_layer->clip_self = !(flags & CL_DONT_CLIP_SELF);
|
|
new_layer->opaque = !!(flags & CL_OPAQUE);
|
|
new_layer->prefer_draw_onscreen = !!(flags & CL_PREFER_DRAW_ONSCREEN);
|
|
new_layer->prefer_draw_offscreen = !!(flags & CL_PREFER_DRAW_OFFSCREEN);
|
|
new_layer->enumerated = !(flags & CL_DONT_ENUMERATE);
|
|
new_layer->cutout = !!(flags & CL_CUTOUT);
|
|
new_layer->override_inherit_visibility =
|
|
!!(flags & CL_OVERRIDE_INHERIT_VISIBILITY);
|
|
new_layer->client_data = client_data;
|
|
new_layer->draw_region = FE_NULL_REGION;
|
|
|
|
return new_layer;
|
|
}
|
|
|
|
/* Destroy an existing layer */
|
|
void
|
|
CL_DestroyLayer(CL_Layer *layer)
|
|
{
|
|
CL_Layer *parent_layer;
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return;
|
|
|
|
if (layer->compositor)
|
|
cl_LayerDestroyed(layer->compositor, layer);
|
|
|
|
parent_layer = CL_GetLayerParent(layer);
|
|
if (parent_layer)
|
|
CL_RemoveChild(parent_layer, layer);
|
|
|
|
if (layer->vtable.destroy_func)
|
|
(*layer->vtable.destroy_func)(layer);
|
|
|
|
XP_FREEIF(layer->uniform_color);
|
|
XP_FREEIF(layer->name);
|
|
XP_FREE(layer);
|
|
}
|
|
|
|
/* Frees an entire sub-tree, rooted at the specified node */
|
|
void
|
|
CL_DestroyLayerTree(CL_Layer *root)
|
|
{
|
|
CL_Layer *child, *next;
|
|
|
|
XP_ASSERT(root);
|
|
|
|
if (!root)
|
|
return;
|
|
|
|
/* Iterate through the child list. For each child, recurse and free */
|
|
for (child = root->top_child; child; child = next) {
|
|
/* Need to grab the next child here, because child will be freed */
|
|
next = child->sib_below;
|
|
CL_DestroyLayerTree(child);
|
|
}
|
|
|
|
CL_DestroyLayer(root);
|
|
}
|
|
|
|
uint32
|
|
CL_GetLayerFlags(CL_Layer *layer)
|
|
{
|
|
uint32 flags = 0;
|
|
flags |= CL_HIDDEN * (layer->hidden == PR_TRUE);
|
|
flags |= CL_DONT_SCROLL_WITH_DOCUMENT * (layer->scrolling == PR_FALSE);
|
|
flags |= CL_CLIP_CHILD_LAYERS * (layer->clip_children == PR_TRUE);
|
|
flags |= CL_DONT_CLIP_SELF * (layer->clip_self == PR_FALSE);
|
|
flags |= CL_OPAQUE * (layer->opaque == PR_TRUE);
|
|
flags |= CL_PREFER_DRAW_ONSCREEN * (layer->prefer_draw_onscreen == PR_TRUE);
|
|
flags |= CL_PREFER_DRAW_OFFSCREEN * (layer->prefer_draw_offscreen == PR_TRUE);
|
|
flags |= CL_DONT_ENUMERATE * (layer->enumerated == PR_FALSE);
|
|
flags |= CL_CUTOUT * (layer->cutout == PR_TRUE);
|
|
flags |= CL_OVERRIDE_INHERIT_VISIBILITY * (layer->override_inherit_visibility == PR_TRUE);
|
|
|
|
return flags;
|
|
}
|
|
|
|
static PRBool
|
|
cl_change_layer_flags(CL_Layer *layer, uint32 new_flags)
|
|
{
|
|
PRBool success;
|
|
uint32 old_flags = CL_GetLayerFlags(layer);
|
|
uint32 changed_flags = old_flags ^ new_flags;
|
|
|
|
/* Assume success */
|
|
success = PR_TRUE;
|
|
|
|
if (changed_flags == 0)
|
|
return success;
|
|
|
|
if (changed_flags & CL_HIDDEN)
|
|
CL_SetLayerHidden(layer, (PRBool)((new_flags & CL_HIDDEN) != 0));
|
|
|
|
if (changed_flags & CL_OVERRIDE_INHERIT_VISIBILITY) {
|
|
layer->override_inherit_visibility =
|
|
!!(new_flags & CL_OVERRIDE_INHERIT_VISIBILITY);
|
|
cl_hidden_changed(layer);
|
|
}
|
|
|
|
if (changed_flags &
|
|
(CL_DONT_SCROLL_WITH_DOCUMENT | CL_CLIP_CHILD_LAYERS | CL_DONT_CLIP_SELF)) {
|
|
XP_ASSERT(0); /* We don't support changing this on the fly yet */
|
|
success = PR_FALSE;
|
|
}
|
|
|
|
if (changed_flags & CL_OPAQUE) {
|
|
layer->opaque = ((new_flags & CL_OPAQUE) != 0);
|
|
if (!layer->opaque)
|
|
CL_SetLayerUniformColor(layer, NULL);
|
|
}
|
|
|
|
if (changed_flags & CL_PREFER_DRAW_ONSCREEN) {
|
|
layer->prefer_draw_onscreen = (new_flags & CL_PREFER_DRAW_ONSCREEN) != 0;
|
|
layer->prefer_draw_offscreen = PR_FALSE;
|
|
}
|
|
|
|
if (changed_flags & CL_PREFER_DRAW_OFFSCREEN) {
|
|
layer->prefer_draw_offscreen = (new_flags & CL_PREFER_DRAW_OFFSCREEN) != 0;
|
|
layer->prefer_draw_onscreen = PR_FALSE;
|
|
}
|
|
|
|
if (changed_flags & CL_DONT_ENUMERATE)
|
|
layer->enumerated = (new_flags & CL_DONT_ENUMERATE) == 0;
|
|
|
|
if (changed_flags & CL_CUTOUT)
|
|
layer->cutout = (new_flags & CL_CUTOUT) != 0;
|
|
|
|
return success;
|
|
}
|
|
|
|
extern PRBool
|
|
CL_ChangeLayerFlag(CL_Layer *layer, uint32 flag, PRBool value)
|
|
{
|
|
uint32 old_flags, new_flags;
|
|
|
|
LOCK_LAYERS(layer);
|
|
|
|
old_flags = CL_GetLayerFlags(layer);
|
|
if (value)
|
|
new_flags = old_flags | flag;
|
|
else
|
|
new_flags = old_flags & ~flag;
|
|
|
|
cl_change_layer_flags(layer, new_flags);
|
|
|
|
UNLOCK_LAYERS(layer);
|
|
|
|
return value;
|
|
}
|
|
|
|
PRBool
|
|
CL_ForEachChildOfLayer(CL_Layer *parent,
|
|
CL_ChildOfLayerFunc func,
|
|
void *closure)
|
|
{
|
|
CL_Layer *child, *next;
|
|
PRBool done;
|
|
CL_Compositor *compositor;
|
|
|
|
XP_ASSERT(parent);
|
|
XP_ASSERT(func);
|
|
|
|
if (!parent)
|
|
return PR_FALSE;
|
|
|
|
compositor = parent->compositor;
|
|
if (compositor)
|
|
LOCK_COMPOSITOR(compositor);
|
|
|
|
/* Iterate through the child list. For each child, recurse and free */
|
|
for (child = parent->top_child; child; child = next) {
|
|
/*
|
|
* Need to grab the next child here, in case child
|
|
* is no longer valid
|
|
*/
|
|
next = child->sib_below;
|
|
if (func) {
|
|
done = (PRBool) ! (*func)(child, closure);
|
|
if (done) {
|
|
if (compositor)
|
|
UNLOCK_COMPOSITOR(compositor);
|
|
return PR_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (compositor)
|
|
UNLOCK_COMPOSITOR(compositor);
|
|
return PR_TRUE;
|
|
}
|
|
|
|
void
|
|
cl_SetCompositorRecursive(CL_Layer *layer, CL_Compositor *compositor)
|
|
{
|
|
CL_Layer *child;
|
|
|
|
for(child = layer->top_child; child; child = child->sib_below)
|
|
cl_SetCompositorRecursive(child, compositor);
|
|
|
|
layer->compositor = compositor;
|
|
}
|
|
|
|
/* Insert a layer into the layer tree as a child of the parent layer.
|
|
* If sibling is NULL, the layer is added as the topmost (in z-order) child
|
|
* if where==CL_ABOVE or the bottommost child if where==CL_BELOW.
|
|
* If sibling is non-NULL, the layer is added above or below (in z-order)
|
|
* sibling based on the value of where.
|
|
*/
|
|
void
|
|
CL_InsertChild(CL_Layer *parent, CL_Layer *child,
|
|
CL_Layer *sibling, CL_LayerPosition where)
|
|
{
|
|
XP_ASSERT(parent);
|
|
|
|
if (!parent)
|
|
return;
|
|
|
|
LOCK_LAYERS(parent);
|
|
|
|
/* If no sibling is specified... */
|
|
if (sibling == NULL) {
|
|
/* If there are no children */
|
|
if (parent->top_child == NULL)
|
|
parent->top_child = parent->bottom_child = child;
|
|
|
|
else if (where == CL_ABOVE) {
|
|
/* Add it as the first child */
|
|
child->sib_below = parent->top_child;
|
|
child->sib_above = NULL;
|
|
parent->top_child = child;
|
|
if (child->sib_below)
|
|
child->sib_below->sib_above = child;
|
|
child->z_index = child->sib_below->z_index;
|
|
}
|
|
|
|
else {
|
|
/* Add it as the last child */
|
|
child->sib_above = parent->bottom_child;
|
|
child->sib_below = NULL;
|
|
parent->bottom_child = child;
|
|
if (child->sib_above)
|
|
child->sib_above->sib_below = child;
|
|
child->z_index = child->sib_above->z_index;
|
|
}
|
|
}
|
|
else {
|
|
if (where == CL_ABOVE) {
|
|
child->sib_above = sibling->sib_above;
|
|
child->sib_below = sibling;
|
|
/* If there is a sibling above this, point it at child */
|
|
if (sibling->sib_above)
|
|
sibling->sib_above->sib_below = child;
|
|
/* Otherwise, sibling was the first child */
|
|
else
|
|
parent->top_child = child;
|
|
sibling->sib_above = child;
|
|
}
|
|
else {
|
|
child->sib_below = sibling->sib_below;
|
|
child->sib_above = sibling;
|
|
/* If there is a sibling below this, point it at child */
|
|
if (sibling->sib_below)
|
|
sibling->sib_below->sib_above = child;
|
|
/* Otherwise, sibling was the last child */
|
|
else
|
|
parent->bottom_child = child;
|
|
sibling->sib_below = child;
|
|
}
|
|
child->z_index = sibling->z_index;
|
|
}
|
|
|
|
cl_SetCompositorRecursive(child, parent->compositor);
|
|
child->parent = parent;
|
|
|
|
if (child->compositor)
|
|
cl_LayerAdded(child->compositor, child);
|
|
|
|
UNLOCK_LAYERS(parent);
|
|
}
|
|
|
|
void
|
|
CL_InsertChildByZ(CL_Layer *parent, CL_Layer *child, int32 z_index)
|
|
{
|
|
CL_Layer *sibling;
|
|
XP_ASSERT(parent);
|
|
|
|
if (!parent)
|
|
return;
|
|
|
|
LOCK_LAYERS(parent);
|
|
|
|
for (sibling = parent->top_child; sibling; sibling = sibling->sib_below) {
|
|
if (sibling->z_index <= z_index)
|
|
break;
|
|
}
|
|
|
|
if (sibling)
|
|
CL_InsertChild(parent, child, sibling, CL_ABOVE);
|
|
else
|
|
CL_InsertChild(parent, child, NULL, CL_BELOW);
|
|
|
|
child->z_index = z_index;
|
|
|
|
UNLOCK_LAYERS(parent);
|
|
}
|
|
|
|
/* Removes a layer from a parent's sub-tree */
|
|
void
|
|
CL_RemoveChild(CL_Layer *parent, CL_Layer *child)
|
|
{
|
|
XP_ASSERT(parent);
|
|
XP_ASSERT(child);
|
|
|
|
if (!parent || !child)
|
|
return;
|
|
|
|
LOCK_LAYERS(parent);
|
|
|
|
if (child == parent->top_child)
|
|
parent->top_child = child->sib_below;
|
|
if (child == parent->bottom_child)
|
|
parent->bottom_child = child->sib_above;
|
|
|
|
if (child->sib_above)
|
|
child->sib_above->sib_below = child->sib_below;
|
|
if (child->sib_below)
|
|
child->sib_below->sib_above = child->sib_above;
|
|
|
|
if (CL_IsMouseEventGrabber(child->compositor, child))
|
|
CL_GrabMouseEvents(child->compositor, NULL);
|
|
if (CL_IsKeyEventGrabber(child->compositor, child))
|
|
CL_GrabKeyEvents(child->compositor, NULL);
|
|
|
|
child->parent = NULL;
|
|
|
|
cl_LayerRemoved(parent->compositor, child);
|
|
|
|
UNLOCK_LAYERS(parent);
|
|
}
|
|
|
|
/* A rectangle that covers the entire world.
|
|
Note: We don't use the extrema values for 32-bit integers. Instead,
|
|
we deliberately leave headroom to avoid overflow of the coordinates
|
|
as a result of translating the rect. */
|
|
static XP_Rect max_rect = CL_MAX_RECT;
|
|
|
|
/* Return the clipping box, in document coordinates, that this layer
|
|
applies to child layers */
|
|
static XP_Rect *
|
|
cl_clipping_bbox(CL_Layer *layer)
|
|
{
|
|
if (! layer)
|
|
return &max_rect;
|
|
|
|
if (layer->clip_children)
|
|
return &layer->clipped_bbox;
|
|
|
|
return cl_clipping_bbox(layer->parent);
|
|
}
|
|
|
|
/* Propagate changes in the bboxes of layers to their children. This
|
|
may cause the origin of child layers to change and may also change
|
|
their widths and heights due to clipping. */
|
|
static PRBool
|
|
cl_bbox_changed_recurse(CL_Layer *layer, XP_Rect *parent_clip_bbox,
|
|
PRBool ancestor_not_hidden,
|
|
int32 x_parent_origin, int32 y_parent_origin)
|
|
{
|
|
CL_Layer *child;
|
|
XP_Rect *child_clip_bbox;
|
|
int32 x_origin, y_origin;
|
|
PRBool visible, not_hidden;
|
|
int descendant_visible;
|
|
XP_Rect *clipped_bbox = &layer->clipped_bbox;
|
|
XP_Rect *layer_bbox = &layer->bbox;
|
|
PRBool clip_children = (PRBool)(layer->clip_children && layer->clip_self);
|
|
|
|
/* Compute new layer origin, in document coordinates */
|
|
x_origin = layer->x_origin = x_parent_origin + layer->x_offset;
|
|
y_origin = layer->y_origin = y_parent_origin + layer->y_offset;
|
|
|
|
/* A layer is considered visible for purposes of compositing if ...
|
|
= the layer is not hidden, and
|
|
= none of the layer's ancestors is hidden, and
|
|
= the layer is not entirely clipped by ancestor layers */
|
|
not_hidden = visible = (PRBool)(!layer->hidden &&
|
|
(ancestor_not_hidden || layer->override_inherit_visibility));
|
|
|
|
if (layer->clip_self) {
|
|
|
|
/* Get layer bounds in coordinates relative to parent layer */
|
|
XP_CopyRect(layer_bbox, clipped_bbox);
|
|
|
|
/* Convert to document coordinates */
|
|
XP_OffsetRect(clipped_bbox, x_origin, y_origin);
|
|
|
|
/* Clip by parents bbox */
|
|
if (parent_clip_bbox) {
|
|
|
|
if (layer->cutout) {
|
|
/* Special case: a cutout layer is rendered invisibly if it is
|
|
clipped, even partially, by an ancestor. */
|
|
visible &= XP_RectContainsRect(parent_clip_bbox, clipped_bbox);
|
|
XP_IntersectRect(clipped_bbox, parent_clip_bbox, clipped_bbox);
|
|
} else {
|
|
XP_IntersectRect(clipped_bbox, parent_clip_bbox, clipped_bbox);
|
|
/* "Normal" layers are only invisible if they're wholly clipped
|
|
by ancestors. */
|
|
visible &= !XP_IsEmptyRect(clipped_bbox);
|
|
}
|
|
}
|
|
} else {
|
|
XP_CopyRect(parent_clip_bbox, clipped_bbox);
|
|
}
|
|
|
|
layer->visible = visible;
|
|
child_clip_bbox = clip_children ? clipped_bbox : parent_clip_bbox;
|
|
|
|
descendant_visible = 0;
|
|
for (child = layer->top_child; child; child = child->sib_below) {
|
|
descendant_visible |=
|
|
(int)cl_bbox_changed_recurse(child, child_clip_bbox, not_hidden,
|
|
layer->x_origin, layer->y_origin);
|
|
}
|
|
|
|
layer->visible = visible;
|
|
|
|
layer->descendant_visible = (PRBool)descendant_visible;
|
|
|
|
return visible;
|
|
}
|
|
|
|
static void
|
|
cl_property_changed(CL_Layer *layer)
|
|
{
|
|
int32 x_offset, y_offset;
|
|
XP_Rect *child_clip_bbox;
|
|
PRBool ancestor_not_hidden;
|
|
CL_Layer *parent, *layer2;
|
|
|
|
if (layer->compositor) {
|
|
layer->compositor->recompute_update_region = PR_TRUE;
|
|
cl_start_compositor_timeouts(layer->compositor);
|
|
}
|
|
|
|
parent = layer->parent;
|
|
if (parent) {
|
|
layer2 = parent;
|
|
ancestor_not_hidden = PR_TRUE;
|
|
while (layer2) {
|
|
if (layer2->hidden) {
|
|
ancestor_not_hidden = PR_FALSE;
|
|
break;
|
|
}
|
|
layer2 = layer2->parent;
|
|
}
|
|
child_clip_bbox = cl_clipping_bbox(parent);
|
|
x_offset = parent->x_origin;
|
|
y_offset = parent->y_origin;
|
|
} else {
|
|
ancestor_not_hidden = PR_TRUE;
|
|
child_clip_bbox = &max_rect;
|
|
x_offset = 0;
|
|
y_offset = 0;
|
|
}
|
|
|
|
/* If a layer is visible for compositing, then so are all its ancestors */
|
|
if (cl_bbox_changed_recurse(layer, child_clip_bbox, ancestor_not_hidden,
|
|
x_offset, y_offset))
|
|
while (parent) {
|
|
parent->descendant_visible = PR_TRUE;
|
|
parent = parent->parent;
|
|
}
|
|
}
|
|
|
|
static void
|
|
cl_bbox_changed(CL_Layer *layer)
|
|
{
|
|
cl_property_changed(layer);
|
|
}
|
|
|
|
void
|
|
cl_ParentChanged(CL_Layer *layer)
|
|
{
|
|
cl_property_changed(layer);
|
|
}
|
|
|
|
static void
|
|
cl_hidden_changed(CL_Layer *layer)
|
|
{
|
|
cl_property_changed(layer);
|
|
}
|
|
|
|
static void
|
|
cl_position_changed(CL_Layer *layer)
|
|
{
|
|
cl_property_changed(layer);
|
|
}
|
|
|
|
static void
|
|
cl_set_hidden (CL_Layer *layer, PRBool hidden)
|
|
{
|
|
if (hidden == layer->hidden)
|
|
return;
|
|
|
|
layer->hidden = hidden;
|
|
|
|
/* If the layer is currently visible and it's to be hidden, or the
|
|
layer isn't visible and it's being un-hidden, update the area
|
|
occupied by the layer. */
|
|
if (layer->visible == hidden)
|
|
cl_hidden_changed(layer);
|
|
}
|
|
|
|
/* Change the physical position of a layer with relative values */
|
|
/* May trigger asynchronous drawing to update screen */
|
|
void
|
|
CL_OffsetLayer(CL_Layer *layer, int32 x_offset, int32 y_offset)
|
|
{
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return;
|
|
|
|
CL_MoveLayer(layer, layer->x_offset + x_offset, layer->y_offset + y_offset);
|
|
}
|
|
|
|
/* Change the position of a layer. XY coordinates are relative to the
|
|
origin of the parent layer. May trigger asynchronous drawing to
|
|
update screen */
|
|
void
|
|
CL_MoveLayer(CL_Layer *layer, int32 x, int32 y)
|
|
{
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return;
|
|
|
|
LOCK_LAYERS(layer);
|
|
|
|
/* Layer position changed ? */
|
|
if ((x == layer->x_offset) && (y == layer->y_offset)) {
|
|
UNLOCK_LAYERS(layer);
|
|
return;
|
|
}
|
|
|
|
layer->x_offset = x;
|
|
layer->y_offset = y;
|
|
cl_position_changed(layer);
|
|
cl_LayerMoved(layer->compositor, layer);
|
|
|
|
UNLOCK_LAYERS(layer);
|
|
}
|
|
|
|
/*
|
|
* Change the dimensions of a layer
|
|
* May trigger asynchronous drawing to update screen
|
|
* FIXME - There is a performance bug here that shows up when a
|
|
* layer's width grows, but its height shrinks or vice-versa.
|
|
* The update rectangles are overdrawn for these cases.
|
|
*/
|
|
void
|
|
CL_ResizeLayer(CL_Layer *layer, int32 width, int32 height)
|
|
{
|
|
XP_Rect *layer_bbox;
|
|
int32 old_width, old_height;
|
|
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer) /* Paranoia */
|
|
return;
|
|
|
|
LOCK_LAYERS(layer);
|
|
|
|
/* Get the existing layer width and height */
|
|
layer_bbox = &layer->bbox;
|
|
old_width = layer_bbox->right - layer_bbox->left;
|
|
old_height = layer_bbox->bottom - layer_bbox->top;
|
|
if ((width == old_width) && (height == old_height)) {
|
|
UNLOCK_LAYERS(layer);
|
|
return;
|
|
}
|
|
|
|
/* Reset layer bbox to new size */
|
|
layer_bbox->right = layer_bbox->left + width;
|
|
layer_bbox->bottom = layer_bbox->top + height;
|
|
cl_bbox_changed(layer);
|
|
|
|
UNLOCK_LAYERS(layer);
|
|
}
|
|
|
|
int32
|
|
CL_GetLayerXOffset(CL_Layer *layer)
|
|
{
|
|
return layer->x_offset;
|
|
}
|
|
|
|
int32
|
|
CL_GetLayerYOffset(CL_Layer *layer)
|
|
{
|
|
return layer->y_offset;
|
|
}
|
|
|
|
int32
|
|
CL_GetLayerXOrigin(CL_Layer *layer)
|
|
{
|
|
return layer->x_origin;
|
|
}
|
|
|
|
int32
|
|
CL_GetLayerYOrigin(CL_Layer *layer)
|
|
{
|
|
return layer->y_origin;
|
|
}
|
|
|
|
void
|
|
CL_SetLayerUniformColor(CL_Layer *layer, CL_Color *color)
|
|
{
|
|
if (color) {
|
|
CL_Color *copy_color = XP_NEW(CL_Color);
|
|
XP_ASSERT(copy_color);
|
|
if (!copy_color)
|
|
return;
|
|
*copy_color = *color;
|
|
layer->uniform_color = copy_color;
|
|
} else {
|
|
XP_FREEIF(layer->uniform_color);
|
|
}
|
|
}
|
|
|
|
void
|
|
CL_SetLayerOpaque(CL_Layer *layer, PRBool opaque)
|
|
{
|
|
layer->opaque = opaque;
|
|
}
|
|
|
|
PRBool
|
|
CL_GetLayerOpaque(CL_Layer *layer)
|
|
{
|
|
return layer->opaque;
|
|
}
|
|
|
|
int32
|
|
CL_GetLayerZIndex(CL_Layer *layer)
|
|
{
|
|
return layer->z_index;
|
|
}
|
|
|
|
/* Change the bounding box of a layer */
|
|
void
|
|
CL_SetLayerBbox(CL_Layer *layer, XP_Rect *new_bbox)
|
|
{
|
|
XP_ASSERT(layer);
|
|
if (!layer)
|
|
return;
|
|
|
|
LOCK_LAYERS(layer);
|
|
|
|
/* Don't do anything if the bbox didn't change. */
|
|
if (XP_EqualRect(new_bbox, &layer->bbox)) {
|
|
UNLOCK_LAYERS(layer);
|
|
return;
|
|
}
|
|
|
|
layer->bbox = *new_bbox;
|
|
cl_sanitize_bbox(&layer->bbox);
|
|
|
|
cl_bbox_changed(layer);
|
|
|
|
UNLOCK_LAYERS(layer);
|
|
}
|
|
|
|
void
|
|
CL_GetLayerBbox(CL_Layer *layer, XP_Rect *bbox)
|
|
{
|
|
XP_ASSERT(layer);
|
|
XP_ASSERT(bbox);
|
|
|
|
if (!layer || !bbox)
|
|
return;
|
|
|
|
LOCK_LAYERS(layer);
|
|
bbox->left = layer->bbox.left;
|
|
bbox->top = layer->bbox.top;
|
|
bbox->right = layer->bbox.right;
|
|
bbox->bottom = layer->bbox.bottom;
|
|
UNLOCK_LAYERS(layer);
|
|
}
|
|
|
|
void
|
|
CL_GetLayerBboxAbsolute(CL_Layer *layer, XP_Rect *bbox)
|
|
{
|
|
XP_ASSERT(layer);
|
|
XP_ASSERT(bbox);
|
|
|
|
if (!layer || !bbox)
|
|
return;
|
|
|
|
LOCK_LAYERS(layer);
|
|
bbox->left = layer->x_origin;
|
|
bbox->top = layer->y_origin;
|
|
bbox->right = layer->x_origin + (layer->bbox.right - layer->bbox.left);
|
|
bbox->bottom = layer->y_origin + (layer->bbox.bottom - layer->bbox.top);
|
|
UNLOCK_LAYERS(layer);
|
|
}
|
|
|
|
char *
|
|
CL_GetLayerName(CL_Layer *layer)
|
|
{
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return NULL;
|
|
else
|
|
return layer->name;
|
|
}
|
|
|
|
void
|
|
CL_SetLayerName(CL_Layer *layer, char *name)
|
|
{
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return;
|
|
|
|
layer->name = name;
|
|
}
|
|
|
|
PRBool
|
|
CL_GetLayerHidden(CL_Layer *layer)
|
|
{
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return PR_FALSE;
|
|
else
|
|
return layer->hidden;
|
|
}
|
|
|
|
void
|
|
CL_SetLayerHidden(CL_Layer *layer, PRBool hidden)
|
|
{
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return;
|
|
|
|
cl_set_hidden(layer, hidden);
|
|
}
|
|
|
|
void *
|
|
CL_GetLayerClientData(CL_Layer *layer)
|
|
{
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return NULL;
|
|
else
|
|
return layer->client_data;
|
|
}
|
|
|
|
void
|
|
CL_SetLayerClientData(CL_Layer *layer, void *client_data)
|
|
{
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return;
|
|
|
|
layer->client_data = client_data;
|
|
}
|
|
|
|
CL_Compositor *
|
|
CL_GetLayerCompositor(CL_Layer *layer)
|
|
{
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return NULL;
|
|
else
|
|
return layer->compositor;
|
|
}
|
|
|
|
CL_Layer *
|
|
CL_GetLayerSiblingAbove(CL_Layer *layer)
|
|
{
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return NULL;
|
|
else
|
|
return layer->sib_above;
|
|
}
|
|
|
|
CL_Layer *
|
|
CL_GetLayerSiblingBelow(CL_Layer *layer)
|
|
{
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return NULL;
|
|
else
|
|
return layer->sib_below;
|
|
}
|
|
|
|
static CL_Layer *
|
|
cl_bottommost(CL_Layer *layer)
|
|
{
|
|
while (layer->bottom_child && layer->bottom_child->z_index < 0)
|
|
layer = layer->bottom_child;
|
|
|
|
return layer;
|
|
}
|
|
|
|
static CL_Layer *
|
|
cl_GetLayerAbove2(CL_Layer *layer, PRBool consider_children)
|
|
{
|
|
CL_Layer *layer_above;
|
|
|
|
if (! layer)
|
|
return NULL;
|
|
|
|
if (consider_children &&
|
|
layer->top_child && (layer->top_child->z_index >= 0)) {
|
|
CL_Layer *child;
|
|
|
|
child = layer->bottom_child;
|
|
while (child->z_index < 0)
|
|
child = child->sib_above;
|
|
|
|
layer_above = child;
|
|
} else if (layer->z_index < 0) {
|
|
if (layer->sib_above && (layer->sib_above->z_index < 0))
|
|
layer_above = cl_bottommost(layer->sib_above);
|
|
else
|
|
layer_above = layer->parent;
|
|
} else {
|
|
if (layer->sib_above)
|
|
layer_above = cl_bottommost(layer->sib_above);
|
|
else
|
|
layer_above = cl_GetLayerAbove2(layer->parent, PR_FALSE);
|
|
}
|
|
|
|
if (!layer_above)
|
|
return NULL;
|
|
|
|
if (!layer_above->enumerated)
|
|
return cl_GetLayerAbove2(layer_above, PR_TRUE);
|
|
|
|
return layer_above;
|
|
}
|
|
|
|
CL_Layer *
|
|
CL_GetLayerAbove(CL_Layer *layer)
|
|
{
|
|
CL_Layer *layer_above;
|
|
XP_ASSERT(layer);
|
|
LOCK_LAYERS(layer);
|
|
layer_above = cl_GetLayerAbove2(layer, PR_TRUE);
|
|
UNLOCK_LAYERS(layer);
|
|
return layer_above;
|
|
}
|
|
|
|
static CL_Layer *
|
|
cl_topmost(CL_Layer *layer)
|
|
{
|
|
while (layer->top_child && layer->top_child->z_index >= 0)
|
|
layer = layer->top_child;
|
|
|
|
return layer;
|
|
}
|
|
|
|
static CL_Layer *
|
|
cl_GetLayerBelow2(CL_Layer *layer, PRBool consider_children)
|
|
{
|
|
CL_Layer *layer_below;
|
|
|
|
if (! layer)
|
|
return NULL;
|
|
|
|
if (consider_children &&
|
|
layer->bottom_child && (layer->bottom_child->z_index < 0)) {
|
|
CL_Layer *child;
|
|
|
|
child = layer->top_child;
|
|
while (child->z_index >= 0)
|
|
child = child->sib_below;
|
|
|
|
layer_below = child;
|
|
} else if (layer->z_index >= 0) {
|
|
if (layer->sib_below && (layer->sib_below->z_index >= 0))
|
|
layer_below = cl_topmost(layer->sib_below);
|
|
else
|
|
layer_below = layer->parent;
|
|
} else {
|
|
if (layer->sib_below)
|
|
layer_below = cl_topmost(layer->sib_below);
|
|
else
|
|
layer_below = cl_GetLayerBelow2(layer->parent, PR_FALSE);
|
|
}
|
|
|
|
if (!layer_below)
|
|
return NULL;
|
|
|
|
if (!layer_below->enumerated)
|
|
return cl_GetLayerBelow2(layer_below, PR_TRUE);
|
|
|
|
return layer_below;
|
|
}
|
|
|
|
CL_Layer *
|
|
CL_GetLayerBelow(CL_Layer *layer)
|
|
{
|
|
CL_Layer *layer_below;
|
|
XP_ASSERT(layer);
|
|
LOCK_LAYERS(layer);
|
|
layer_below = cl_GetLayerBelow2(layer, PR_TRUE);
|
|
UNLOCK_LAYERS(layer);
|
|
return layer_below;
|
|
}
|
|
|
|
CL_Layer *
|
|
CL_GetLayerChildByName(CL_Layer *layer, char *name)
|
|
{
|
|
CL_Layer *child;
|
|
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return NULL;
|
|
for (child = layer->top_child; child; child = child->sib_below)
|
|
if (child->name && strcmp(child->name, name) == 0)
|
|
return child;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CL_Layer *
|
|
CL_GetLayerChildByIndex(CL_Layer *layer, uint index)
|
|
{
|
|
CL_Layer *child;
|
|
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return NULL;
|
|
|
|
LOCK_LAYERS(layer);
|
|
for (child = layer->bottom_child; child && index; child = child->sib_above) {
|
|
if (child->enumerated)
|
|
index--;
|
|
}
|
|
|
|
while (child && !child->enumerated)
|
|
child = child->sib_above;
|
|
|
|
UNLOCK_LAYERS(layer);
|
|
return child;
|
|
}
|
|
|
|
int
|
|
CL_GetLayerChildCount(CL_Layer *layer)
|
|
{
|
|
CL_Layer *child;
|
|
int child_count = 0;
|
|
|
|
if (!layer)
|
|
return 0;
|
|
|
|
XP_ASSERT(layer);
|
|
|
|
LOCK_LAYERS(layer);
|
|
for (child = layer->top_child; child; child = child->sib_below) {
|
|
if (child->enumerated)
|
|
child_count++;
|
|
}
|
|
UNLOCK_LAYERS(layer);
|
|
|
|
return child_count;
|
|
}
|
|
|
|
void
|
|
CL_GetLayerVTable(CL_Layer *layer, CL_LayerVTable *vtable)
|
|
{
|
|
XP_ASSERT(layer);
|
|
XP_ASSERT(vtable);
|
|
|
|
if (!layer || !vtable)
|
|
return;
|
|
|
|
*vtable = layer->vtable;
|
|
}
|
|
|
|
|
|
void
|
|
CL_SetLayerVTable(CL_Layer *layer, CL_LayerVTable *vtable)
|
|
{
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return;
|
|
|
|
if (vtable)
|
|
layer->vtable = *vtable;
|
|
else {
|
|
layer->vtable.painter_func = NULL;
|
|
layer->vtable.region_cleanup_func = NULL;
|
|
layer->vtable.event_handler_func = NULL;
|
|
layer->vtable.destroy_func = NULL;
|
|
}
|
|
}
|
|
|
|
CL_Layer *CL_GetLayerParent(CL_Layer *layer)
|
|
{
|
|
XP_ASSERT(layer);
|
|
|
|
if (!layer)
|
|
return NULL;
|
|
else
|
|
return layer->parent;
|
|
}
|
|
|
|
|