*/ static void Detach_Gob(REBGOB *gob) /* ** Remove a gob value from its parent. ** Done normally in advance of inserting gobs into new parent. ** ***********************************************************************/ { REBGOB *par; REBINT i; par = GOB_PARENT(gob); if (par && GOB_PANE(par) && (i = Find_Gob(par, gob)) != NOT_FOUND) { Remove_Series(GOB_PANE(par), i, 1); } GOB_PARENT(gob) = 0; }
*/ static void Remove_Gobs(REBGOB *gob, REBCNT index, REBCNT len) /* ** Remove one or more gobs from a pane at the given index. ** ***********************************************************************/ { REBGOB **ptr; REBCNT n; ptr = GOB_SKIP(gob, index); for (n = 0; n < len; n++, ptr++) { GOB_PARENT(*ptr) = 0; } Remove_Series(GOB_PANE(gob), index, len); }
*/ static REBFLG Get_GOB_Var(REBGOB *gob, REBVAL *word, REBVAL *val) /* ***********************************************************************/ { switch (VAL_WORD_CANON(word)) { case SYM_OFFSET: SET_PAIR(val, GOB_X(gob), GOB_Y(gob)); break; case SYM_SIZE: SET_PAIR(val, GOB_W(gob), GOB_H(gob)); break; case SYM_IMAGE: if (GOB_TYPE(gob) == GOBT_IMAGE) { // image } else goto is_none; break; case SYM_DRAW: if (GOB_TYPE(gob) == GOBT_DRAW) { Set_Block(val, GOB_CONTENT(gob)); // Note: compiler optimizes SET_BLOCKs below } else goto is_none; break; case SYM_TEXT: if (GOB_TYPE(gob) == GOBT_TEXT) { Set_Block(val, GOB_CONTENT(gob)); } else if (GOB_TYPE(gob) == GOBT_STRING) { Set_String(val, GOB_CONTENT(gob)); } else goto is_none; break; case SYM_EFFECT: if (GOB_TYPE(gob) == GOBT_EFFECT) { Set_Block(val, GOB_CONTENT(gob)); } else goto is_none; break; case SYM_COLOR: if (GOB_TYPE(gob) == GOBT_COLOR) { Set_Tuple_Pixel((REBYTE*)&GOB_CONTENT(gob), val); } else goto is_none; break; case SYM_ALPHA: SET_INTEGER(val, GOB_ALPHA(gob)); break; case SYM_PANE: if (GOB_PANE(gob)) Set_Block(val, Pane_To_Block(gob, 0, -1)); else Set_Block(val, Make_Block(0)); break; case SYM_PARENT: if (GOB_PARENT(gob)) { SET_GOB(val, GOB_PARENT(gob)); } else is_none: SET_NONE(val); break; case SYM_DATA: if (GOB_DTYPE(gob) == GOBD_OBJECT) { SET_OBJECT(val, GOB_DATA(gob)); } else if (GOB_DTYPE(gob) == GOBD_BLOCK) { Set_Block(val, GOB_DATA(gob)); } else if (GOB_DTYPE(gob) == GOBD_STRING) { Set_String(val, GOB_DATA(gob)); } else if (GOB_DTYPE(gob) == GOBD_BINARY) { SET_BINARY(val, GOB_DATA(gob)); } else if (GOB_DTYPE(gob) == GOBD_INTEGER) { SET_INTEGER(val, (REBIPT)GOB_DATA(gob)); } else goto is_none; break; case SYM_FLAGS: Set_Block(val, Flags_To_Block(gob)); break; default: return FALSE; } return TRUE; }
*/ static void Insert_Gobs(REBGOB *gob, REBVAL *arg, REBCNT index, REBCNT len, REBFLG change) /* ** Insert one or more gobs into a pane at the given index. ** If index >= tail, an append occurs. Each gob has its parent ** gob field set. (Call Detach_Gobs() before inserting.) ** ***********************************************************************/ { REBGOB **ptr; REBCNT n, count; REBVAL *val, *sarg; REBINT i; // Verify they are gobs: sarg = arg; for (n = count = 0; n < len; n++, val++) { val = arg++; if (IS_WORD(val)) val = Get_Var(val); if (IS_GOB(val)) { count++; if (GOB_PARENT(VAL_GOB(val))) { // Check if inserting into same parent: i = -1; if (GOB_PARENT(VAL_GOB(val)) == gob) { i = Find_Gob(gob, VAL_GOB(val)); if (i > 0 && i == (REBINT)index-1) { // a no-op SET_GOB_STATE(VAL_GOB(val), GOBS_NEW); return; } } Detach_Gob(VAL_GOB(val)); if ((REBINT)index > i) index--; } } } arg = sarg; // Create or expand the pane series: if (!GOB_PANE(gob)) { GOB_PANE(gob) = Make_Series(count, sizeof(REBGOB*), 0); LABEL_SERIES(GOB_PANE(gob), "gob pane"); GOB_TAIL(gob) = count; index = 0; } else { if (change) { if (index + count > GOB_TAIL(gob)) { EXPAND_SERIES_TAIL(GOB_PANE(gob), index + count - GOB_TAIL(gob)); } } else { Expand_Series(GOB_PANE(gob), index, count); if (index >= GOB_TAIL(gob)) index = GOB_TAIL(gob)-1; } } ptr = GOB_SKIP(gob, index); for (n = 0; n < len; n++) { val = arg++; if (IS_WORD(val)) val = Get_Var(val); if (IS_GOB(val)) { if GOB_PARENT(VAL_GOB(val)) Trap_Temp(); *ptr++ = VAL_GOB(val); GOB_PARENT(VAL_GOB(val)) = gob; SET_GOB_STATE(VAL_GOB(val), GOBS_NEW); } } }
*/ void rebcmp_compose(REBCMP_CTX* ctx, REBGOB* winGob, REBGOB* gob, REBOOL only) /* ** Compose content of the specified gob. Main compositing function. ** ** If the ONLY arg is TRUE then the specified gob area will be ** rendered to the buffer at 0x0 offset.(used by TO-IMAGE) ** ***********************************************************************/ { REBINT max_depth = 1000; // avoid infinite loops REBD32 abs_x = 0; REBD32 abs_y = 0; REBD32 abs_ox; REBD32 abs_oy; REBGOB* parent_gob = gob; REBINT x = GOB_LOG_X_INT(gob); REBINT y = GOB_LOG_Y_INT(gob); REBINT w = GOB_LOG_W_INT(gob); REBINT h = GOB_LOG_H_INT(gob); /* RL_Print("Composing gob: %x (%dx%d, %dx%d) in wingob %x\n", gob, (int)GOB_LOG_X(gob), (int)GOB_LOG_Y(gob), GOB_W_INT(gob), GOB_H_INT(gob), winGob); */ //reset clip region to window area if (ctx->Win_Region != NULL){ XDestroyRegion(ctx->Win_Region); } ctx->Win_Region = XCreateRegion(); //calculate absolute offset of the gob while (GOB_PARENT(parent_gob) && (max_depth-- > 0) && !GET_GOB_FLAG(parent_gob, GOBF_WINDOW)) { abs_x += GOB_LOG_X(parent_gob); abs_y += GOB_LOG_Y(parent_gob); parent_gob = GOB_PARENT(parent_gob); } assert(max_depth > 0); //the offset is shifted to render given gob at offset 0x0 (used by TO-IMAGE) if (only){ ctx->absOffset.x = -abs_x; ctx->absOffset.y = -abs_y; abs_x = 0; abs_y = 0; } else { ctx->absOffset.x = 0; ctx->absOffset.y = 0; } ctx->New_Clip.x = abs_x; ctx->New_Clip.y = abs_y; ctx->New_Clip.width = GOB_LOG_W_INT(gob); ctx->New_Clip.height = GOB_LOG_H_INT(gob); //handle newly added gob case if (!GET_GOB_STATE(gob, GOBS_NEW)){ //calculate absolute old offset of the gob abs_ox = abs_x + (GOB_XO(gob) - GOB_LOG_X(gob)); abs_oy = abs_y + (GOB_YO(gob) - GOB_LOG_Y(gob)); //set region with old gob location and dimensions ctx->Old_Clip.x = abs_ox; ctx->Old_Clip.y = abs_oy; ctx->Old_Clip.width = GOB_WO_INT(gob); ctx->Old_Clip.height = GOB_HO_INT(gob); XUnionRectWithRegion(&ctx->Old_Clip, ctx->Win_Region, ctx->Win_Region); //RL_Print("OLD: %dx%d %dx%d\n",(REBINT)abs_ox, (REBINT)abs_oy, (REBINT)abs_ox + GOB_WO_INT(gob), (REBINT)abs_oy + GOB_HO_INT(gob)); } //RL_Print("NEW: %dx%d %dx%d\n",(REBINT)abs_x, (REBINT)abs_y, (REBINT)abs_x + GOB_LOG_W_INT(gob), (REBINT)abs_y + GOB_LOG_H_INT(gob)); //Create union of "new" and "old" gob location XUnionRectWithRegion(&ctx->New_Clip, ctx->Win_Region, ctx->Win_Region); /* XClipBox(ctx->Win_Region, &win_rect); RL_Print("Old+New, %dx%d,%dx%d\n", win_rect.x, win_rect.y, win_rect.x + win_rect.width, win_rect.y + win_rect.height); */ if (!XEmptyRegion(ctx->Win_Region)) { swap_buffer(ctx); ctx->Window_Buffer = rebcmp_get_buffer(ctx); if (gob == winGob) { memset(ctx->Window_Buffer, 0, ctx->pixbuf_len); } //redraw gobs process_gobs(ctx, winGob); rebcmp_release_buffer(ctx); ctx->Window_Buffer = NULL; } //update old GOB area GOB_XO(gob) = GOB_LOG_X(gob); GOB_YO(gob) = GOB_LOG_Y(gob); GOB_WO(gob) = GOB_LOG_W(gob); GOB_HO(gob) = GOB_LOG_H(gob); }
*/ static REBFLG Get_GOB_Var(REBGOB *gob, REBVAL *word, REBVAL *val) /* ***********************************************************************/ { REBSER *data; switch (VAL_WORD_CANON(word)) { case SYM_OFFSET: SET_PAIR(val, GOB_X(gob), GOB_Y(gob)); break; case SYM_SIZE: SET_PAIR(val, GOB_W(gob), GOB_H(gob)); break; case SYM_IMAGE: if (GOB_TYPE(gob) == GOBT_IMAGE) { // image } else goto is_none; break; #ifdef HAS_WIDGET_GOB case SYM_WIDGET: data = VAL_SERIES(GOB_WIDGET_SPEC(gob)); Init_Word(val, VAL_WORD_CANON(BLK_HEAD(data))); VAL_SET(val, REB_LIT_WORD); break; #endif case SYM_DRAW: if (GOB_TYPE(gob) == GOBT_DRAW) { Set_Block(val, GOB_CONTENT(gob)); // Note: compiler optimizes SET_BLOCKs below } else goto is_none; break; case SYM_TEXT: if (GOB_TYPE(gob) == GOBT_TEXT) { Set_Block(val, GOB_CONTENT(gob)); } else if (GOB_TYPE(gob) == GOBT_STRING) { Set_String(val, GOB_CONTENT(gob)); } else goto is_none; break; case SYM_EFFECT: if (GOB_TYPE(gob) == GOBT_EFFECT) { Set_Block(val, GOB_CONTENT(gob)); } else goto is_none; break; case SYM_COLOR: if (GOB_TYPE(gob) == GOBT_COLOR) { Set_Tuple_Pixel((REBYTE*)&GOB_CONTENT(gob), val); } else goto is_none; break; case SYM_ALPHA: SET_INTEGER(val, GOB_ALPHA(gob)); break; case SYM_PANE: if (GOB_PANE(gob)) Set_Block(val, Pane_To_Block(gob, 0, -1)); else Set_Block(val, Make_Block(0)); break; case SYM_PARENT: if (GOB_PARENT(gob)) { SET_GOB(val, GOB_PARENT(gob)); } else is_none: SET_NONE(val); break; case SYM_DATA: #ifdef HAS_WIDGET_GOB if (GOB_TYPE(gob) == GOBT_WIDGET) { return OS_GET_WIDGET_DATA(gob, val); } #endif data = GOB_DATA(gob); if (GOB_DTYPE(gob) == GOBD_OBJECT) { SET_OBJECT(val, data); } else if (GOB_DTYPE(gob) == GOBD_BLOCK) { Set_Block(val, data); } else if (GOB_DTYPE(gob) == GOBD_STRING) { Set_String(val, data); } else if (GOB_DTYPE(gob) == GOBD_BINARY) { SET_BINARY(val, data); } else if (GOB_DTYPE(gob) == GOBD_INTEGER) { SET_INTEGER(val, (REBIPT)data); } else goto is_none; break; case SYM_FLAGS: Set_Block(val, Flags_To_Block(gob)); break; default: return FALSE; } return TRUE; }
*/ void rebcmp_compose(REBCMP_CTX* ctx, REBGOB* winGob, REBGOB* gob, REBOOL only) /* ** Compose content of the specified gob. Main compositing function. ** ** If the ONLY arg is TRUE then the specified gob area will be ** rendered to the buffer at 0x0 offset.(used by TO-IMAGE) ** ***********************************************************************/ { REBINT max_depth = 1000; // avoid infinite loops REBD32 abs_x = 0; REBD32 abs_y = 0; REBD32 abs_ox; REBD32 abs_oy; REBGOB* parent_gob = gob; //reset clip region to window area //------------------------------ //Put backend specific code here //------------------------------ //calculate absolute offset of the gob while (GOB_PARENT(parent_gob) && (max_depth-- > 0) && !GET_GOB_FLAG(parent_gob, GOBF_WINDOW)) { abs_x += GOB_LOG_X(parent_gob); abs_y += GOB_LOG_Y(parent_gob); parent_gob = GOB_PARENT(parent_gob); } //the offset is shifted to render given gob at offset 0x0 (used by TO-IMAGE) if (only){ ctx->absOffset.x = -abs_x; ctx->absOffset.y = -abs_y; abs_x = 0; abs_y = 0; } else { ctx->absOffset.x = 0; ctx->absOffset.y = 0; } //handle newly added gob case if (!GET_GOB_STATE(gob, GOBS_NEW)){ //calculate absolute old offset of the gob abs_ox = abs_x + (GOB_XO(gob) - GOB_LOG_X(gob)); abs_oy = abs_y + (GOB_YO(gob) - GOB_LOG_Y(gob)); //set region with old gob location and dimensions //------------------------------ //Put backend specific code here //------------------------------ } //Create union of "new" and "old" gob location REBOOL valid_intersection; //------------------------------ //Put backend specific code here //------------------------------ //intersect resulting region with window clip region //------------------------------ //Put backend specific code here //------------------------------ if (valid_intersection) { ctx->Window_Buffer = rebcmp_get_buffer(ctx); //redraw gobs process_gobs(ctx, winGob); rebcmp_release_buffer(ctx); ctx->Window_Buffer = NULL; } //update old GOB area GOB_XO(gob) = GOB_LOG_X(gob); GOB_YO(gob) = GOB_LOG_Y(gob); GOB_WO(gob) = GOB_LOG_W(gob); GOB_HO(gob) = GOB_LOG_H(gob); }