Milán Major

netscape-revival

1 branch
Code

lib/layout/laylayer.c

/* -*- Mode: C; tab-width: 4; tabs-indent-mode: t -*- */

#include "xp.h"
#include "pa_tags.h"
#include "layout.h"
#include "layers.h"

/**********************
 *
 * BLINK tag-related layering code
 *
 **********************/

#define LO_BLINK_RATE 750

typedef struct lo_BlinkStruct {
    MWContext *context;
    lo_DocState *state;
    LO_TextStruct *text;
} lo_BlinkStruct;

static void
lo_blink_destroy_func(CL_Layer *layer)
{
    CL_RemoveLayerFromGroup(layer->compositor, layer, "_BLINKGROUP");
    XP_FREE(layer->author_data);
}

static FE_Region 
lo_blink_painter_func(void *drawable, 
                      CL_Layer *layer, 
                      FE_Region update_region,
                      XP_Bool allow_transparency)
{
    lo_BlinkStruct *closure = (lo_BlinkStruct *)layer->author_data;
  
    /* This layer can't draw in the back-to-front phase */
    if (allow_transparency == FALSE)
        return NULL;

    /* Draw the text element associated with this layer */
    lo_DisplayText(closure->context, FE_VIEW, closure->text,
                   FALSE, TRUE);
}

static void
lo_blink_callback(void *closure)
{
    MWContext *context = (MWContext *)closure;

    if (context->blink_hidden == FALSE) {
        CL_HideLayerGroup(context->compositor, "_BLINKGROUP");
        context->blink_hidden = TRUE;
    }
    else {
        CL_UnhideLayerGroup(context->compositor, "_BLINKGROUP");
        context->blink_hidden = FALSE;
    }

    /* Set the next timeout */
    context->blink_timeout = FE_SetTimeout(lo_blink_callback,
                                           (void *)context,
                                           LO_BLINK_RATE);
}

void
lo_CreateBlinkLayer (MWContext *context, lo_DocState *state,
                     LO_TextStruct *text)
{
    CL_Layer *blink_layer, *parent;
    lo_BlinkStruct *closure;
    XP_Rect bbox;

    closure = XP_NEW_ZAP(lo_BlinkStruct);
    closure->context = context;
    closure->state = state;
    closure->text = text;
        
    bbox.left = text->x + text->x_offset;
    bbox.top = text->y + text->y_offset;
    bbox.right = bbox.left + text->width;
    bbox.bottom = bbox.top + text->height;
        
    blink_layer = CL_NewLayer(&bbox);
    blink_layer->direct = TRUE;
    blink_layer->painter_func = lo_blink_painter_func;
    blink_layer->destroy_func = lo_blink_destroy_func;
    blink_layer->author_data = (void *)closure;

    /* 
     * BUGBUG LAYERS: Right now we just use the _BASE layer. This 
     * code should find the layer associated with the text element.
     */
    parent = CL_FindLayer(context->compositor, "_BASE");
    CL_InsertChild(parent, blink_layer, NULL, CL_ABOVE);
    CL_AddLayerToGroup(context->compositor, blink_layer, "_BLINKGROUP");

    /* If noone has setup the callback yet, start it up */
    if (context->blink_timeout == NULL) {
        context->blink_hidden = FALSE;
        context->blink_timeout = FE_SetTimeout(lo_blink_callback,
                                               (void *)context,
                                               LO_BLINK_RATE);
    }
}

void
lo_DestroyBlinkers(MWContext *context)
{
    if (context->blink_timeout) {
        FE_ClearTimeout(context->blink_timeout);
        context->blink_timeout = NULL;
    }

#if 0
    CL_ForEachLayerInGroup(context->compositor, "_BLINKGROUP",
                           lo_blink_destroy_func, NULL);
#endif
}

/**********************
 *
 * HTML and background layer code
 *
 **********************/

/* Called for each rectangle in the update region */
static void
lo_html_rect_func(void *drawable,
				  XP_Rect *rect)
{
  MWContext *context = (MWContext *)drawable;

  LO_RefreshArea(context,
				 rect->left, rect->top,
				 (rect->right - rect->left),
				 (rect->bottom - rect->top));
}

