Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2006 Richard Wilson <info@tinct.net>
  3.  *
  4.  * This file is part of NetSurf, http://www.netsurf-browser.org/
  5.  *
  6.  * NetSurf is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; version 2 of the License.
  9.  *
  10.  * NetSurf is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  */
  18.  
  19. /** \file
  20.  * Frame and frameset creation and manipulation (implementation).
  21.  */
  22.  
  23. #include <assert.h>
  24. #include <limits.h>
  25. #include <stdbool.h>
  26. #include <stdint.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <time.h>
  30. #include <math.h>
  31. #include "utils/config.h"
  32. #include "content/hlcache.h"
  33. #include "desktop/browser_private.h"
  34. #include "desktop/frames.h"
  35. #include "desktop/history_core.h"
  36. #include "desktop/gui.h"
  37. #include "desktop/scrollbar.h"
  38. #include "desktop/selection.h"
  39. #include "utils/log.h"
  40. #include "utils/messages.h"
  41. #include "utils/utils.h"
  42. #include "render/html.h"
  43. #include "render/box.h"
  44.  
  45. /** maximum frame resize margin */
  46. #define FRAME_RESIZE 6
  47.  
  48. static bool browser_window_resolve_frame_dimension(struct browser_window *bw,
  49.                 struct browser_window *sibling, int x, int y, bool width,
  50.                 bool height);
  51.  
  52.  
  53. /**
  54.  * Callback for (i)frame scrollbars.
  55.  */
  56. void browser_window_scroll_callback(void *client_data,
  57.                 struct scrollbar_msg_data *scrollbar_data)
  58. {
  59.         struct browser_window *bw = client_data;
  60.  
  61.         switch(scrollbar_data->msg) {
  62.         case SCROLLBAR_MSG_MOVED:
  63.                 if (bw->browser_window_type == BROWSER_WINDOW_IFRAME) {
  64.                         html_redraw_a_box(bw->parent->current_content, bw->box);
  65.                 } else {
  66.                         struct rect rect;
  67.  
  68.                         rect.x0 = scrollbar_get_offset(bw->scroll_x);
  69.                         rect.y0 = scrollbar_get_offset(bw->scroll_y);
  70.                         rect.x1 = rect.x0 + bw->width;
  71.                         rect.y1 = rect.y0 + bw->height;
  72.  
  73.                         browser_window_update_box(bw, &rect);
  74.                 }
  75.                 break;
  76.         case SCROLLBAR_MSG_SCROLL_START:
  77.         {
  78.                 struct rect rect = {
  79.                         .x0 = scrollbar_data->x0,
  80.                         .y0 = scrollbar_data->y0,
  81.                         .x1 = scrollbar_data->x1,
  82.                         .y1 = scrollbar_data->y1
  83.                 };
  84.  
  85.                 if (scrollbar_is_horizontal(scrollbar_data->scrollbar))
  86.                         browser_window_set_drag_type(bw, DRAGGING_SCR_X, &rect);
  87.                 else
  88.                         browser_window_set_drag_type(bw, DRAGGING_SCR_Y, &rect);
  89.         }
  90.                 break;
  91.         case SCROLLBAR_MSG_SCROLL_FINISHED:
  92.                 browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);
  93.  
  94.                 browser_window_set_pointer(bw, BROWSER_POINTER_DEFAULT);
  95.                 break;
  96.         }
  97. }
  98.  
  99. /* exported interface, documented in browser.h */
  100. void browser_window_handle_scrollbars(struct browser_window *bw)
  101. {
  102.         hlcache_handle *h = bw->current_content;
  103.         bool scroll_x;
  104.         bool scroll_y;
  105.         int c_width = 0;
  106.         int c_height = 0;
  107.  
  108.         assert(!bw->window); /* Core-handled windows only */
  109.  
  110.         if (h != NULL) {
  111.                 c_width  = content_get_width(h);
  112.                 c_height = content_get_height(h);
  113.         }
  114.  
  115.         if (bw->scrolling == SCROLLING_YES) {
  116.                 scroll_x = true;
  117.                 scroll_y = true;
  118.         } else if (bw->scrolling == SCROLLING_AUTO &&
  119.                         bw->current_content) {
  120.                 int bw_width = bw->width;
  121.                 int bw_height = bw->height;
  122.  
  123.                 /* subtract existing scrollbar width */
  124.                 bw_width -= bw->scroll_y ? SCROLLBAR_WIDTH : 0;
  125.                 bw_height -= bw->scroll_x ? SCROLLBAR_WIDTH : 0;
  126.  
  127.                 scroll_y = (c_height > bw_height) ? true : false;
  128.                 scroll_x = (c_width > bw_width) ? true : false;
  129.         } else {
  130.                 /* No scrollbars */
  131.                 scroll_x = false;
  132.                 scroll_y = false;
  133.         }
  134.  
  135.         if (!scroll_x && bw->scroll_x != NULL) {
  136.                 scrollbar_destroy(bw->scroll_x);
  137.                 bw->scroll_x = NULL;
  138.         }
  139.  
  140.         if (!scroll_y && bw->scroll_y != NULL) {
  141.                 scrollbar_destroy(bw->scroll_y);
  142.                 bw->scroll_y = NULL;
  143.         }
  144.  
  145.         if (scroll_y) {
  146.                 int length = bw->height;
  147.                 int visible = bw->height - (scroll_x ? SCROLLBAR_WIDTH : 0);
  148.  
  149.                 if (bw->scroll_y == NULL) {
  150.                         /* create vertical scrollbar */
  151.                         if (!scrollbar_create(false, length, c_height, visible,
  152.                                         bw, browser_window_scroll_callback,
  153.                                         &(bw->scroll_y)))
  154.                                 return;
  155.                 } else {
  156.                         /* update vertical scrollbar */
  157.                         scrollbar_set_extents(bw->scroll_y, length,
  158.                                         visible, c_height);
  159.                 }
  160.         }
  161.  
  162.         if (scroll_x) {
  163.                 int length = bw->width - (scroll_y ? SCROLLBAR_WIDTH : 0);
  164.                 int visible = length;
  165.  
  166.                 if (bw->scroll_x == NULL) {
  167.                         /* create horizontal scrollbar */
  168.                         if (!scrollbar_create(true, length, c_width, visible,
  169.                                         bw, browser_window_scroll_callback,
  170.                                         &(bw->scroll_x)))
  171.                                 return;
  172.                 } else {
  173.                         /* update horizontal scrollbar */
  174.                         scrollbar_set_extents(bw->scroll_x, length,
  175.                                         visible, c_width);
  176.                 }
  177.         }
  178.  
  179.         if (scroll_x && scroll_y)
  180.                 scrollbar_make_pair(bw->scroll_x, bw->scroll_y);
  181. }
  182.  
  183.  
  184. /**
  185.  * Create and open a iframes for a browser window.
  186.  *
  187.  * \param  bw       The browser window to create iframes for
  188.  * \param  iframe   The iframes to create
  189.  */
  190.  
  191. void browser_window_create_iframes(struct browser_window *bw,
  192.                 struct content_html_iframe *iframe)
  193. {
  194.         struct browser_window *window;
  195.         struct content_html_iframe *cur;
  196.         struct rect rect;
  197.         int iframes = 0;
  198.         int index;
  199.  
  200.         for (cur = iframe; cur; cur = cur->next)
  201.                 iframes++;
  202.         bw->iframes = calloc(iframes, sizeof(*bw));
  203.         if (!bw->iframes)
  204.                 return;
  205.         bw->iframe_count = iframes;
  206.  
  207.         index = 0;
  208.         for (cur = iframe; cur; cur = cur->next) {
  209.                 window = &(bw->iframes[index++]);
  210.  
  211.                 /* Initialise common parts */
  212.                 browser_window_initialise_common(window, NULL);
  213.  
  214.                 /* window characteristics */
  215.                 window->browser_window_type = BROWSER_WINDOW_IFRAME;
  216.                 window->scrolling = cur->scrolling;
  217.                 window->border = cur->border;
  218.                 window->border_colour = cur->border_colour;
  219.                 window->no_resize = true;
  220.                 window->margin_width = cur->margin_width;
  221.                 window->margin_height = cur->margin_height;
  222.                 window->cur_sel = bw->cur_sel;
  223.                 window->scale = bw->scale;
  224.                 if (cur->name) {
  225.                         window->name = strdup(cur->name);
  226.                         if (!window->name)
  227.                                 warn_user("NoMemory", 0);
  228.                 }
  229.  
  230.                 /* linking */
  231.                 window->box = cur->box;
  232.                 window->parent = bw;
  233.                 window->box->iframe = window;
  234.  
  235.                 /* iframe dimensions */
  236.                 box_bounds(window->box, &rect);
  237.  
  238.                 browser_window_set_position(window, rect.x0, rect.y0);
  239.                 browser_window_set_dimensions(window, rect.x1 - rect.x0,
  240.                                 rect.y1 - rect.y0);
  241.         }
  242.  
  243.         /* calculate dimensions */
  244.         browser_window_update_extent(bw);
  245.         browser_window_recalculate_iframes(bw);
  246.  
  247.         index = 0;
  248.         for (cur = iframe; cur; cur = cur->next) {
  249.                 window = &(bw->iframes[index++]);
  250.                 if (cur->url) {
  251.                         /* fetch iframe's content */
  252.                         browser_window_go_unverifiable(window,
  253.                                         nsurl_access(cur->url),
  254.                                         nsurl_access(hlcache_handle_get_url(
  255.                                                         bw->current_content)),
  256.                                         false, bw->current_content);
  257.                 }
  258.         }
  259. }
  260.  
  261.  
  262. /**
  263.  * Recalculate iframe positions following a resize.
  264.  *
  265.  * \param  bw       The browser window to reposition iframes for
  266.  */
  267.  
  268. void browser_window_recalculate_iframes(struct browser_window *bw)
  269. {
  270.         struct browser_window *window;
  271.         int index;
  272.  
  273.         for (index = 0; index < bw->iframe_count; index++) {
  274.                 window = &(bw->iframes[index]);
  275.  
  276.                 if (window != NULL) {
  277.                         browser_window_handle_scrollbars(window);
  278.                 }
  279.         }
  280. }
  281.  
  282.  
  283. /**
  284.  * Create and open a frameset for a browser window.
  285.  *
  286.  * \param  bw       The browser window to create the frameset for
  287.  * \param  iframe   The frameset to create
  288.  */
  289.  
  290. void browser_window_create_frameset(struct browser_window *bw,
  291.                 struct content_html_frames *frameset)
  292. {
  293.         int row, col, index;
  294.         struct content_html_frames *frame;
  295.         struct browser_window *window;
  296.         hlcache_handle *parent;
  297.  
  298.         assert(bw && frameset);
  299.  
  300.         /* 1. Create children */
  301.         assert(bw->children == NULL);
  302.         assert(frameset->cols + frameset->rows != 0);
  303.  
  304.         bw->children = calloc((frameset->cols * frameset->rows), sizeof(*bw));
  305.         if (!bw->children)
  306.                 return;
  307.         bw->cols = frameset->cols;
  308.         bw->rows = frameset->rows;
  309.         for (row = 0; row < bw->rows; row++) {
  310.                 for (col = 0; col < bw->cols; col++) {
  311.                         index = (row * bw->cols) + col;
  312.                         frame = &frameset->children[index];
  313.                         window = &bw->children[index];
  314.  
  315.                         /* Initialise common parts */
  316.                         browser_window_initialise_common(window, NULL);
  317.  
  318.                         /* window characteristics */
  319.                         if (frame->children)
  320.                                 window->browser_window_type =
  321.                                                 BROWSER_WINDOW_FRAMESET;
  322.                         else
  323.                                 window->browser_window_type =
  324.                                                 BROWSER_WINDOW_FRAME;
  325.                         window->scrolling = frame->scrolling;
  326.                         window->border = frame->border;
  327.                         window->border_colour = frame->border_colour;
  328.                         window->no_resize = frame->no_resize;
  329.                         window->frame_width = frame->width;
  330.                         window->frame_height = frame->height;
  331.                         window->margin_width = frame->margin_width;
  332.                         window->margin_height = frame->margin_height;
  333.                         if (frame->name) {
  334.                                 window->name = strdup(frame->name);
  335.                                 if (!window->name)
  336.                                         warn_user("NoMemory", 0);
  337.                         }
  338.  
  339.                         window->cur_sel = bw->cur_sel;
  340.                         window->scale = bw->scale;
  341.  
  342.                         /* linking */
  343.                         window->parent = bw;
  344.  
  345.                         if (window->name)
  346.                                 LOG(("Created frame '%s'", window->name));
  347.                         else
  348.                                 LOG(("Created frame (unnamed)"));
  349.                 }
  350.         }
  351.  
  352.         /* 2. Calculate dimensions */
  353.         browser_window_update_extent(bw);
  354.         browser_window_recalculate_frameset(bw);
  355.  
  356.         /* 3. Recurse for grandchildren */
  357.         for (row = 0; row < bw->rows; row++) {
  358.                 for (col = 0; col < bw->cols; col++) {
  359.                         index = (row * bw->cols) + col;
  360.                         frame = &frameset->children[index];
  361.                         window = &bw->children[index];
  362.  
  363.                         if (frame->children)
  364.                                 browser_window_create_frameset(window, frame);
  365.                 }
  366.         }
  367.  
  368.         /* Use the URL of the first ancestor window containing html content
  369.          * as the referer */
  370.         for (window = bw; window->parent; window = window->parent) {
  371.                 if (window->current_content &&
  372.                                 content_get_type(window->current_content) ==
  373.                                 CONTENT_HTML)
  374.                         break;
  375.         }
  376.  
  377.         parent = window->current_content;
  378.  
  379.         /* 4. Launch content */
  380.         for (row = 0; row < bw->rows; row++) {
  381.                 for (col = 0; col < bw->cols; col++) {
  382.                         index = (row * bw->cols) + col;
  383.                         frame = &frameset->children[index];
  384.                         window = &bw->children[index];
  385.  
  386.                         if (frame->url) {
  387.                                 browser_window_go_unverifiable(window,
  388.                                                 nsurl_access(frame->url),
  389.                                                 nsurl_access(hlcache_handle_get_url(
  390.                                                                 parent)),
  391.                                                 true,
  392.                                                 parent);
  393.                         }
  394.                 }
  395.         }
  396. }
  397.  
  398.  
  399. /**
  400.  * Recalculate frameset positions following a resize.
  401.  *
  402.  * \param  bw       The browser window to reposition framesets for
  403.  */
  404.  
  405. void browser_window_recalculate_frameset(struct browser_window *bw)
  406. {
  407.         int widths[bw->cols][bw->rows];
  408.         int heights[bw->cols][bw->rows];
  409.         int bw_width, bw_height;
  410.         int avail_width, avail_height;
  411.         int row, row2, col, index;
  412.         struct browser_window *window;
  413.         float relative;
  414.         int size, extent, applied;
  415.         int x, y;
  416.         int new_width, new_height;
  417.  
  418.         assert(bw);
  419.  
  420.         /* window dimensions */
  421.         if (!bw->parent) {
  422.                 browser_window_get_dimensions(bw, &bw_width, &bw_height, true);
  423.                 bw->x = 0;
  424.                 bw->y = 0;
  425.                 bw->width = bw_width;
  426.                 bw->height = bw_height;
  427.         } else {
  428.                 bw_width = bw->width;
  429.                 bw_height = bw->height;
  430.         }
  431.         bw_width++;
  432.         bw_height++;
  433.  
  434.         /* widths */
  435.         for (row = 0; row < bw->rows; row++) {
  436.                 avail_width = bw_width;
  437.                 relative = 0;
  438.                 for (col = 0; col < bw->cols; col++) {
  439.                         index = (row * bw->cols) + col;
  440.                         window = &bw->children[index];
  441.  
  442.                         switch (window->frame_width.unit) {
  443.                         case FRAME_DIMENSION_PIXELS:
  444.                                 widths[col][row] = window->frame_width.value *
  445.                                                 window->scale;
  446.                                 if (window->border) {
  447.                                         if (col != 0)
  448.                                                 widths[col][row] += 1;
  449.                                         if (col != bw->cols - 1)
  450.                                                 widths[col][row] += 1;
  451.                                 }
  452.                                 break;
  453.                         case FRAME_DIMENSION_PERCENT:
  454.                                 widths[col][row] = bw_width *
  455.                                                 window->frame_width.value / 100;
  456.                                 break;
  457.                         case FRAME_DIMENSION_RELATIVE:
  458.                                 widths[col][row] = 0;
  459.                                 relative += window->frame_width.value;
  460.                                 break;
  461.                         default:
  462.                                 /* unknown frame dimension unit */
  463.                                 assert(window->frame_width.unit ==
  464.                                                 FRAME_DIMENSION_PIXELS ||
  465.                                                 window->frame_width.unit ==
  466.                                                 FRAME_DIMENSION_PERCENT ||
  467.                                                 window->frame_width.unit ==
  468.                                                 FRAME_DIMENSION_RELATIVE);
  469.                                 break;
  470.                         }
  471.                         avail_width -= widths[col][row];
  472.                 }
  473.  
  474.                 /* Redistribute to fit window */
  475.                 if ((relative > 0) && (avail_width > 0)) {
  476.                         /* Expand the relative sections to fill remainder */
  477.                         for (col = 0; col < bw->cols; col++) {
  478.                                 index = (row * bw->cols) + col;
  479.                                 window = &bw->children[index];
  480.  
  481.                                 if (window->frame_width.unit ==
  482.                                                 FRAME_DIMENSION_RELATIVE) {
  483.                                         size = avail_width * window->
  484.                                                         frame_width.value /
  485.                                                         relative;
  486.                                         avail_width -= size;
  487.                                         relative -= window->frame_width.value;
  488.                                         widths[col][row] += size;
  489.                                 }
  490.                         }
  491.                 } else if (bw_width != avail_width) {
  492.                         /* proportionally distribute error */
  493.                         extent = avail_width;
  494.                         applied = 0;
  495.                         for (col = 0; col < bw->cols; col++) {
  496.                                 if (col == bw->cols - 1) {
  497.                                         /* Last cell, use up remainder */
  498.                                         widths[col][row] += extent - applied;
  499.                                         widths[col][row] =
  500.                                                         widths[col][row] < 0 ?
  501.                                                         0 : widths[col][row];
  502.                                 } else {
  503.                                         /* Find size of cell adjustment */
  504.                                         size = (widths[col][row] * extent) /
  505.                                                         (bw_width - extent);
  506.                                         /* Modify cell */
  507.                                         widths[col][row] += size;
  508.                                         applied += size;
  509.                                 }
  510.                         }
  511.                 }
  512.         }
  513.  
  514.         /* heights */
  515.         for (col = 0; col < bw->cols; col++) {
  516.                 avail_height = bw_height;
  517.                 relative = 0;
  518.                 for (row = 0; row < bw->rows; row++) {
  519.                         index = (row * bw->cols) + col;
  520.                         window = &bw->children[index];
  521.  
  522.                         switch (window->frame_height.unit) {
  523.                         case FRAME_DIMENSION_PIXELS:
  524.                                 heights[col][row] = window->frame_height.value *
  525.                                                 window->scale;
  526.                                 if (window->border) {
  527.                                         if (row != 0)
  528.                                                 heights[col][row] += 1;
  529.                                         if (row != bw->rows - 1)
  530.                                                 heights[col][row] += 1;
  531.                                 }
  532.                                 break;
  533.                         case FRAME_DIMENSION_PERCENT:
  534.                                 heights[col][row] = bw_height *
  535.                                                 window->frame_height.value / 100;
  536.                                 break;
  537.                         case FRAME_DIMENSION_RELATIVE:
  538.                                 heights[col][row] = 0;
  539.                                 relative += window->frame_height.value;
  540.                                 break;
  541.                         default:
  542.                                 /* unknown frame dimension unit */
  543.                                 assert(window->frame_height.unit ==
  544.                                                 FRAME_DIMENSION_PIXELS ||
  545.                                                 window->frame_height.unit ==
  546.                                                 FRAME_DIMENSION_PERCENT ||
  547.                                                 window->frame_height.unit ==
  548.                                                 FRAME_DIMENSION_RELATIVE);
  549.                                 break;
  550.                         }
  551.                         avail_height -= heights[col][row];
  552.                 }
  553.  
  554.                 if (avail_height == 0)
  555.                         continue;
  556.  
  557.                 /* Redistribute to fit window */
  558.                 if ((relative > 0) && (avail_height > 0)) {
  559.                         /* Expand the relative sections to fill remainder */
  560.                         for (row = 0; row < bw->rows; row++) {
  561.                                 index = (row * bw->cols) + col;
  562.                                 window = &bw->children[index];
  563.  
  564.                                 if (window->frame_height.unit ==
  565.                                                 FRAME_DIMENSION_RELATIVE) {
  566.                                         size = avail_height * window->
  567.                                                         frame_height.value /
  568.                                                         relative;
  569.                                         avail_height -= size;
  570.                                         relative -= window->frame_height.value;
  571.                                         heights[col][row] += size;
  572.                                 }
  573.                         }
  574.                 } else if (bw_height != avail_height) {
  575.                         /* proportionally distribute error */
  576.                         extent = avail_height;
  577.                         applied = 0;
  578.                         for (row = 0; row < bw->rows; row++) {
  579.                                 if (row == bw->rows - 1) {
  580.                                         /* Last cell, use up remainder */
  581.                                         heights[col][row] += extent - applied;
  582.                                         heights[col][row] =
  583.                                                         heights[col][row] < 0 ?
  584.                                                         0 : heights[col][row];
  585.                                 } else {
  586.                                         /* Find size of cell adjustment */
  587.                                         size = (heights[col][row] * extent) /
  588.                                                         (bw_height - extent);
  589.                                         /* Modify cell */
  590.                                         heights[col][row] += size;
  591.                                         applied += size;
  592.                                 }
  593.                         }
  594.                 }
  595.         }
  596.  
  597.         /* position frames and calculate children */
  598.         for (row = 0; row < bw->rows; row++) {
  599.                 x = 0;
  600.                 for (col = 0; col < bw->cols; col++) {
  601.                         index = (row * bw->cols) + col;
  602.                         window = &bw->children[index];
  603.  
  604.                         y = 0;
  605.                         for (row2 = 0; row2 < row; row2++)
  606.                                 y+= heights[col][row2];
  607.  
  608.                         window->x = x;
  609.                         window->y = y;
  610.  
  611.                         new_width = widths[col][row] - 1;
  612.                         new_height = heights[col][row] - 1;
  613.  
  614.                         if (window->width != new_width ||
  615.                                         window->height != new_height) {
  616.                                 /* Change in frame size */
  617.                                 browser_window_reformat(window, false,
  618.                                                 new_width * bw->scale,
  619.                                                 new_height * bw->scale);
  620.                                 window->width = new_width;
  621.                                 window->height = new_height;
  622.  
  623.                                 browser_window_handle_scrollbars(window);
  624.                         }
  625.  
  626.                         x += widths[col][row];
  627.  
  628.                         if (window->children)
  629.                                 browser_window_recalculate_frameset(window);
  630.                 }
  631.         }
  632. }
  633.  
  634.  
  635. /**
  636.  * Resize a browser window that is a frame.
  637.  *
  638.  * \param  bw       The browser window to resize
  639.  */
  640.  
  641. void browser_window_resize_frame(struct browser_window *bw, int x, int y)
  642. {
  643.         struct browser_window *parent;
  644.         struct browser_window *sibling;
  645.         int col = -1, row = -1, i;
  646.         bool change = false;
  647.  
  648.         parent = bw->parent;
  649.         assert(parent);
  650.  
  651.         /* get frame location */
  652.         for (i = 0; i < (parent->cols * parent->rows); i++) {
  653.                 if (&parent->children[i] == bw) {
  654.                         col = i % parent->cols;
  655.                         row = i / parent->cols;
  656.                  }
  657.         }
  658.         assert((col >= 0) && (row >= 0));
  659.  
  660.         sibling = NULL;
  661.         if (bw->drag_resize_left)
  662.                 sibling = &parent->children[row * parent->cols + (col - 1)];
  663.         else if (bw->drag_resize_right)
  664.                 sibling = &parent->children[row * parent->cols + (col + 1)];
  665.         if (sibling)
  666.                 change |= browser_window_resolve_frame_dimension(bw, sibling,
  667.                                 x, y, true, false);
  668.  
  669.         sibling = NULL;
  670.         if (bw->drag_resize_up)
  671.                 sibling = &parent->children[(row - 1) * parent->cols + col];
  672.         else if (bw->drag_resize_down)
  673.                 sibling = &parent->children[(row + 1) * parent->cols + col];
  674.         if (sibling)
  675.                 change |= browser_window_resolve_frame_dimension(bw, sibling,
  676.                                 x, y, false, true);
  677.  
  678.         if (change)
  679.                 browser_window_recalculate_frameset(parent);
  680. }
  681.  
  682.  
  683. bool browser_window_resolve_frame_dimension(struct browser_window *bw,
  684.                 struct browser_window *sibling,
  685.                 int x, int y, bool width, bool height)
  686. {
  687.         int bw_dimension, sibling_dimension;
  688.         int bw_pixels, sibling_pixels;
  689.         struct frame_dimension *bw_d, *sibling_d;
  690.         float total_new;
  691.         int frame_size;
  692.  
  693.         assert(!(width && height));
  694.  
  695.         /* extend/shrink the box to the pointer */
  696.         if (width) {
  697.                 if (bw->drag_resize_left)
  698.                         bw_dimension = bw->x + bw->width - x;
  699.                 else
  700.                         bw_dimension = x - bw->x;
  701.                 bw_pixels = bw->width;
  702.                 sibling_pixels = sibling->width;
  703.                 bw_d = &bw->frame_width;
  704.                 sibling_d = &sibling->frame_width;
  705.                 frame_size = bw->parent->width;
  706.         } else {
  707.                 if (bw->drag_resize_up)
  708.                         bw_dimension = bw->y + bw->height - y;
  709.                 else
  710.                         bw_dimension = y - bw->y;
  711.                 bw_pixels = bw->height;
  712.                 sibling_pixels = sibling->height;
  713.                 bw_d = &bw->frame_height;
  714.                 sibling_d = &sibling->frame_height;
  715.                 frame_size = bw->parent->height;
  716.         }
  717.         sibling_dimension = bw_pixels + sibling_pixels - bw_dimension;
  718.  
  719.         /* check for no change or no frame size*/
  720.         if ((bw_dimension == bw_pixels) || (frame_size == 0))
  721.                 return false;
  722.         /* check for both being 0 */
  723.         total_new = bw_dimension + sibling_dimension;
  724.         if ((bw_dimension + sibling_dimension) == 0)
  725.                 return false;
  726.  
  727.         /* our frame dimensions are now known to be:
  728.          *
  729.          * <--              frame_size              --> [VISIBLE PIXELS]
  730.          * |<--  bw_pixels -->|<--  sibling_pixels -->| [VISIBLE PIXELS, BEFORE RESIZE]
  731.          * |<-- bw_d->value-->|<-- sibling_d->value-->| [SPECIFIED UNITS, BEFORE RESIZE]
  732.          * |<--bw_dimension-->|<--sibling_dimension-->| [VISIBLE PIXELS, AFTER RESIZE]
  733.          * |<--              total_new             -->| [VISIBLE PIXELS, AFTER RESIZE]
  734.          *
  735.          * when we resize, we must retain the original unit specification such that any
  736.          * subsequent resizing of the parent window will recalculate the page as the
  737.          * author specified.
  738.          *
  739.          * if the units of both frames are the same then we can resize the values simply
  740.          * by updating the values to be a percentage of the original widths.
  741.          */
  742.         if (bw_d->unit == sibling_d->unit) {
  743.                 float total_specified = bw_d->value + sibling_d->value;
  744.                 bw_d->value = (total_specified * bw_dimension) / total_new;
  745.                 sibling_d->value = total_specified - bw_d->value;
  746.                 return true;
  747.         }
  748.  
  749.         /* if one of the sizes is relative then we don't alter the relative width and
  750.          * just let it reflow across. the non-relative (pixel/percentage) value can
  751.          * simply be resolved to the specified width that will result in the required
  752.          * dimension.
  753.          */
  754.         if (bw_d->unit == FRAME_DIMENSION_RELATIVE) {
  755.                 if ((sibling_pixels == 0) && (bw_dimension == 0))
  756.                         return false;
  757.                 if (fabs(sibling_d->value) < 0.0001)
  758.                         bw_d->value = 1;
  759.                 if (sibling_pixels == 0)
  760.                         sibling_d->value = (sibling_d->value * bw_pixels) / bw_dimension;
  761.                 else
  762.                         sibling_d->value =
  763.                                         (sibling_d->value * sibling_dimension) / sibling_pixels;
  764.  
  765.                 /* todo: the availble resize may have changed, update the drag box */
  766.                 return true;
  767.         } else if (sibling_d->unit == FRAME_DIMENSION_RELATIVE) {
  768.                 if ((bw_pixels == 0) && (sibling_dimension == 0))
  769.                         return false;
  770.                 if (fabs(bw_d->value) < 0.0001)
  771.                         bw_d->value = 1;
  772.                 if (bw_pixels == 0)
  773.                         bw_d->value = (bw_d->value * sibling_pixels) / sibling_dimension;
  774.                 else
  775.                         bw_d->value = (bw_d->value * bw_dimension) / bw_pixels;
  776.  
  777.                 /* todo: the availble resize may have changed, update the drag box */
  778.                 return true;
  779.         }
  780.  
  781.         /* finally we have a pixel/percentage mix. unlike relative values, percentages
  782.          * can easily be backwards-calculated as they can simply be scaled like pixel
  783.          * values
  784.          */
  785.         if (bw_d->unit == FRAME_DIMENSION_PIXELS) {
  786.                 float total_specified = bw_d->value + frame_size * sibling_d->value / 100;
  787.                 bw_d->value = (total_specified * bw_dimension) / total_new;
  788.                 sibling_d->value = (total_specified - bw_d->value) * 100 / frame_size;
  789.                 return true;
  790.         } else if (sibling_d->unit == FRAME_DIMENSION_PIXELS) {
  791.                 float total_specified = bw_d->value * frame_size / 100 + sibling_d->value;
  792.                 sibling_d->value = (total_specified * sibling_dimension) / total_new;
  793.                 bw_d->value = (total_specified - sibling_d->value) * 100 / frame_size;
  794.                 return true;
  795.         }
  796.         assert(!"Invalid frame dimension unit");
  797.         return false;
  798. }
  799.  
  800.  
  801. static bool browser_window_resize_frames(struct browser_window *bw,
  802.                 browser_mouse_state mouse, int x, int y,
  803.                 browser_pointer_shape *pointer)
  804. {
  805.         struct browser_window *parent;
  806.         bool left, right, up, down;
  807.         int i, resize_margin;
  808.  
  809.         if ((x < bw->x) || (x > bw->x + bw->width) ||
  810.                         (y < bw->y) || (y > bw->y + bw->height))
  811.                 return false;
  812.  
  813.         parent = bw->parent;
  814.         if ((!bw->no_resize) && parent) {
  815.                 resize_margin = FRAME_RESIZE;
  816.                 if (resize_margin * 2 > bw->width)
  817.                         resize_margin = bw->width / 2;
  818.                 left = (x < bw->x + resize_margin);
  819.                 right = (x > bw->x + bw->width - resize_margin);
  820.                 resize_margin = FRAME_RESIZE;
  821.                 if (resize_margin * 2 > bw->height)
  822.                         resize_margin = bw->height / 2;
  823.                 up = (y < bw->y + resize_margin);
  824.                 down = (y > bw->y + bw-> height - resize_margin);
  825.  
  826.                 /* check if the edges can actually be moved */
  827.                 if (left || right || up || down) {
  828.                         int row = -1, col = -1;
  829.                         switch (bw->browser_window_type) {
  830.                                 case BROWSER_WINDOW_NORMAL:
  831.                                 case BROWSER_WINDOW_IFRAME:
  832.                                         assert(0);
  833.                                         break;
  834.                                 case BROWSER_WINDOW_FRAME:
  835.                                 case BROWSER_WINDOW_FRAMESET:
  836.                                         break;
  837.                         }
  838.                         for (i = 0; i < (parent->cols * parent->rows); i++) {
  839.                                 if (&parent->children[i] == bw) {
  840.                                         col = i % parent->cols;
  841.                                         row = i / parent->cols;
  842.                                         break;
  843.                                 }
  844.                         }
  845.                         assert((row >= 0) && (col >= 0));
  846.  
  847.                         /* check the sibling frame is within bounds */
  848.                         left &= (col > 0);
  849.                         right &= (col < parent->cols - 1);
  850.                         up &= (row > 0);
  851.                         down &= (row < parent->rows - 1);
  852.  
  853.                         /* check the sibling frames can be resized */
  854.                         if (left)
  855.                                 left &= !parent->children[row *
  856.                                                 parent->cols + (col - 1)].
  857.                                                 no_resize;
  858.                         if (right)
  859.                                 right &= !parent->children[row *
  860.                                                 parent->cols + (col + 1)].
  861.                                                 no_resize;
  862.                         if (up)
  863.                                 up &= !parent->children[(row - 1) *
  864.                                                 parent->cols + col].
  865.                                                 no_resize;
  866.                         if (down)
  867.                                 down &= !parent->children[(row + 1) *
  868.                                                 parent->cols + col].
  869.                                                 no_resize;
  870.  
  871.                         /* can't have opposite directions simultaneously */
  872.                         if (up)
  873.                                 down = false;
  874.                         if (left)
  875.                                 right = false;
  876.                 }
  877.  
  878.                 if (left || right || up || down) {
  879.                         if (left) {
  880.                                 if (down)
  881.                                         *pointer = BROWSER_POINTER_LD;
  882.                                 else if (up)
  883.                                         *pointer = BROWSER_POINTER_LU;
  884.                                 else
  885.                                         *pointer = BROWSER_POINTER_LEFT;
  886.                         } else if (right) {
  887.                                 if (down)
  888.                                         *pointer = BROWSER_POINTER_RD;
  889.                                 else if (up)
  890.                                         *pointer = BROWSER_POINTER_RU;
  891.                                 else
  892.                                         *pointer = BROWSER_POINTER_RIGHT;
  893.                         } else if (up) {
  894.                                 *pointer = BROWSER_POINTER_UP;
  895.                         } else {
  896.                                 *pointer = BROWSER_POINTER_DOWN;
  897.                         }
  898.                         if (mouse & (BROWSER_MOUSE_DRAG_1 |
  899.                                         BROWSER_MOUSE_DRAG_2)) {
  900.  
  901.                                 /* TODO: Pass appropriate rectangle to allow
  902.                                  *       front end to clamp pointer range */
  903.                                 browser_window_set_drag_type(bw,
  904.                                                 DRAGGING_FRAME, NULL);
  905.                                 bw->drag_start_x = x;
  906.                                 bw->drag_start_y = y;
  907.                                 bw->drag_resize_left = left;
  908.                                 bw->drag_resize_right = right;
  909.                                 bw->drag_resize_up = up;
  910.                                 bw->drag_resize_down = down;
  911.                         }
  912.                         return true;
  913.                 }
  914.         }
  915.  
  916.         if (bw->children) {
  917.                 for (i = 0; i < (bw->cols * bw->rows); i++)
  918.                         if (browser_window_resize_frames(&bw->children[i],
  919.                                         mouse, x, y, pointer))
  920.                                 return true;
  921.         }
  922.         if (bw->iframes) {
  923.                 for (i = 0; i < bw->iframe_count; i++)
  924.                         if (browser_window_resize_frames(&bw->iframes[i],
  925.                                         mouse, x, y, pointer))
  926.                                 return true;
  927.         }
  928.         return false;
  929. }
  930.  
  931.  
  932. bool browser_window_frame_resize_start(struct browser_window *bw,
  933.                 browser_mouse_state mouse, int x, int y,
  934.                 browser_pointer_shape *pointer)
  935. {
  936.         struct browser_window *root = browser_window_get_root(bw);
  937.         int offx, offy;
  938.  
  939.         browser_window_get_position(bw, true, &offx, &offy);
  940.  
  941.         return browser_window_resize_frames(root, mouse,
  942.                         x + offx, y + offy, pointer);
  943. }
  944.