home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / layout / laymap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  19.1 KB  |  1,011 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "xp.h"
  20. #include "pa_parse.h"
  21. #include "layout.h"
  22. #include "laylayer.h"
  23.  
  24.  
  25. extern Bool lo_is_location_in_poly(int32 x, int32 y,
  26.                 int32 *coords, int32 coord_cnt);
  27.  
  28. /* #ifndef NO_TAB_NAVIGATION */
  29. extern Bool lo_find_location_in_poly(int32 *xx, int32 *yy,
  30.                 int32 *coords, int32 coord_cnt);
  31. /* NO_TAB_NAVIGATION  */
  32.  
  33.  
  34. /*
  35.  * This function parses a list of numbers (coordinates).
  36.  * The numbers can have any integer value, and it is a comma separated list.
  37.  * (optionally, whitespace can replace commas as separators in the list)
  38.  */
  39. int32 *
  40. lo_parse_coord_list(char *str, int32 *value_cnt, Bool must_be_odd)
  41. {
  42.     char *tptr;
  43.     char *n_str;
  44.     int32 i, cnt, acnt;
  45.     int32 *value_list;
  46.  
  47.     /*
  48.      * Nothing in an empty list
  49.      */
  50.     *value_cnt = 0;
  51.     if ((str == NULL)||(*str == '\0'))
  52.     {
  53.         return((int32 *)NULL);
  54.     }
  55.  
  56.     /*
  57.      * Skip beginning whitespace, all whitespace is empty list.
  58.      */
  59.     n_str = str;
  60.     while (XP_IS_SPACE(*n_str))
  61.     {
  62.         n_str++;
  63.     }
  64.     if (*n_str == '\0')
  65.     {
  66.         return((int32 *)NULL);
  67.     }
  68.  
  69.     /*
  70.      * Make a pass where any two numbers separated by just whitespace
  71.      * are given a comma separator.  Count entries while passing.
  72.      */
  73.     cnt = 0;
  74.     while (*n_str != '\0')
  75.     {
  76.         Bool has_comma;
  77.  
  78.         /*
  79.          * Skip to a separator
  80.          */
  81.         tptr = n_str;
  82.         while ((!XP_IS_SPACE(*tptr))&&(*tptr != ',')&&(*tptr != '\0'))
  83.         {
  84.             tptr++;
  85.         }
  86.         n_str = tptr;
  87.  
  88.         /*
  89.          * If no more entries, break out here
  90.          */
  91.         if (*n_str == '\0')
  92.         {
  93.             break;
  94.         }
  95.  
  96.         /*
  97.          * Skip to the end of the separator, noting if we have a
  98.          * comma.
  99.          */
  100.         has_comma = FALSE;
  101.         while ((XP_IS_SPACE(*tptr))||(*tptr == ','))
  102.         {
  103.             if (*tptr == ',')
  104.             {
  105.                 if (has_comma == FALSE)
  106.                 {
  107.                     has_comma = TRUE;
  108.                 }
  109.                 else
  110.                 {
  111.                     break;
  112.                 }
  113.             }
  114.             tptr++;
  115.         }
  116.         /*
  117.          * If this was trailing whitespace we skipped, we are done.
  118.          */
  119.         if ((*tptr == '\0')&&(has_comma == FALSE))
  120.         {
  121.             break;
  122.         }
  123.         /*
  124.          * Else if the separator is all whitespace, and this is not the
  125.          * end of the string, add a comma to the separator.
  126.          */
  127.         else if (has_comma == FALSE)
  128.         {
  129.             *n_str = ',';
  130.         }
  131.  
  132.         /*
  133.          * count the entry skipped.
  134.          */
  135.         cnt++;
  136.  
  137.         n_str = tptr;
  138.     }
  139.     /*
  140.      * count the last entry in the list.
  141.      */
  142.     cnt++;
  143.     
  144.     /*
  145.      * For polygons, we need a fake empty coord at the
  146.      * end of the list of x,y pairs.
  147.      */
  148.     if ((must_be_odd != FALSE)&&((cnt & 0x01) == 0))
  149.     {
  150.         acnt = cnt + 1;
  151.     }
  152.     else
  153.     {
  154.         acnt = cnt;
  155.     }
  156.  
  157.     *value_cnt = acnt;
  158.  
  159.     /*
  160.      * Allocate space for the coordinate array.
  161.      */
  162.     value_list = (int32 *)XP_ALLOC(acnt * sizeof(int32));
  163.     if (value_list == NULL)
  164.     {
  165.         return((int32 *)NULL);
  166.     }
  167.  
  168.     /*
  169.      * Second pass to copy integer values into list.
  170.      */
  171.     tptr = str;
  172.     for (i=0; i<cnt; i++)
  173.     {
  174.         char *ptr;
  175.  
  176.         ptr = strchr(tptr, ',');
  177.         if (ptr != NULL)
  178.         {
  179.             *ptr = '\0';
  180.         }
  181.         /*
  182.          * Strip whitespace in front of number because I don't
  183.          * trust atoi to do it on all platforms.
  184.          */
  185.         while (XP_IS_SPACE(*tptr))
  186.         {
  187.             tptr++;
  188.         }
  189.         if (*tptr == '\0')
  190.         {
  191.             value_list[i] = 0;
  192.         }
  193.         else
  194.         {
  195.             value_list[i] = (int32)XP_ATOI(tptr);
  196.         }
  197.         if (ptr != NULL)
  198.         {
  199.             *ptr = ',';
  200.             tptr = (char *)(ptr + 1);
  201.         }
  202.     }
  203.     return(value_list);
  204. }
  205.  
  206.  
  207. /*
  208.  * The beginning of a usemap MAP record.
  209.  * Allocate the structure and initialize it.  It will be filled
  210.  * by later AREA tags.
  211.  */
  212. void
  213. lo_BeginMap(MWContext *context, lo_DocState *state, PA_Tag *tag)
  214. {
  215.     PA_Block buff;
  216.     char *str;
  217.     lo_MapRec *map;
  218.  
  219.     map = XP_NEW(lo_MapRec);
  220.     if (map == NULL)
  221.     {
  222.         state->top_state->out_of_memory = TRUE;
  223.         return;
  224.     }
  225.  
  226.     map->name = NULL;
  227.     map->areas = NULL;
  228.     map->areas_last = NULL;
  229.     map->next = NULL;
  230.  
  231.     buff = lo_FetchParamValue(context, tag, PARAM_NAME);
  232.     if (buff != NULL)
  233.     {
  234.         char *name;
  235.  
  236.         PA_LOCK(str, char *, buff);
  237.         if (str != NULL)
  238.         {
  239.             int32 len;
  240.  
  241.             len = lo_StripTextWhitespace(str, XP_STRLEN(str));
  242.         }
  243.         name = (char *)XP_ALLOC(XP_STRLEN(str) + 1);
  244.         if (name == NULL)
  245.         {
  246.             map->name = NULL;
  247.         }
  248.         else
  249.         {
  250.             XP_STRCPY(name, str);
  251.             map->name = name;
  252.         }
  253.         PA_UNLOCK(buff);
  254.         PA_FREE(buff);
  255.     }
  256.     else
  257.     {
  258.         map->name = NULL;
  259.     }
  260.  
  261.     if (map->name == NULL)
  262.     {
  263.         XP_DELETE(map);
  264.         return;
  265.     }
  266.  
  267.     state->top_state->current_map = map;
  268. }
  269.  
  270.  
  271. /*
  272.  * Look through the list of finished maps to find one with
  273.  * a matching name.  If found, remove it.
  274.  */
  275. static lo_MapRec *
  276. lo_remove_named_map(MWContext *context, lo_DocState *state, char *map_name)
  277. {
  278.     lo_MapRec *prev_map;
  279.     lo_MapRec *map_list;
  280.  
  281.     if (map_name == NULL)
  282.     {
  283.         return(NULL);
  284.     }
  285.  
  286.     prev_map = NULL;
  287.     map_list = state->top_state->map_list;
  288.     while (map_list != NULL)
  289.     {
  290.         /*
  291.          * Found a map with a matching name, return it.
  292.          */
  293.         if (XP_STRCMP(map_name, map_list->name) == 0)
  294.         {
  295.             break;
  296.         }
  297.         prev_map = map_list;
  298.         map_list = map_list->next;
  299.     }
  300.  
  301.     /*
  302.      * No map by that name found.
  303.      */
  304.     if (map_list == NULL)
  305.     {
  306.         return(NULL);
  307.     }
  308.  
  309.     /*
  310.      * If no prev_map, our match is the head of the map_list.
  311.      */
  312.     if (prev_map == NULL)
  313.     {
  314.         state->top_state->map_list = map_list->next;
  315.     }
  316.     else
  317.     {
  318.         prev_map->next = map_list->next;
  319.     }
  320.  
  321.     map_list->next = NULL;
  322.     return(map_list);
  323. }
  324.  
  325.  
  326. /*
  327.  * This map is done, add it to the map list.
  328.  */
  329. void
  330. lo_EndMap(MWContext *context, lo_DocState *state, lo_MapRec *map)
  331. {
  332.     lo_MapRec *old_map;
  333.  
  334.     if (map == NULL)
  335.     {
  336.         return;
  337.     }
  338.  
  339.     old_map = lo_remove_named_map(context, state, map->name);
  340.     if (old_map != NULL)
  341.     {
  342.         (void)lo_FreeMap(old_map);
  343.     }
  344.  
  345.     map->next = state->top_state->map_list;
  346.     state->top_state->map_list = map;
  347. }
  348.  
  349.  
  350. lo_MapRec *
  351. lo_FreeMap(lo_MapRec *map)
  352. {
  353.     lo_MapRec *next;
  354.  
  355.     if (map->areas != NULL)
  356.     {
  357.         lo_MapAreaRec *tmp_area;
  358.         lo_MapAreaRec *areas;
  359.  
  360.         areas = map->areas;
  361.         while (areas != NULL)
  362.         {
  363.             tmp_area = areas;
  364.             areas = areas->next;
  365.             if (tmp_area->alt != NULL)
  366.             {
  367.                 PA_FREE(tmp_area->alt);
  368.             }
  369.             if (tmp_area->coords != NULL)
  370.             {
  371.                 XP_FREE(tmp_area->coords);
  372.             }
  373.             XP_DELETE(tmp_area);
  374.         }
  375.     }
  376.     if (map->name != NULL)
  377.     {
  378.         XP_FREE(map->name);
  379.     }
  380.     next = map->next;
  381.     XP_DELETE(map);
  382.     return next;
  383. }
  384.  
  385.  
  386. /*
  387.  * This is an AREA tag.  Create the structure, fill it in based on the
  388.  * attributes passed, and add it to the map record for the current
  389.  * MAP tag.
  390.  */
  391. void
  392. lo_BeginMapArea(MWContext *context, lo_DocState *state, PA_Tag *tag)
  393. {
  394.     PA_Block buff;
  395.     char *str;
  396.     lo_MapRec *map;
  397.     lo_MapAreaRec *area;
  398.         lo_DocLists *doc_lists;
  399.         
  400.         doc_lists = lo_GetCurrentDocLists(state);
  401.  
  402.     /*
  403.      * Get the current map, if there is none, error out.
  404.      */
  405.     map = state->top_state->current_map;
  406.     if (map == NULL)
  407.     {
  408.         return;
  409.     }
  410.  
  411.     area = XP_NEW(lo_MapAreaRec);
  412.     if (area == NULL)
  413.     {
  414.         state->top_state->out_of_memory = TRUE;
  415.         return;
  416.     }
  417.  
  418.     area->type = AREA_SHAPE_RECT;
  419.     area->coords = NULL;
  420.     area->coord_cnt = 0;
  421.     area->anchor = NULL;
  422.     area->alt = NULL;
  423.     area->alt_len = 0;
  424.     area->next = NULL;
  425.  
  426.     buff = lo_FetchParamValue(context, tag, PARAM_SHAPE);
  427.     if (buff != NULL)
  428.     {
  429.         PA_LOCK(str, char *, buff);
  430.         if (pa_TagEqual(S_AREA_SHAPE_RECT, str))
  431.         {
  432.             area->type = AREA_SHAPE_RECT;
  433.         }
  434.         else if (pa_TagEqual(S_AREA_SHAPE_CIRCLE, str))
  435.         {
  436.             area->type = AREA_SHAPE_CIRCLE;
  437.         }
  438.         else if (pa_TagEqual(S_AREA_SHAPE_POLY, str))
  439.         {
  440.             area->type = AREA_SHAPE_POLY;
  441.         }
  442.         else if (pa_TagEqual(S_AREA_SHAPE_POLYGON, str))
  443.         {
  444.             area->type = AREA_SHAPE_POLY;
  445.         }
  446.         else if (pa_TagEqual(S_AREA_SHAPE_DEFAULT, str))
  447.         {
  448.             area->type = AREA_SHAPE_DEFAULT;
  449.         }
  450.         else
  451.         {
  452.             area->type = AREA_SHAPE_UNKNOWN;
  453.         }
  454.         PA_UNLOCK(buff);
  455.         PA_FREE(buff);
  456.     }
  457.  
  458.     /*
  459.      * Get the alt parameter, and store the resulting
  460.      * text, and its length.
  461.      */
  462.     buff = lo_FetchParamValue(context, tag, PARAM_ALT);
  463.     if (buff != NULL)
  464.     {
  465.         PA_LOCK(str, char *, buff);
  466.         area->alt_len = XP_STRLEN(str);
  467.         area->alt_len = (int16)lo_StripTextNewlines(str,
  468.                         (int32)area->alt_len);
  469.         PA_UNLOCK(buff);
  470.     }
  471.     area->alt = buff;
  472.  
  473.     /*
  474.      * Parse the comma separated coordinate list into an
  475.      * array of integers.
  476.      */
  477.     buff = lo_FetchParamValue(context, tag, PARAM_COORDS);
  478.     if (buff != NULL)
  479.     {
  480.         int32 cnt;
  481.         Bool must_be_odd;
  482.  
  483.         must_be_odd = FALSE;
  484.         if (area->type == AREA_SHAPE_POLY)
  485.         {
  486.             must_be_odd = TRUE;
  487.         }
  488.         PA_LOCK(str, char *, buff);
  489.         area->coords = lo_parse_coord_list(str, &cnt, must_be_odd);
  490.         if (area->coords != NULL)
  491.         {
  492.             area->coord_cnt = cnt;
  493.         }
  494.         PA_UNLOCK(buff);
  495.         PA_FREE(buff);
  496.     }
  497.  
  498.     /*
  499.      * Get the HREF, and if one exists, get the TARGET to go along
  500.      * with it.
  501.      */
  502.     buff = lo_FetchParamValue(context, tag, PARAM_HREF);
  503.     if (buff != NULL)
  504.     {
  505.         char *target;
  506.         PA_Block targ_buff;
  507.         PA_Block href_buff;
  508.         LO_AnchorData *anchor;
  509.  
  510.         anchor = NULL;
  511.         PA_LOCK(str, char *, buff);
  512.         if (str != NULL)
  513.         {
  514.             int32 len;
  515.  
  516.             len = lo_StripTextWhitespace(str, XP_STRLEN(str));
  517.         }
  518.         str = NET_MakeAbsoluteURL(state->top_state->base_url, str);
  519.         if (str == NULL)
  520.         {
  521.             href_buff = NULL;
  522.         }
  523.         else
  524.         {
  525.             href_buff = PA_ALLOC(XP_STRLEN(str) + 1);
  526.             if (href_buff != NULL)
  527.             {
  528.                 char *full_url;
  529.  
  530.                 PA_LOCK(full_url, char *, href_buff);
  531.                 XP_STRCPY(full_url, str);
  532.                 PA_UNLOCK(href_buff);
  533.             }
  534.             else
  535.             {
  536.                 state->top_state->out_of_memory = TRUE;
  537.             }
  538.             XP_FREE(str);
  539.         }
  540.         PA_UNLOCK(buff);
  541.         PA_FREE(buff);
  542.  
  543.         if (href_buff != NULL)
  544.         {
  545.             targ_buff = lo_FetchParamValue(context, tag, PARAM_TARGET);
  546.             if (targ_buff != NULL)
  547.             {
  548.                 int32 len;
  549.  
  550.                 PA_LOCK(target, char *, targ_buff);
  551.                 len = lo_StripTextWhitespace(target,
  552.                         XP_STRLEN(target));
  553.                 if ((*target == '\0')||
  554.                     (lo_IsValidTarget(target) == FALSE))
  555.                 {
  556.                     PA_UNLOCK(targ_buff);
  557.                     PA_FREE(targ_buff);
  558.                     targ_buff = NULL;
  559.                 }
  560.                 else
  561.                 {
  562.                     PA_UNLOCK(targ_buff);
  563.                 }
  564.             }
  565.  
  566.             /*
  567.              * If there was no target use the default one.
  568.              * (default provided by BASE tag)
  569.              */
  570.             if ((targ_buff == NULL)&&
  571.                 (state->top_state->base_target != NULL))
  572.             {
  573.                 targ_buff = PA_ALLOC(XP_STRLEN(
  574.                     state->top_state->base_target) + 1);
  575.                 if (targ_buff != NULL)
  576.                 {
  577.                     char *targ;
  578.  
  579.                     PA_LOCK(targ, char *, targ_buff);
  580.                     XP_STRCPY(targ,
  581.                         state->top_state->base_target);
  582.                     PA_UNLOCK(targ_buff);
  583.                 }
  584.                 else
  585.                 {
  586.                     state->top_state->out_of_memory = TRUE;
  587.                 }
  588.             }
  589.  
  590.             anchor = lo_NewAnchor(state, href_buff, targ_buff);
  591.             if (anchor == NULL)
  592.             {
  593.                 PA_FREE(href_buff);
  594.                 if (targ_buff != NULL)
  595.                 {
  596.                     PA_FREE(targ_buff);
  597.                 }
  598.             }
  599.             /*
  600.              * If the AREA tag has an ALT attribute,
  601.              * stick that text into the anchor data.
  602.              */
  603.             else if (area->alt != NULL)
  604.             {
  605.                 PA_Block alt_buff;
  606.                 char *alt_text;
  607.  
  608.                 PA_LOCK(alt_text, char *, area->alt);
  609.                 alt_buff = PA_ALLOC(area->alt_len + 1);
  610.                 if (alt_buff != NULL)
  611.                 {
  612.                     char *new_alt;
  613.  
  614.                     PA_LOCK(new_alt, char *, alt_buff);
  615.                     XP_STRCPY(new_alt, alt_text);
  616.                     PA_UNLOCK(alt_buff);
  617.                 }
  618.                 PA_UNLOCK(area->alt);
  619.                 anchor->alt = alt_buff;
  620.             }
  621.         }
  622.  
  623.         /* If SUPPRESS attribute is present, suppress visual feedback (dashed rectangle)
  624.            when link is selected */
  625.         buff = lo_FetchParamValue(context, tag, PARAM_SUPPRESS);
  626.         if (buff && !XP_STRCASECMP((char*)buff, "true"))
  627.         {
  628.             anchor->flags |= ANCHOR_SUPPRESS_FEEDBACK;
  629.         }
  630.  
  631.         /*
  632.          * Add this url's block to the list
  633.          * of all allocated urls so we can free
  634.          * it later.
  635.          */
  636.         lo_AddToUrlList(context, state, anchor);
  637.         if (state->top_state->out_of_memory != FALSE)
  638.         {
  639.             return;
  640.         }
  641.         area->anchor = anchor;
  642.  
  643.         /*
  644.          * If there are event handlers, reflect this
  645.          * tag into Mocha as a link.
  646.          */
  647.         lo_ReflectLink(context, state, tag, anchor,
  648.                                lo_CurrentLayerId(state),
  649.                                doc_lists->url_list_len - 1);
  650.     }
  651.  
  652.     /*
  653.      * Add this are to the end of the area list in this
  654.      * map record.
  655.      */
  656.     if (map->areas_last == NULL)
  657.     {
  658.         map->areas = area;
  659.         map->areas_last = area;
  660.     }
  661.     else
  662.     {
  663.         map->areas_last->next = area;
  664.         map->areas_last = area;
  665.     }
  666. }
  667.  
  668.  
  669. /*
  670.  * Look through the list of finished maps to find one with
  671.  * a matching name.
  672.  */
  673. lo_MapRec *
  674. lo_FindNamedMap(MWContext *context, lo_DocState *state, char *map_name)
  675. {
  676.     lo_MapRec *map_list;
  677.  
  678.     if (map_name == NULL)
  679.     {
  680.         return(NULL);
  681.     }
  682.  
  683.     map_list = state->top_state->map_list;
  684.     while (map_list != NULL)
  685.     {
  686.         /*
  687.          * Found a map with a matching name, return it.
  688.          */
  689.         if (XP_STRCMP(map_name, map_list->name) == 0)
  690.         {
  691.             break;
  692.         }
  693.         map_list = map_list->next;
  694.     }
  695.     return(map_list);
  696. }
  697.  
  698.  
  699. /*
  700.  * Check if a point is in a rectable specified by upper-left and
  701.  * lower-right corners.
  702.  */
  703. static Bool
  704. lo_is_location_in_rect(int32 x, int32 y, int32 *coords)
  705. {
  706.     int32 x1, y1, x2, y2;
  707.  
  708.     x1 = coords[0];
  709.     y1 = coords[1];
  710.     x2 = coords[2];
  711.     y2 = coords[3];
  712.     if ((x1 > x2)||(y1 > y2))
  713.     {
  714.         return(FALSE);
  715.     }
  716.     if ((x >= x1)&&(x <= x2)&&(y >= y1)&&(y <= y2))
  717.     {
  718.         return(TRUE);
  719.     }
  720.     else
  721.     {
  722.         return(FALSE);
  723.     }
  724. }
  725.  
  726.  
  727. /*
  728.  * Check if a point is within the radius of a circle specified
  729.  * by center and radius.
  730.  */
  731. static Bool
  732. lo_is_location_in_circle(int32 x, int32 y, int32 *coords)
  733. {
  734.     int32 x1, y1, radius;
  735.     int32 dx, dy, dist;
  736.  
  737.     x1 = coords[0];
  738.     y1 = coords[1];
  739.     radius = coords[2];
  740.     if (radius < 0)
  741.     {
  742.         return(FALSE);
  743.     }
  744.  
  745.     dx = x1 - x;
  746.     dy = y1 - y;
  747.  
  748.     dist = (dx * dx) + (dy * dy);
  749.  
  750.     if (dist <= (radius * radius))
  751.     {
  752.         return(TRUE);
  753.     }
  754.     else
  755.     {
  756.         return(FALSE);
  757.     }
  758. }
  759.  
  760.  
  761. /*
  762.  * Check if the passed point is withing the area described in
  763.  * the area structure.
  764.  */
  765. static Bool
  766. lo_is_location_in_area(lo_MapAreaRec *area, int32 x, int32 y)
  767. {
  768.     Bool ret_val;
  769.  
  770.     if (area == NULL)
  771.     {
  772.         return(FALSE);
  773.     }
  774.  
  775.     ret_val = FALSE;
  776.     switch(area->type)
  777.     {
  778.         case AREA_SHAPE_RECT:
  779.             if (area->coord_cnt < 4)
  780.             {
  781.                 ret_val = FALSE;
  782.             }
  783.             else
  784.             {
  785.                 ret_val = lo_is_location_in_rect(x, y,
  786.                                 area->coords);
  787.             }
  788.             break;
  789.  
  790.         case AREA_SHAPE_CIRCLE:
  791.             if (area->coord_cnt < 3)
  792.             {
  793.                 ret_val = FALSE;
  794.             }
  795.             else
  796.             {
  797.                 ret_val = lo_is_location_in_circle(x, y,
  798.                                 area->coords);
  799.             }
  800.             break;
  801.  
  802.         case AREA_SHAPE_POLY:
  803.             if (area->coord_cnt < 6)
  804.             {
  805.                 ret_val = FALSE;
  806.             }
  807.             else
  808.             {
  809.                 ret_val = lo_is_location_in_poly(x, y,
  810.                         area->coords, area->coord_cnt);
  811.             }
  812.             break;
  813.  
  814.         case AREA_SHAPE_DEFAULT:
  815.             ret_val = TRUE;
  816.             break;
  817.  
  818.         case AREA_SHAPE_UNKNOWN:
  819.         default:
  820.             break;
  821.     }
  822.     return(ret_val);
  823. }
  824.  
  825. /*
  826.  * Given an x,y location and a map, return the anchor data for the
  827.  * usemap.  Return NULL for areas not described or with no specified href.
  828.  */
  829. LO_AnchorData *
  830. lo_MapXYToAnchorData(MWContext *context, lo_DocState *state,
  831.             lo_MapRec *map, int32 x, int32 y)
  832. {
  833.     lo_MapAreaRec *areas;
  834.  
  835.     if (map == NULL)
  836.     {
  837.         return(NULL);
  838.     }
  839.  
  840.     areas = map->areas;
  841.     while (areas != NULL)
  842.     {
  843.         /*
  844.          * If we found a containing area, return its anchor data.
  845.          */
  846.         if (lo_is_location_in_area(areas, x, y) != FALSE)
  847.         {
  848.             break;
  849.         }
  850.         areas = areas->next;
  851.     }
  852.     if (areas != NULL)
  853.     {
  854.         return(areas->anchor);
  855.     }
  856.     else
  857.     {
  858.         return(NULL);
  859.     }
  860. }
  861.  
  862.  
  863. /*
  864.  * Public function for front ends to get the usemap anchor data
  865.  * for an image, based on the x,y of the user in the image.
  866.  */
  867. LO_AnchorData *
  868. LO_MapXYToAreaAnchor(MWContext *context, LO_ImageStruct *image,
  869.             int32 x, int32 y)
  870. {
  871.     int32 doc_id;
  872.     lo_TopState *top_state;
  873.     lo_DocState *state;
  874.     LO_AnchorData *anchor;
  875.     lo_MapRec *map;
  876.  
  877.     /*
  878.      * Get the unique document ID, and retreive this
  879.      * documents layout state.
  880.      */
  881.     doc_id = XP_DOCID(context);
  882.     top_state = lo_FetchTopState(doc_id);
  883.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  884.     {
  885.         return(NULL);
  886.     }
  887.     state = top_state->doc_state;
  888.  
  889.     /*
  890.      * If this is not really a USEMAP image, leave now.
  891.      */
  892.     if (image->image_attr->usemap_name == NULL)
  893.     {
  894.         return(NULL);
  895.     }
  896.  
  897.     /*
  898.      * If we havn't looked up and stored the map
  899.      * pointer for this image before, do that now,
  900.      * otherwise use the stored map pointer.
  901.      */
  902.     if (image->image_attr->usemap_ptr == NULL)
  903.     {
  904.         map = lo_FindNamedMap(context, state,
  905.                 image->image_attr->usemap_name);
  906.         image->image_attr->usemap_ptr = (void *)map;
  907.     }
  908.     else
  909.     {
  910.         map = (lo_MapRec *)image->image_attr->usemap_ptr;
  911.     }
  912.  
  913.     anchor = lo_MapXYToAnchorData(context, state, map, x, y);
  914.     return(anchor);
  915. }
  916.  
  917. /* #ifndef NO_TAB_NAVIGATION */
  918. /*
  919.     see LO_MapXYToAreaAnchor() above for accessing the map structure.
  920.     if currentAreaIndex <= 0 , return the first area.
  921. */
  922. lo_MapAreaRec *
  923. LO_getTabableMapArea(MWContext *context, LO_ImageStruct *image, int32 wantedIndex )
  924. {
  925.     lo_MapRec        *map;    
  926.     lo_MapAreaRec    *areas;
  927.     LO_AnchorData    *tempData;
  928.  
  929.  
  930.     if( image == NULL || image->type != LO_IMAGE )
  931.         return( NULL );
  932.  
  933.     /* We don't need the Anchor, but make sure we look up and store the map pointer.*/
  934.     tempData = LO_MapXYToAreaAnchor( context, image, 0, 0);
  935.  
  936.     if (image->image_attr->usemap_name == NULL)    /*     not really a USEMAP image. */
  937.         return(NULL);
  938.  
  939.     map = (lo_MapRec *)image->image_attr->usemap_ptr;
  940.     if (map == NULL)
  941.         return(NULL);
  942.  
  943.     /* TODO if wantedIndex == -2, return the last tabable area */
  944.     if( wantedIndex <= 0 )    
  945.         wantedIndex = 1;
  946.     
  947.     areas = map->areas;
  948.     while (areas != NULL )
  949.     {
  950.         if( areas->anchor != NULL ) { /* only tabable areas are counted */
  951.             if( wantedIndex == 1 )
  952.                 return( areas );        /* got it */
  953.             else
  954.                 wantedIndex--;                
  955.         }
  956.         areas = areas->next;
  957.     }
  958.  
  959.     return( NULL );
  960. }
  961.  
  962. Bool
  963. LO_findApointInArea( lo_MapAreaRec *pArea, int32 *xx, int32 *yy )
  964. {
  965.  
  966.     if ( pArea == NULL)
  967.         return(FALSE);
  968.  
  969.     switch( pArea->type )
  970.     {
  971.         case AREA_SHAPE_RECT:
  972.             if (pArea->coord_cnt >= 4)
  973.             {    /* the center of the rect */
  974.                 *xx    = ( pArea->coords[0] + pArea->coords[2] ) / 2;        
  975.                 *yy    = ( pArea->coords[1] + pArea->coords[3] ) / 2;        
  976.                 return( TRUE );
  977.             }
  978.             break;
  979.  
  980.         case AREA_SHAPE_CIRCLE:
  981.             if ( pArea->coord_cnt >= 3)
  982.             {    /* the center of the rect */
  983.                 *xx = pArea->coords[0];
  984.                 *yy = pArea->coords[1];
  985.                 return( TRUE );
  986.             }
  987.             break;
  988.  
  989.         case AREA_SHAPE_POLY:
  990.             if (pArea->coord_cnt >= 6)
  991.             {
  992.                 return( lo_find_location_in_poly(xx, yy, pArea->coords, pArea->coord_cnt) );
  993.             }
  994.             break;
  995.  
  996.         case AREA_SHAPE_DEFAULT:
  997.             /* TODO ?????? */
  998.             break;
  999.  
  1000.         case AREA_SHAPE_UNKNOWN:
  1001.         default:
  1002.             break;
  1003.     }
  1004.  
  1005.     return( FALSE );
  1006. }
  1007.  
  1008. /* NO_TAB_NAVIGATION */
  1009.  
  1010.  
  1011.