/* painter_func for HTML document layers */
FE_Region 
lo_html_painter_func(void *drawable, 
					 CL_Layer *layer, 
					 FE_Region update_region,
					 XP_Bool allow_transparency)
{
  /* If this is the front-to-back pass, we can't draw here */
  if (!allow_transparency)
	return NULL;

  FE_ForEachRectInRegion(update_region, 
						 (FE_RectInRegionFunc)lo_html_rect_func,
						 (void *)drawable);

  return update_region;
}


/* Called for each rectangle in the update region */
static void
lo_bgcolor_rect_func(void *drawable,
					 XP_Rect *rect)
{
  MWContext *context = (MWContext *)drawable;

  FE_EraseBackground(context, FE_VIEW, rect->left, rect->top,
					 (rect->right - rect->left), (rect->bottom - rect->top));
}

/* painter_func for a HTML background layer */
FE_Region
lo_html_bgcolor_painter_func(void *drawable, 
							 CL_Layer *layer, 
							 FE_Region update_region,
							 XP_Bool allow_transparency)
{
  FE_ForEachRectInRegion(update_region, 
						 (FE_RectInRegionFunc)lo_bgcolor_rect_func,
						 (void *)drawable);

  return update_region;
}

/* 
 * Creates a HTML layer (either the _BASE layer or one created
 * using the <LAYER> tag.
 */
CL_Layer *
lo_CreateHTMLLayer(MWContext *context, char *name, int32 x, int32 y,
                   uint32 width, uint32 height, Bool scrolling,
                   Bool hidden, Bool direct)
{
    CL_Layer *layer;
    XP_Rect bbox;
    
    bbox.left = x;
    bbox.top = y;
    bbox.right = x + width;
    bbox.bottom = y + width;
    
    layer = CL_NewLayer(&bbox);
    layer->name = name;
    layer->direct = direct;
    layer->scrolling = scrolling;
    layer->hidden = hidden;
    /* Use the default HTML layer func */
    layer->painter_func = lo_html_painter_func;
    layer->author_data = (void *)context;
    
    return layer;
}

/* Creates a HTML background layer */
CL_Layer *
lo_CreateHTMLBackgroundLayer(MWContext *context)
{
    CL_Layer *layer;
    XP_Rect bbox;
    
    bbox.left = bbox.right = bbox.top = bbox.bottom = 0;
    layer = CL_NewLayer(&bbox);
    layer->name = "_BGCOLOR";
    layer->direct = TRUE;
    layer->painter_func = lo_html_bgcolor_painter_func;
    layer->author_data = (void *)context;

    return layer;
}

/* Creates the _BASE and _BGCOLOR layers and adds them to the layer tree */
void
lo_CreateDefaultLayers(MWContext *context)
{
    CL_Layer *base_layer, *bg_layer, *doc_layer;
    
    doc_layer = CL_FindLayer(context->compositor, "_DOCUMENT");
    
    bg_layer = lo_CreateHTMLBackgroundLayer(context);
    CL_InsertChild(doc_layer, bg_layer, NULL, CL_ABOVE);

    base_layer = lo_CreateHTMLLayer(context, "_BASE", 0, 0, 0, 0,
                                    FALSE, FALSE, TRUE);
    CL_InsertChild(doc_layer, base_layer, NULL, CL_ABOVE);
}

static void
lo_destroy_layer_recursive(CL_Layer *layer, void *arg)
{
    CL_Layer *parent = (CL_Layer *)arg;
    
    CL_RemoveChild(parent, layer);
    CL_DestroyLayerTree(layer);
}

/* Destroy all HTML-created layers */
void
lo_DestroyLayers(MWContext *context)
{
    CL_Layer *doc_layer;
    
    doc_layer = CL_FindLayer(context->compositor, "_DOCUMENT");

    /* BUGBUG LAYERS For now, destroy all children of the _DOCUMENT layer */
    CL_ForEachChildOfLayer(doc_layer, lo_destroy_layer_recursive, 
                           (void *)doc_layer);
}