home *** CD-ROM | disk | FTP | other *** search
- /* -*- 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.
- */
-
- #include "xp.h"
- #include "layout.h"
- #include "laylayer.h"
- #include "libi18n.h"
- #include "xlate.h"
- #include "layers.h"
-
- #define IL_CLIENT /* XXXM12N Defined by Image Library clients */
- #include "libimg.h" /* Image Library public API. */
-
- #ifdef PROFILE
- #pragma profile on
- #endif
-
- #ifdef XP_MAC
- # ifdef XP_TRACE
- # undef XP_TRACE
- # endif
- # define XP_TRACE(X)
- #else
- #ifndef XP_TRACE
- # define XP_TRACE(X) fprintf X
- #endif
- #endif /* XP_MAC */
-
-
- /*
- * BUGBUG LAYERS: This is a hack that is currently being used for selection
- * but might be useful elsewhere. Essentially, for extending the selected
- * text, we know exactly how much we want to draw (using FE_DisplaySubtext).
- * Rather than ask for a synchronous refresh of the area and relying on
- * LO_RefreshArea to do the correct drawing (actually, it can't do the
- * correct drawing since it doesn't draw sub-strings), we temporarily replace
- * the painter_func for the layer in question to one that just does the
- * required drawing. We still do a synchronous refresh, but the temporary
- * painter_func is called instead of the one that calls LO_RefreshArea.
- */
- typedef struct LO_SelectionHackStruct {
- MWContext *context;
- LO_TextStruct *text;
- int32 start_pos;
- int32 end_pos;
- Bool need_bg;
- } LO_SelectionHackStruct;
-
- static void
- lo_selection_hack_painter_func(void *drawable,
- CL_Layer *layer,
- FE_Region update_region)
- {
- LO_SelectionHackStruct *hack = (LO_SelectionHackStruct *)CL_GetLayerClientData(layer);
-
- FE_SetDrawable(hack->context, drawable);
-
- /* For layers, we don't ever need to clear the background */
- FE_DisplaySubtext(hack->context, FE_VIEW,
- hack->text, hack->start_pos, hack->end_pos,
- FALSE);
-
- FE_SetDrawable(hack->context, NULL);
- }
-
- static void
- lo_NormalizeStartAndEndOfSelection(LO_TextStruct *text, int32 *start,
- int32 *end)
- {
- int32 p1, p2;
- char *string;
- int n;
- int16 charset;
-
- if (text->ele_attrmask & LO_ELE_SELECTED)
- {
- if (text->sel_start < 0)
- {
- p1 = 0;
- }
- else
- {
- p1 = text->sel_start;
- }
-
- if (text->sel_end < 0)
- {
- p2 = text->text_len - 1;
- }
- else
- {
- p2 = text->sel_end;
- }
-
- PA_LOCK(string, char *, text->text);
-
- /*
- * find beginning of first character
- */
- charset = text->text_attr->charset;
- switch (n = INTL_NthByteOfChar(charset, string, (int)(p1+1)))
- {
- case 0:
- case 1:
- break;
- default:
- p1 -= (n - 1);
- if (p1 < 0)
- {
- p1 = 0;
- }
- break;
- }
- if (text->sel_start >= 0)
- {
- text->sel_start = p1;
- }
-
- /*
- * find end of last character
- */
- switch (n = INTL_NthByteOfChar(charset, string, (int)(p2+1)))
- {
- case 0:
- break;
- default:
- p2 -= (n - 1);
- if (p2 < 0)
- {
- p2 = 0;
- }
- /* fall through */
- case 1:
- p2 += INTL_IsLeadByte(charset, string[p2]);
- if (p2 > text->text_len - 1)
- {
- p2 = text->text_len - 1;
- }
- break;
- }
- if (text->sel_end >= 0)
- {
- text->sel_end = p2;
- }
-
- *start = p1;
- *end = p2;
-
- PA_UNLOCK(text->text);
- }
- }
-
- #ifdef DEBUG
- void
- LO_DUMP_RECT(XP_Rect *rect)
- {
- XP_TRACE(("Compositing rectangle: [%3d,%3d] %d x %d\n", rect->left, rect->top,
- rect->right - rect->left, rect->bottom - rect->top));
- }
- #endif
-
- /*
- * BUGBUG LAYERS: Since we know that lo_DisplaySubtext is only done
- * for selection, we generate a synchronous composite. This might
- * not be the right thing to do: maybe we should have an additional
- * argument to the LO_Display routines
- */
- void
- lo_DisplaySubtext(MWContext *context, LO_TextStruct *text,
- int32 start_pos, int32 end_pos, Bool need_bg,
- CL_Layer *sel_layer)
- {
- lo_NormalizeStartAndEndOfSelection(text, &start_pos, &end_pos);
- /* If we have to draw, go through the compositor */
- if (context->compositor) {
- XP_Rect rect;
- CL_Layer *layer;
- int32 x_offset, y_offset;
-
- if (!sel_layer)
- layer = CL_FindLayer(context->compositor, LO_BODY_LAYER_NAME);
- else
- layer = sel_layer;
-
- FE_GetTextFrame(context, text, start_pos, end_pos, &rect);
- lo_GetLayerXYShift(layer, &x_offset, &y_offset);
- XP_OffsetRect(&rect, -x_offset, -y_offset);
-
- CL_UpdateLayerRect(context->compositor, layer, &rect, PR_FALSE);
-
- return;
- }
- else
- /* For layers, we don't ever need to clear the background */
- FE_DisplaySubtext(context, FE_VIEW, text, start_pos, end_pos,
- FALSE);
- }
-
-
- void
- lo_DisplayText(MWContext *context,
- LO_TextStruct *text, Bool need_bg)
- {
- int32 p1, p2;
- LO_TextAttr tmp_attr;
- LO_TextAttr *hold_attr;
-
- /* Blinking text elements are placed in a separate layer */
- if (context->compositor && text->text_attr->attrmask & LO_ATTR_BLINK)
- {
- if (! (text->ele_attrmask & LO_ELE_DRAWN))
- {
- /* XXX - If the BLINK is in a layer, we need to create the
- blink layer as a child of that layer, not as a child of
- the _BODY layer. */
- CL_Layer *body_layer =
- CL_FindLayer(context->compositor, LO_BODY_LAYER_NAME);
- lo_CreateBlinkLayer(context, text, body_layer);
- text->ele_attrmask |= LO_ELE_DRAWN;
- }
-
- /* All blink text drawing is handled by the blink layer's
- painter function. Don't do any drawing here. */
- return;
- }
-
- if (text->ele_attrmask & LO_ELE_SELECTED)
- {
- lo_NormalizeStartAndEndOfSelection(text, &p1, &p2);
-
- if (p1 > 0)
- {
- /* For layers we don't ever need to clear the background */
- FE_DisplaySubtext(context, FE_VIEW, text,
- 0, (p1 - 1), FALSE);
- }
-
- lo_CopyTextAttr(text->text_attr, &tmp_attr);
- tmp_attr.fg.red = text->text_attr->bg.red;
- tmp_attr.fg.green = text->text_attr->bg.green;
- tmp_attr.fg.blue = text->text_attr->bg.blue;
- tmp_attr.bg.red = text->text_attr->fg.red;
- tmp_attr.bg.green = text->text_attr->fg.green;
- tmp_attr.bg.blue = text->text_attr->fg.blue;
-
- /* lo_CopyTextAttr doesn't copy the FE_Data. In
- * this case, however, we need to copy the FE_Data
- * because otherwise the front end will
- * synthesize a new copy. This assumes that
- * the FE_Data doesn't care about font color.
- */
- tmp_attr.FE_Data = text->text_attr->FE_Data;
-
- hold_attr = text->text_attr;
- text->text_attr = &tmp_attr;
- /* For layers we don't ever need to clear the background */
- FE_DisplaySubtext(context, FE_VIEW, text, p1, p2,
- FALSE);
- text->text_attr = hold_attr;
-
- if (p2 < (text->text_len - 1))
- {
- /* For layers we don't ever need to clear the background */
- FE_DisplaySubtext(context, FE_VIEW, text,
- (p2 + 1), (text->text_len - 1),
- FALSE);
- }
- }
- else
- {
- /* For layers we don't ever need to clear the background */
- FE_DisplayText(context, FE_VIEW, text, FALSE);
- }
- }
-
-
- void
- lo_DisplayEmbed(MWContext *context, LO_EmbedStruct *embed)
- {
- CL_Layer *layer;
-
- if (! context->compositor) {
- FE_DisplayEmbed(context, FE_VIEW, embed);
- return;
- }
-
- /* Don't ever display hidden embeds */
- if (embed->ele_attrmask & LO_ELE_HIDDEN)
- return;
-
- layer = embed->layer;
- XP_ASSERT(layer);
- if (! layer) /* Paranoia */
- return;
-
- if (!(embed->ele_attrmask & LO_ELE_DRAWN)) {
- /* Move layer to new position */
- CL_MoveLayer(layer,
- embed->x + embed->x_offset,
- embed->y + embed->y_offset);
- CL_SetLayerHidden(layer, PR_FALSE);
- embed->ele_attrmask |= LO_ELE_DRAWN;
- }
- }
-
- #ifdef JAVA
- void
- lo_DisplayJavaApp(MWContext *context, LO_JavaAppStruct *java_app)
- {
- CL_Layer *layer;
-
- if (! context->compositor) {
- FE_DisplayJavaApp(context, FE_VIEW, java_app);
- return;
- }
-
- layer = java_app->layer;
- XP_ASSERT(layer);
- if (! layer) /* Paranoia */
- return;
-
- if (!(java_app->ele_attrmask & LO_ELE_DRAWN)) {
- /* Move layer to new position */
- CL_MoveLayer(layer,
- java_app->x + java_app->x_offset,
- java_app->y + java_app->y_offset);
-
- /* Now that layer is layed out to its final position,
- we can display it */
- CL_SetLayerHidden(layer, PR_FALSE);
- java_app->ele_attrmask |= LO_ELE_DRAWN;
- }
- }
- #endif
-
- /* Make the image layer visible and draw the image border. Should only be called
- if there is a compositor. */
- static void
- lo_DisplayImage(MWContext *context, LO_ImageStruct *image)
- {
- int bw = image->border_width;
-
- XP_ASSERT(context->compositor);
-
- /* Allow the compositor to start drawing the image layer. */
- lo_ActivateImageLayer(context, image);
-
- /* The image border, if present, draws in the parent of the image layer. */
- if (bw) {
- int x = image->x + image->x_offset + bw;
- int y = image->y + image->y_offset + bw;
-
- FE_DisplayBorder(context, FE_VIEW, x - bw, y - bw,
- image->width + 2 * bw, image->height + 2 * bw, bw,
- &image->text_attr->fg, LO_SOLID);
- }
- }
-
- void
- lo_DisplayImageWithoutCompositor(MWContext *context, LO_ImageStruct *image)
- {
- int bw = image->border_width;
- int x = image->x + image->x_offset + bw;
- int y = image->y + image->y_offset + bw;
- int width = image->width;
- int height = image->height;
-
- /* This routine should only be called in the absence of a compositor. */
- XP_ASSERT(!context->compositor);
-
- /* Handle the TextFE. */
- if (context->type == MWContextText) {
- XL_DisplayTextImage(context, FE_VIEW, image);
- return;
- }
-
- if (image->is_icon) {
- IL_DisplayIcon(context->img_cx, image->icon_number, x, y);
- }
- else {
- int cnv_x = context->convertPixX;
- int cnv_y = context->convertPixY;
-
- IL_DisplaySubImage(image->image_req, x/cnv_x, y/cnv_y, 0, 0,
- width/cnv_x, height/cnv_y);
- }
-
- if (bw)
- FE_DisplayBorder(context, FE_VIEW, x - bw, y - bw, width + 2 * bw,
- height + 2 * bw, bw, &image->text_attr->fg, LO_SOLID);
- }
-
- void
- lo_DisplaySubImageWithoutCompositor(MWContext *context, LO_ImageStruct *image,
- int32 x, int32 y, uint32 width, uint32 height)
- {
- int bw = image->border_width;
- int x_pos = image->x + image->x_offset + bw;
- int y_pos = image->y + image->y_offset + bw;
- int sub_x, sub_y, sub_w, sub_h;
-
- /* This routine should only be called in the absence of a compositor. */
- XP_ASSERT(!context->compositor);
-
- /* Handle the TextFE. */
- if (context->type == MWContextText) {
- XL_DisplayTextImage(context, FE_VIEW, image);
- return;
- }
-
- if (x < x_pos) {
- sub_x = x_pos;
- sub_w = width + x - x_pos;
- }
- else {
- sub_x = x;
- sub_w = width;
- }
-
- if (y < y_pos) {
- sub_y = y_pos;
- sub_h = height + y - y_pos;
- }
- else {
- sub_y = y;
- sub_h = height;
- }
-
- if (x + width > x_pos + image->width)
- sub_w += (x_pos + image->width - x - width);
-
- if (y + height > y_pos + image->height)
- sub_h += (y_pos + image->height - y - height);
-
- if (sub_w > 0 && sub_h > 0) {
- if (image->is_icon) {
- IL_DisplayIcon(context->img_cx, image->icon_number,
- x_pos, y_pos);
- }
- else {
- int cnv_x = context->convertPixX;
- int cnv_y = context->convertPixY;
-
- IL_DisplaySubImage(image->image_req, x_pos/cnv_x, y_pos/cnv_y,
- (sub_x - x_pos)/cnv_x, (sub_y - y_pos)/cnv_y,
- sub_w/cnv_x, sub_h/cnv_y);
- }
- }
-
- if (bw)
- FE_DisplayBorder(context, FE_VIEW, x - bw, y - bw, width + 2 * bw,
- height + 2 * bw, bw, &image->text_attr->fg,
- LO_SOLID);
- }
-
- /* Should only be called in the absence of a compositor. */
- void
- lo_ClipImage(MWContext *context, LO_ImageStruct *image,
- int32 x, int32 y, uint32 width, uint32 height)
- {
- int32 sub_x, sub_y;
- uint32 sub_w, sub_h;
-
- /*
- * If the two don't overlap, do nothing.
- */
- if (((int32)(image->x + image->x_offset + image->width +
- 2*image->border_width) < x)||
- ((int32)(x + width) < (int32)(image->x + image->x_offset))||
- ((int32)(image->y + image->y_offset + image->height +
- 2*image->border_width) < y)||
- ((int32)(y + height) < (int32)(image->y + image->y_offset)))
- {
- return;
- }
-
- if ((image->x + image->x_offset) >= x)
- {
- sub_x = image->x + image->x_offset;
- }
- else
- {
- sub_x = x;
- }
-
- if ((int32)(image->x + image->x_offset + image->width + 2*image->border_width)
- <= (int32)(x + width))
- {
- sub_w = image->x + image->x_offset + image->width +
- 2*image->border_width - sub_x;
- }
- else
- {
- sub_w = x + width - sub_x;
- }
-
- if ((image->y + image->y_offset) >= y)
- {
- sub_y = image->y + image->y_offset;
- }
- else
- {
- sub_y = y;
- }
-
- if ((int32)(image->y + image->y_offset + image->height + 2*image->border_width)
- <= (int32)(y + height))
- {
- sub_h = image->y + image->y_offset + image->height +
- 2*image->border_width - sub_y;
- }
- else
- {
- sub_h = y + height - sub_y;
- }
-
- if (((int32)sub_w >= (int32)(image->width - 2))&&
- ((int32)sub_h >= (int32)(image->height - 2)))
- {
- lo_DisplayImageWithoutCompositor(context, (LO_ImageStruct *)image);
- }
- else
- {
- lo_DisplaySubImageWithoutCompositor(context, (LO_ImageStruct *)image,
- sub_x, sub_y, sub_w, sub_h);
- }
- }
-
-
- void
- lo_DisplayEdge(MWContext *context, LO_EdgeStruct *edge)
- {
- if (edge->visible != FALSE)
- {
- FE_DisplayEdge(context, FE_VIEW, edge);
- }
- }
-
-
- void
- lo_DisplayTable(MWContext *context, LO_TableStruct *table)
- {
- FE_DisplayTable(context, FE_VIEW, table);
- }
-
-
- void
- lo_DisplaySubDoc(MWContext *context, LO_SubDocStruct *subdoc)
- {
- FE_DisplaySubDoc(context, FE_VIEW, subdoc);
- }
-
-
- void
- lo_DisplayCell(MWContext *context, LO_CellStruct *cell)
- {
- /* If this cell is empty, bail */
- if (cell->cell_list == NULL && cell->cell_float_list == NULL)
- return;
-
- if (context->compositor && cell->cell_bg_layer)
- CL_SetLayerHidden(cell->cell_bg_layer, PR_FALSE);
-
- FE_DisplayCell(context, FE_VIEW, cell);
- }
-
- void
- lo_DisplayLineFeed(MWContext *context,
- LO_LinefeedStruct *lfeed, Bool need_bg)
- {
- LO_TextAttr tmp_attr;
- LO_TextAttr *hold_attr;
-
- if (lfeed->ele_attrmask & LO_ELE_SELECTED)
- {
- lo_CopyTextAttr(lfeed->text_attr, &tmp_attr);
- tmp_attr.fg.red = lfeed->text_attr->bg.red;
- tmp_attr.fg.green = lfeed->text_attr->bg.green;
- tmp_attr.fg.blue = lfeed->text_attr->bg.blue;
- tmp_attr.bg.red = lfeed->text_attr->fg.red;
- tmp_attr.bg.green = lfeed->text_attr->fg.green;
- tmp_attr.bg.blue = lfeed->text_attr->fg.blue;
- hold_attr = lfeed->text_attr;
- lfeed->text_attr = &tmp_attr;
- FE_DisplayLineFeed(context, FE_VIEW, lfeed, (XP_Bool)need_bg);
- lfeed->text_attr = hold_attr;
- }
- else
- {
- FE_DisplayLineFeed(context, FE_VIEW, lfeed, (XP_Bool)need_bg);
- }
- }
-
-
- void
- lo_DisplayHR(MWContext *context, LO_HorizRuleStruct *hrule)
- {
- FE_DisplayHR(context, FE_VIEW, hrule);
- }
-
-
- void
- lo_DisplayBullet(MWContext *context, LO_BulletStruct *bullet)
- {
- FE_DisplayBullet(context, FE_VIEW, bullet);
- }
-
- void
- lo_DisplayFormElement(MWContext *context, LO_FormElementStruct *form_element)
- {
- CL_Layer *layer;
-
- if (! context->compositor) {
- FE_DisplayFormElement(context, FE_VIEW, form_element);
- return;
- }
-
- layer = form_element->layer;
- XP_ASSERT(layer);
- if (! layer) /* Paranoia */
- return;
-
- if (!(form_element->ele_attrmask & LO_ELE_DRAWN)) {
- /* Move layer to new position */
- CL_MoveLayer(layer,
- form_element->x + form_element->x_offset +
- form_element->border_horiz_space,
- form_element->y + form_element->y_offset +
- form_element->border_vert_space);
- CL_SetLayerHidden(layer, PR_FALSE);
- form_element->ele_attrmask |= LO_ELE_DRAWN;
- }
- }
-
- void
- lo_DisplayElement(MWContext *context, LO_Element *tptr,
- int32 base_x, int32 base_y,
- int32 x, int32 y,
- uint32 width, uint32 height)
- {
- LO_Any *any = &tptr->lo_any;
- XP_Rect bbox;
-
- lo_GetElementBbox(tptr, &bbox);
- XP_OffsetRect(&bbox, base_x, base_y);
-
- if (bbox.top >= (int32)(y + height))
- return;
-
- if (bbox.bottom <= y )
- return;
-
- if (bbox.left >= (int32)(x + width))
- return;
-
- if (bbox.right <= x )
- return;
-
- /* Temporarily translate to new coordinate system */
- any->x += base_x;
- any->y += base_y;
-
- switch (tptr->type)
- {
- case LO_TEXT:
- if (tptr->lo_text.text != NULL)
- lo_DisplayText(context, (LO_TextStruct *)tptr, FALSE);
- break;
-
- case LO_LINEFEED:
- lo_DisplayLineFeed(context, (LO_LinefeedStruct *)tptr, FALSE);
- break;
-
- case LO_HRULE:
- lo_DisplayHR(context, (LO_HorizRuleStruct *)tptr);
- break;
-
- case LO_FORM_ELE:
- lo_DisplayFormElement(context, (LO_FormElementStruct *)tptr);
- break;
-
- case LO_BULLET:
- lo_DisplayBullet(context, (LO_BulletStruct *)tptr);
- break;
-
- case LO_IMAGE:
- if (context->compositor) {
- /* Allow the compositor to start drawing the image. */
- lo_DisplayImage(context, (LO_ImageStruct *)tptr);
- }
- else {
- /* There is no compositor, so draw the image directly, with the
- appropriate clip. */
- lo_ClipImage(context,
- (LO_ImageStruct *)tptr,
- (x + base_x),
- (y + base_y), width, height);
- }
- break;
-
- case LO_TABLE:
- lo_DisplayTable(context, (LO_TableStruct *)tptr);
- break;
-
- case LO_EMBED:
- lo_DisplayEmbed(context, (LO_EmbedStruct *)tptr);
- break;
-
- #ifdef JAVA
- case LO_JAVA:
- lo_DisplayJavaApp(context, (LO_JavaAppStruct *)tptr);
- break;
- #endif
-
- case LO_EDGE:
- lo_DisplayEdge(context, (LO_EdgeStruct *)tptr);
- break;
-
- case LO_CELL:
- /* If this cell is a container for an inflow layer (and
- therefore not a table cell), don't descend into the cell
- because the layer's painter function will handle its
- display. */
- if (((LO_CellStruct*)tptr)->cell_inflow_layer)
- break;
-
- /* cmanske: Order changed - display cell contents FIRST
- * so selection feedback near cell border is not wiped out
- * TODO: This doesn't work for images, which are display
- * asynchronously. Need to add "observer" to image display
- */
- lo_DisplayCellContents(context, (LO_CellStruct *)tptr,
- base_x, base_y, x, y, width, height);
- lo_DisplayCell(context, (LO_CellStruct *)tptr);
- break;
-
- case LO_SUBDOC:
- {
- LO_SubDocStruct *subdoc;
- int32 new_x, new_y;
- uint32 new_width, new_height;
- lo_DocState *sub_state;
-
- subdoc = (LO_SubDocStruct *)tptr;
- sub_state = (lo_DocState *)subdoc->state;
-
- if (sub_state == NULL)
- {
- break;
- }
-
- lo_DisplaySubDoc(context, subdoc);
-
- new_x = subdoc->x;
- new_y = subdoc->y;
- new_width = subdoc->x_offset + subdoc->width;
- new_height = subdoc->y_offset + subdoc->height;
-
- new_x = new_x - subdoc->x;
- new_y = new_y - subdoc->y;
- sub_state->base_x = subdoc->x +
- subdoc->x_offset + subdoc->border_width;
- sub_state->base_y = subdoc->y +
- subdoc->y_offset + subdoc->border_width;
- lo_RefreshDocumentArea(context, sub_state,
- new_x, new_y, new_width, new_height);
- }
- break;
-
- case LO_PARAGRAPH:
- case LO_CENTER:
- case LO_MULTICOLUMN:
- case LO_LIST:
- case LO_DESCTITLE:
- case LO_DESCTEXT:
- case LO_BLOCKQUOTE:
- case LO_HEADING:
- case LO_SPAN:
- /* all non-display, doc-state mutating elements. */
- break;
- case LO_TEXTBLOCK:
- break;
- case LO_FLOAT:
- case LO_LAYER:
- break;
- default:
- XP_TRACE(("lo_DisplayElement(%p) skip element type = %d\n", tptr, tptr->type));
- break;
- }
-
- /* Restore original element's coordinates */
- any->x -= base_x;
- any->y -= base_y;
- }
-
- #ifdef PROFILE
- #pragma profile off
- #endif
-
-