186 lines
5.4 KiB
C
186 lines
5.4 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.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
/*
|
|
* cl_paint.c - The default layer creation routine
|
|
*/
|
|
|
|
|
|
#include "prtypes.h"
|
|
#include "layers.h"
|
|
#include "cl_priv.h"
|
|
|
|
/* Convert rectangle from window to document coordinate system */
|
|
void
|
|
CL_WindowToDocumentRect(CL_Compositor *compositor, XP_Rect *rect)
|
|
{
|
|
XP_OffsetRect(rect, compositor->x_offset, compositor->y_offset);
|
|
}
|
|
|
|
/* Convert rectangle from document to window coordinate system */
|
|
void
|
|
CL_DocumentToWindowRect(CL_Compositor *compositor, XP_Rect *rect)
|
|
{
|
|
XP_OffsetRect(rect, -compositor->x_offset, -compositor->y_offset);
|
|
}
|
|
|
|
/* Convert a rect from window to layer coordinate system */
|
|
void
|
|
CL_WindowToLayerRect(CL_Compositor *compositor, CL_Layer *layer,
|
|
XP_Rect *rect)
|
|
{
|
|
int32 x_offset = compositor->x_offset - layer->x_origin;
|
|
int32 y_offset = compositor->y_offset - layer->y_origin;
|
|
|
|
XP_OffsetRect(rect, x_offset, y_offset);
|
|
}
|
|
|
|
/* Convert a rect from window to layer coordinate system */
|
|
void
|
|
CL_LayerToWindowRect(CL_Compositor *compositor, CL_Layer *layer,
|
|
XP_Rect *rect)
|
|
{
|
|
int32 x_offset = compositor->x_offset - layer->x_origin;
|
|
int32 y_offset = compositor->y_offset - layer->y_origin;
|
|
|
|
XP_OffsetRect(rect, -x_offset, -y_offset);
|
|
}
|
|
|
|
/*
|
|
* The assumption for the next two routines is that the layer is
|
|
* visible within the window i.e. translating to and from layer
|
|
* coordinates won't result in a 16-bit overflow.
|
|
*/
|
|
/* Convert a region from layer to window coordinate system */
|
|
void
|
|
CL_LayerToWindowRegion(CL_Compositor *compositor, CL_Layer *layer,
|
|
FE_Region region)
|
|
{
|
|
int32 x_offset = layer->x_origin - compositor->x_offset;
|
|
int32 y_offset = layer->y_origin - compositor->y_offset;
|
|
|
|
if ((x_offset <= FE_MAX_REGION_COORDINATE) &&
|
|
(y_offset <= FE_MAX_REGION_COORDINATE))
|
|
FE_OffsetRegion(region, x_offset, y_offset);
|
|
}
|
|
|
|
/* Convert a region from window to layer coordinate system */
|
|
void
|
|
CL_WindowToLayerRegion(CL_Compositor *compositor, CL_Layer *layer,
|
|
FE_Region region)
|
|
{
|
|
int32 x_offset = compositor->x_offset - layer->x_origin;
|
|
int32 y_offset = compositor->y_offset - layer->y_origin;
|
|
|
|
if ((x_offset <= FE_MAX_REGION_COORDINATE) &&
|
|
(y_offset <= FE_MAX_REGION_COORDINATE))
|
|
FE_OffsetRegion(region, x_offset, y_offset);
|
|
}
|
|
|
|
typedef struct {
|
|
int num_rects;
|
|
uint32 covered_area;
|
|
} cl_entropy_closure;
|
|
|
|
static void
|
|
cl_region_entropy_rect_func(cl_entropy_closure *closure,
|
|
XP_Rect *rect)
|
|
{
|
|
uint32 rect_area;
|
|
|
|
rect_area = (rect->right - rect->left) * (rect->bottom - rect->top);
|
|
|
|
/* Small areas cause higher entropy, since they tend to do
|
|
lots of clipping when overdraw occurs. */
|
|
if (rect_area > 1000)
|
|
closure->covered_area += rect_area;
|
|
closure->num_rects++;
|
|
}
|
|
|
|
/* Return a number between 0 and 1.0 indicating the "entropy" of a
|
|
region. (For now, returns something approximating the fraction of
|
|
uncovered area in the region's bounding box.) */
|
|
float
|
|
CL_RegionEntropy(FE_Region region)
|
|
{
|
|
uint32 bbox_area;
|
|
XP_Rect bbox;
|
|
cl_entropy_closure closure;
|
|
|
|
|
|
FE_GetRegionBoundingBox(region, &bbox);
|
|
bbox_area = (bbox.right - bbox.left) * (bbox.bottom - bbox.top);
|
|
|
|
closure.num_rects = 0;
|
|
closure.covered_area = 0;
|
|
FE_ForEachRectInRegion(region,
|
|
(FE_RectInRegionFunc)cl_region_entropy_rect_func,
|
|
(void *)&closure);
|
|
|
|
if (closure.num_rects <= 1)
|
|
return 0.0F;
|
|
|
|
return 1.0F - (float)closure.covered_area / (float)bbox_area;
|
|
}
|
|
|
|
|
|
/* Like FE_ForEachRectInRegion(), except that there is no guarantee
|
|
that the individual rects delivered to the callback function
|
|
*exactly* cover the region. (They may cover more than the region).
|
|
This may be used for more efficient painting because it is faster
|
|
to paint fewer large rects than many small rects.) */
|
|
void
|
|
CL_ForEachRectCoveringRegion(FE_Region region, FE_RectInRegionFunc func,
|
|
void *closure)
|
|
{
|
|
# define ENTROPY_THRESHOLD 0.85
|
|
|
|
float entropy = CL_RegionEntropy(region);
|
|
|
|
if (entropy < ENTROPY_THRESHOLD) {
|
|
XP_Rect bbox;
|
|
FE_GetRegionBoundingBox(region, &bbox);
|
|
(*func)(closure, &bbox);
|
|
} else {
|
|
FE_ForEachRectInRegion(region, func, closure);
|
|
}
|
|
}
|
|
|
|
void
|
|
cl_XorRegion(FE_Region src1, FE_Region src2, FE_Region dst)
|
|
{
|
|
FE_Region tmp = FE_CreateRegion();
|
|
|
|
if (tmp == FE_NULL_REGION) /* OOM */
|
|
return;
|
|
|
|
FE_SubtractRegion(src1, src2, tmp);
|
|
FE_SubtractRegion(src2, src1, dst);
|
|
FE_UnionRegion(tmp, dst, dst);
|
|
FE_DestroyRegion(tmp);
|
|
}
|
|
|
|
void
|
|
cl_sanitize_bbox(XP_Rect *bbox)
|
|
{
|
|
if (bbox->left > bbox->right)
|
|
bbox->right = bbox->left;
|
|
|
|
if (bbox->top > bbox->bottom)
|
|
bbox->bottom = bbox->top;
|
|
}
|