LCOV - code coverage report
Current view: directory - layout/generic - nsImageMap.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 448 0 0.0 %
Date: 2012-06-02 Functions: 56 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Mats Palmgren <mats.palmgren@bredband.net>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : /* code for HTML client-side image maps */
      40                 : 
      41                 : #include "nsImageMap.h"
      42                 : 
      43                 : #include "nsString.h"
      44                 : #include "nsReadableUtils.h"
      45                 : #include "nsRenderingContext.h"
      46                 : #include "nsPresContext.h"
      47                 : #include "nsIURL.h"
      48                 : #include "nsIServiceManager.h"
      49                 : #include "nsNetUtil.h"
      50                 : #include "nsTextFragment.h"
      51                 : #include "mozilla/dom/Element.h"
      52                 : #include "nsIDocument.h"
      53                 : #include "nsINameSpaceManager.h"
      54                 : #include "nsGkAtoms.h"
      55                 : #include "nsIDOMEventTarget.h"
      56                 : #include "nsIPresShell.h"
      57                 : #include "nsImageFrame.h"
      58                 : #include "nsCoord.h"
      59                 : #include "nsIConsoleService.h"
      60                 : #include "nsIScriptError.h"
      61                 : #include "nsIStringBundle.h"
      62                 : #include "nsContentUtils.h"
      63                 : 
      64                 : namespace dom = mozilla::dom;
      65                 : 
      66                 : static NS_DEFINE_CID(kCStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
      67                 : 
      68                 : class Area {
      69                 : public:
      70                 :   Area(nsIContent* aArea);
      71                 :   virtual ~Area();
      72                 : 
      73                 :   virtual void ParseCoords(const nsAString& aSpec);
      74                 : 
      75                 :   virtual bool IsInside(nscoord x, nscoord y) const = 0;
      76                 :   virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) = 0;
      77                 :   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) = 0;
      78                 : 
      79                 :   void HasFocus(bool aHasFocus);
      80                 : 
      81                 :   nsCOMPtr<nsIContent> mArea;
      82                 :   nscoord* mCoords;
      83                 :   PRInt32 mNumCoords;
      84                 :   bool mHasFocus;
      85                 : };
      86                 : 
      87               0 : Area::Area(nsIContent* aArea)
      88               0 :   : mArea(aArea)
      89                 : {
      90               0 :   MOZ_COUNT_CTOR(Area);
      91               0 :   NS_PRECONDITION(mArea, "How did that happen?");
      92               0 :   mCoords = nsnull;
      93               0 :   mNumCoords = 0;
      94               0 :   mHasFocus = false;
      95               0 : }
      96                 : 
      97               0 : Area::~Area()
      98                 : {
      99               0 :   MOZ_COUNT_DTOR(Area);
     100               0 :   delete [] mCoords;
     101               0 : }
     102                 : 
     103                 : #include <stdlib.h>
     104                 : 
     105                 : inline bool
     106               0 : is_space(char c)
     107                 : {
     108                 :   return (c == ' ' ||
     109                 :           c == '\f' ||
     110                 :           c == '\n' ||
     111                 :           c == '\r' ||
     112                 :           c == '\t' ||
     113               0 :           c == '\v');
     114                 : }
     115                 : 
     116               0 : static void logMessage(nsIContent*      aContent,
     117                 :                        const nsAString& aCoordsSpec,
     118                 :                        PRInt32          aFlags,
     119                 :                        const char* aMessageName) {
     120               0 :   nsIDocument* doc = aContent->OwnerDoc();
     121                 : 
     122                 :   nsContentUtils::ReportToConsole(
     123                 :      aFlags, "ImageMap", doc,
     124                 :      nsContentUtils::eLAYOUT_PROPERTIES,
     125                 :      aMessageName,
     126                 :      nsnull,  /* params */
     127                 :      0, /* params length */
     128                 :      nsnull,
     129               0 :      PromiseFlatString(NS_LITERAL_STRING("coords=\"") +
     130               0 :                        aCoordsSpec +
     131               0 :                        NS_LITERAL_STRING("\""))); /* source line */
     132               0 : }
     133                 : 
     134               0 : void Area::ParseCoords(const nsAString& aSpec)
     135                 : {
     136               0 :   char* cp = ToNewCString(aSpec);
     137               0 :   if (cp) {
     138                 :     char *tptr;
     139                 :     char *n_str;
     140                 :     PRInt32 i, cnt;
     141                 :     PRInt32 *value_list;
     142                 : 
     143                 :     /*
     144                 :      * Nothing in an empty list
     145                 :      */
     146               0 :     mNumCoords = 0;
     147               0 :     mCoords = nsnull;
     148               0 :     if (*cp == '\0')
     149                 :     {
     150               0 :       nsMemory::Free(cp);
     151               0 :       return;
     152                 :     }
     153                 : 
     154                 :     /*
     155                 :      * Skip beginning whitespace, all whitespace is empty list.
     156                 :      */
     157               0 :     n_str = cp;
     158               0 :     while (is_space(*n_str))
     159                 :     {
     160               0 :       n_str++;
     161                 :     }
     162               0 :     if (*n_str == '\0')
     163                 :     {
     164               0 :       nsMemory::Free(cp);
     165               0 :       return;
     166                 :     }
     167                 : 
     168                 :     /*
     169                 :      * Make a pass where any two numbers separated by just whitespace
     170                 :      * are given a comma separator.  Count entries while passing.
     171                 :      */
     172               0 :     cnt = 0;
     173               0 :     while (*n_str != '\0')
     174                 :     {
     175                 :       bool has_comma;
     176                 : 
     177                 :       /*
     178                 :        * Skip to a separator
     179                 :        */
     180               0 :       tptr = n_str;
     181               0 :       while (!is_space(*tptr) && *tptr != ',' && *tptr != '\0')
     182                 :       {
     183               0 :         tptr++;
     184                 :       }
     185               0 :       n_str = tptr;
     186                 : 
     187                 :       /*
     188                 :        * If no more entries, break out here
     189                 :        */
     190               0 :       if (*n_str == '\0')
     191                 :       {
     192               0 :         break;
     193                 :       }
     194                 : 
     195                 :       /*
     196                 :        * Skip to the end of the separator, noting if we have a
     197                 :        * comma.
     198                 :        */
     199               0 :       has_comma = false;
     200               0 :       while (is_space(*tptr) || *tptr == ',')
     201                 :       {
     202               0 :         if (*tptr == ',')
     203                 :         {
     204               0 :           if (!has_comma)
     205                 :           {
     206               0 :             has_comma = true;
     207                 :           }
     208                 :           else
     209                 :           {
     210               0 :             break;
     211                 :           }
     212                 :         }
     213               0 :         tptr++;
     214                 :       }
     215                 :       /*
     216                 :        * If this was trailing whitespace we skipped, we are done.
     217                 :        */
     218               0 :       if ((*tptr == '\0') && !has_comma)
     219                 :       {
     220               0 :         break;
     221                 :       }
     222                 :       /*
     223                 :        * Else if the separator is all whitespace, and this is not the
     224                 :        * end of the string, add a comma to the separator.
     225                 :        */
     226               0 :       else if (!has_comma)
     227                 :       {
     228               0 :         *n_str = ',';
     229                 :       }
     230                 : 
     231                 :       /*
     232                 :        * count the entry skipped.
     233                 :        */
     234               0 :       cnt++;
     235                 : 
     236               0 :       n_str = tptr;
     237                 :     }
     238                 :     /*
     239                 :      * count the last entry in the list.
     240                 :      */
     241               0 :     cnt++;
     242                 : 
     243                 :     /*
     244                 :      * Allocate space for the coordinate array.
     245                 :      */
     246               0 :     value_list = new nscoord[cnt];
     247               0 :     if (!value_list)
     248                 :     {
     249               0 :       nsMemory::Free(cp);
     250               0 :       return;
     251                 :     }
     252                 : 
     253                 :     /*
     254                 :      * Second pass to copy integer values into list.
     255                 :      */
     256               0 :     tptr = cp;
     257               0 :     for (i=0; i<cnt; i++)
     258                 :     {
     259                 :       char *ptr;
     260                 : 
     261               0 :       ptr = strchr(tptr, ',');
     262               0 :       if (ptr)
     263                 :       {
     264               0 :         *ptr = '\0';
     265                 :       }
     266                 :       /*
     267                 :        * Strip whitespace in front of number because I don't
     268                 :        * trust atoi to do it on all platforms.
     269                 :        */
     270               0 :       while (is_space(*tptr))
     271                 :       {
     272               0 :         tptr++;
     273                 :       }
     274               0 :       if (*tptr == '\0')
     275                 :       {
     276               0 :         value_list[i] = 0;
     277                 :       }
     278                 :       else
     279                 :       {
     280               0 :         value_list[i] = (nscoord) ::atoi(tptr);
     281                 :       }
     282               0 :       if (ptr)
     283                 :       {
     284               0 :         *ptr = ',';
     285               0 :         tptr = ptr + 1;
     286                 :       }
     287                 :     }
     288                 : 
     289               0 :     mNumCoords = cnt;
     290               0 :     mCoords = value_list;
     291                 : 
     292               0 :     nsMemory::Free(cp);
     293                 :   }
     294                 : }
     295                 : 
     296               0 : void Area::HasFocus(bool aHasFocus)
     297                 : {
     298               0 :   mHasFocus = aHasFocus;
     299               0 : }
     300                 : 
     301                 : //----------------------------------------------------------------------
     302                 : 
     303               0 : class DefaultArea : public Area {
     304                 : public:
     305                 :   DefaultArea(nsIContent* aArea);
     306                 : 
     307                 :   virtual bool IsInside(nscoord x, nscoord y) const;
     308                 :   virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC);
     309                 :   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect);
     310                 : };
     311                 : 
     312               0 : DefaultArea::DefaultArea(nsIContent* aArea)
     313               0 :   : Area(aArea)
     314                 : {
     315               0 : }
     316                 : 
     317               0 : bool DefaultArea::IsInside(nscoord x, nscoord y) const
     318                 : {
     319               0 :   return true;
     320                 : }
     321                 : 
     322               0 : void DefaultArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
     323                 : {
     324               0 :   if (mHasFocus) {
     325               0 :     nsRect r = aFrame->GetRect();
     326               0 :     r.MoveTo(0, 0);
     327               0 :     nscoord x1 = r.x;
     328               0 :     nscoord y1 = r.y;
     329               0 :     const nscoord kOnePixel = nsPresContext::CSSPixelsToAppUnits(1);
     330               0 :     nscoord x2 = r.XMost() - kOnePixel;
     331               0 :     nscoord y2 = r.YMost() - kOnePixel;
     332                 :     // XXX aRC.DrawRect(r) result is ugly, that's why we use DrawLine.
     333               0 :     aRC.DrawLine(x1, y1, x1, y2);
     334               0 :     aRC.DrawLine(x1, y2, x2, y2);
     335               0 :     aRC.DrawLine(x1, y1, x2, y1);
     336               0 :     aRC.DrawLine(x2, y1, x2, y2);
     337                 :   }
     338               0 : }
     339                 : 
     340               0 : void DefaultArea::GetRect(nsIFrame* aFrame, nsRect& aRect)
     341                 : {
     342               0 :   aRect = aFrame->GetRect();
     343               0 :   aRect.MoveTo(0, 0);
     344               0 : }
     345                 : 
     346                 : //----------------------------------------------------------------------
     347                 : 
     348               0 : class RectArea : public Area {
     349                 : public:
     350                 :   RectArea(nsIContent* aArea);
     351                 : 
     352                 :   virtual void ParseCoords(const nsAString& aSpec);
     353                 :   virtual bool IsInside(nscoord x, nscoord y) const;
     354                 :   virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC);
     355                 :   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect);
     356                 : };
     357                 : 
     358               0 : RectArea::RectArea(nsIContent* aArea)
     359               0 :   : Area(aArea)
     360                 : {
     361               0 : }
     362                 : 
     363               0 : void RectArea::ParseCoords(const nsAString& aSpec)
     364                 : {
     365               0 :   Area::ParseCoords(aSpec);
     366                 : 
     367               0 :   bool saneRect = true;
     368               0 :   PRInt32 flag = nsIScriptError::warningFlag;
     369               0 :   if (mNumCoords >= 4) {
     370               0 :     if (mCoords[0] > mCoords[2]) {
     371                 :       // x-coords in reversed order
     372               0 :       nscoord x = mCoords[2];
     373               0 :       mCoords[2] = mCoords[0];
     374               0 :       mCoords[0] = x;
     375               0 :       saneRect = false;
     376                 :     }
     377                 : 
     378               0 :     if (mCoords[1] > mCoords[3]) {
     379                 :       // y-coords in reversed order
     380               0 :       nscoord y = mCoords[3];
     381               0 :       mCoords[3] = mCoords[1];
     382               0 :       mCoords[1] = y;
     383               0 :       saneRect = false;
     384                 :     }
     385                 : 
     386               0 :     if (mNumCoords > 4) {
     387                 :       // Someone missed the concept of a rect here
     388               0 :       saneRect = false;
     389                 :     }
     390                 :   } else {
     391               0 :     saneRect = false;
     392               0 :     flag = nsIScriptError::errorFlag;
     393                 :   }
     394                 : 
     395               0 :   if (!saneRect) {
     396               0 :     logMessage(mArea, aSpec, flag, "ImageMapRectBoundsError");
     397                 :   }
     398               0 : }
     399                 : 
     400               0 : bool RectArea::IsInside(nscoord x, nscoord y) const
     401                 : {
     402               0 :   if (mNumCoords >= 4) {       // Note: > is for nav compatibility
     403               0 :     nscoord x1 = mCoords[0];
     404               0 :     nscoord y1 = mCoords[1];
     405               0 :     nscoord x2 = mCoords[2];
     406               0 :     nscoord y2 = mCoords[3];
     407               0 :     NS_ASSERTION(x1 <= x2 && y1 <= y2,
     408                 :                  "Someone screwed up RectArea::ParseCoords");
     409               0 :     if ((x >= x1) && (x <= x2) && (y >= y1) && (y <= y2)) {
     410               0 :       return true;
     411                 :     }
     412                 :   }
     413               0 :   return false;
     414                 : }
     415                 : 
     416               0 : void RectArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
     417                 : {
     418               0 :   if (mHasFocus) {
     419               0 :     if (mNumCoords >= 4) {
     420               0 :       nscoord x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
     421               0 :       nscoord y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
     422               0 :       nscoord x2 = nsPresContext::CSSPixelsToAppUnits(mCoords[2]);
     423               0 :       nscoord y2 = nsPresContext::CSSPixelsToAppUnits(mCoords[3]);
     424               0 :       NS_ASSERTION(x1 <= x2 && y1 <= y2,
     425                 :                    "Someone screwed up RectArea::ParseCoords");
     426               0 :       aRC.DrawLine(x1, y1, x1, y2);
     427               0 :       aRC.DrawLine(x1, y2, x2, y2);
     428               0 :       aRC.DrawLine(x1, y1, x2, y1);
     429               0 :       aRC.DrawLine(x2, y1, x2, y2);
     430                 :     }
     431                 :   }
     432               0 : }
     433                 : 
     434               0 : void RectArea::GetRect(nsIFrame* aFrame, nsRect& aRect)
     435                 : {
     436               0 :   if (mNumCoords >= 4) {
     437               0 :     nscoord x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
     438               0 :     nscoord y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
     439               0 :     nscoord x2 = nsPresContext::CSSPixelsToAppUnits(mCoords[2]);
     440               0 :     nscoord y2 = nsPresContext::CSSPixelsToAppUnits(mCoords[3]);
     441               0 :     NS_ASSERTION(x1 <= x2 && y1 <= y2,
     442                 :                  "Someone screwed up RectArea::ParseCoords");
     443                 : 
     444               0 :     aRect.SetRect(x1, y1, x2, y2);
     445                 :   }
     446               0 : }
     447                 : 
     448                 : //----------------------------------------------------------------------
     449                 : 
     450               0 : class PolyArea : public Area {
     451                 : public:
     452                 :   PolyArea(nsIContent* aArea);
     453                 : 
     454                 :   virtual void ParseCoords(const nsAString& aSpec);
     455                 :   virtual bool IsInside(nscoord x, nscoord y) const;
     456                 :   virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC);
     457                 :   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect);
     458                 : };
     459                 : 
     460               0 : PolyArea::PolyArea(nsIContent* aArea)
     461               0 :   : Area(aArea)
     462                 : {
     463               0 : }
     464                 : 
     465               0 : void PolyArea::ParseCoords(const nsAString& aSpec)
     466                 : {
     467               0 :   Area::ParseCoords(aSpec);
     468                 : 
     469               0 :   if (mNumCoords >= 2) {
     470               0 :     if (mNumCoords & 1U) {
     471                 :       logMessage(mArea,
     472                 :                  aSpec,
     473                 :                  nsIScriptError::warningFlag,
     474               0 :                  "ImageMapPolyOddNumberOfCoords");
     475                 :     }
     476                 :   } else {
     477                 :     logMessage(mArea,
     478                 :                aSpec,
     479                 :                nsIScriptError::errorFlag,
     480               0 :                "ImageMapPolyWrongNumberOfCoords");
     481                 :   }
     482               0 : }
     483                 : 
     484               0 : bool PolyArea::IsInside(nscoord x, nscoord y) const
     485                 : {
     486               0 :   if (mNumCoords >= 6) {
     487               0 :     PRInt32 intersects = 0;
     488               0 :     nscoord wherex = x;
     489               0 :     nscoord wherey = y;
     490               0 :     PRInt32 totalv = mNumCoords / 2;
     491               0 :     PRInt32 totalc = totalv * 2;
     492               0 :     nscoord xval = mCoords[totalc - 2];
     493               0 :     nscoord yval = mCoords[totalc - 1];
     494               0 :     PRInt32 end = totalc;
     495               0 :     PRInt32 pointer = 1;
     496                 : 
     497               0 :     if ((yval >= wherey) != (mCoords[pointer] >= wherey)) {
     498               0 :       if ((xval >= wherex) == (mCoords[0] >= wherex)) {
     499               0 :         intersects += (xval >= wherex) ? 1 : 0;
     500                 :       } else {
     501                 :         intersects += ((xval - (yval - wherey) *
     502               0 :                         (mCoords[0] - xval) /
     503               0 :                         (mCoords[pointer] - yval)) >= wherex) ? 1 : 0;
     504                 :       }
     505                 :     }
     506                 : 
     507                 :     // XXX I wonder what this is doing; this is a translation of ptinpoly.c
     508               0 :     while (pointer < end)  {
     509               0 :       yval = mCoords[pointer];
     510               0 :       pointer += 2;
     511               0 :       if (yval >= wherey)  {
     512               0 :         while((pointer < end) && (mCoords[pointer] >= wherey))
     513               0 :           pointer+=2;
     514               0 :         if (pointer >= end)
     515               0 :           break;
     516               0 :         if ((mCoords[pointer-3] >= wherex) ==
     517               0 :             (mCoords[pointer-1] >= wherex)) {
     518               0 :           intersects += (mCoords[pointer-3] >= wherex) ? 1 : 0;
     519                 :         } else {
     520                 :           intersects +=
     521               0 :             ((mCoords[pointer-3] - (mCoords[pointer-2] - wherey) *
     522               0 :               (mCoords[pointer-1] - mCoords[pointer-3]) /
     523               0 :               (mCoords[pointer] - mCoords[pointer - 2])) >= wherex) ? 1:0;
     524                 :         }
     525                 :       }  else  {
     526               0 :         while((pointer < end) && (mCoords[pointer] < wherey))
     527               0 :           pointer+=2;
     528               0 :         if (pointer >= end)
     529               0 :           break;
     530               0 :         if ((mCoords[pointer-3] >= wherex) ==
     531               0 :             (mCoords[pointer-1] >= wherex)) {
     532               0 :           intersects += (mCoords[pointer-3] >= wherex) ? 1:0;
     533                 :         } else {
     534                 :           intersects +=
     535               0 :             ((mCoords[pointer-3] - (mCoords[pointer-2] - wherey) *
     536               0 :               (mCoords[pointer-1] - mCoords[pointer-3]) /
     537               0 :               (mCoords[pointer] - mCoords[pointer - 2])) >= wherex) ? 1:0;
     538                 :         }
     539                 :       }
     540                 :     }
     541               0 :     if ((intersects & 1) != 0) {
     542               0 :       return true;
     543                 :     }
     544                 :   }
     545               0 :   return false;
     546                 : }
     547                 : 
     548               0 : void PolyArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
     549                 : {
     550               0 :   if (mHasFocus) {
     551               0 :     if (mNumCoords >= 6) {
     552               0 :       nscoord x0 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
     553               0 :       nscoord y0 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
     554                 :       nscoord x1, y1;
     555               0 :       for (PRInt32 i = 2; i < mNumCoords; i += 2) {
     556               0 :         x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[i]);
     557               0 :         y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[i+1]);
     558               0 :         aRC.DrawLine(x0, y0, x1, y1);
     559               0 :         x0 = x1;
     560               0 :         y0 = y1;
     561                 :       }
     562               0 :       x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
     563               0 :       y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
     564               0 :       aRC.DrawLine(x0, y0, x1, y1);
     565                 :     }
     566                 :   }
     567               0 : }
     568                 : 
     569               0 : void PolyArea::GetRect(nsIFrame* aFrame, nsRect& aRect)
     570                 : {
     571               0 :   if (mNumCoords >= 6) {
     572                 :     nscoord x1, x2, y1, y2, xtmp, ytmp;
     573               0 :     x1 = x2 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
     574               0 :     y1 = y2 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
     575               0 :     for (PRInt32 i = 2; i < mNumCoords; i += 2) {
     576               0 :       xtmp = nsPresContext::CSSPixelsToAppUnits(mCoords[i]);
     577               0 :       ytmp = nsPresContext::CSSPixelsToAppUnits(mCoords[i+1]);
     578               0 :       x1 = x1 < xtmp ? x1 : xtmp;
     579               0 :       y1 = y1 < ytmp ? y1 : ytmp;
     580               0 :       x2 = x2 > xtmp ? x2 : xtmp;
     581               0 :       y2 = y2 > ytmp ? y2 : ytmp;
     582                 :     }
     583                 : 
     584               0 :     aRect.SetRect(x1, y1, x2, y2);
     585                 :   }
     586               0 : }
     587                 : 
     588                 : //----------------------------------------------------------------------
     589                 : 
     590               0 : class CircleArea : public Area {
     591                 : public:
     592                 :   CircleArea(nsIContent* aArea);
     593                 : 
     594                 :   virtual void ParseCoords(const nsAString& aSpec);
     595                 :   virtual bool IsInside(nscoord x, nscoord y) const;
     596                 :   virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC);
     597                 :   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect);
     598                 : };
     599                 : 
     600               0 : CircleArea::CircleArea(nsIContent* aArea)
     601               0 :   : Area(aArea)
     602                 : {
     603               0 : }
     604                 : 
     605               0 : void CircleArea::ParseCoords(const nsAString& aSpec)
     606                 : {
     607               0 :   Area::ParseCoords(aSpec);
     608                 : 
     609               0 :   bool wrongNumberOfCoords = false;
     610               0 :   PRInt32 flag = nsIScriptError::warningFlag;
     611               0 :   if (mNumCoords >= 3) {
     612               0 :     if (mCoords[2] < 0) {
     613                 :       logMessage(mArea,
     614                 :                  aSpec,
     615                 :                  nsIScriptError::errorFlag,
     616               0 :                  "ImageMapCircleNegativeRadius");
     617                 :     }
     618                 : 
     619               0 :     if (mNumCoords > 3) {
     620               0 :       wrongNumberOfCoords = true;
     621                 :     }
     622                 :   } else {
     623               0 :     wrongNumberOfCoords = true;
     624               0 :     flag = nsIScriptError::errorFlag;
     625                 :   }
     626                 : 
     627               0 :   if (wrongNumberOfCoords) {
     628                 :     logMessage(mArea,
     629                 :                aSpec,
     630                 :                flag,
     631               0 :                "ImageMapCircleWrongNumberOfCoords");
     632                 :   }
     633               0 : }
     634                 : 
     635               0 : bool CircleArea::IsInside(nscoord x, nscoord y) const
     636                 : {
     637                 :   // Note: > is for nav compatibility
     638               0 :   if (mNumCoords >= 3) {
     639               0 :     nscoord x1 = mCoords[0];
     640               0 :     nscoord y1 = mCoords[1];
     641               0 :     nscoord radius = mCoords[2];
     642               0 :     if (radius < 0) {
     643               0 :       return false;
     644                 :     }
     645               0 :     nscoord dx = x1 - x;
     646               0 :     nscoord dy = y1 - y;
     647               0 :     nscoord dist = (dx * dx) + (dy * dy);
     648               0 :     if (dist <= (radius * radius)) {
     649               0 :       return true;
     650                 :     }
     651                 :   }
     652               0 :   return false;
     653                 : }
     654                 : 
     655               0 : void CircleArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
     656                 : {
     657               0 :   if (mHasFocus) {
     658               0 :     if (mNumCoords >= 3) {
     659               0 :       nscoord x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
     660               0 :       nscoord y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
     661               0 :       nscoord radius = nsPresContext::CSSPixelsToAppUnits(mCoords[2]);
     662               0 :       if (radius < 0) {
     663               0 :         return;
     664                 :       }
     665               0 :       nscoord x = x1 - radius;
     666               0 :       nscoord y = y1 - radius;
     667               0 :       nscoord w = 2 * radius;
     668               0 :       aRC.DrawEllipse(x, y, w, w);
     669                 :     }
     670                 :   }
     671                 : }
     672                 : 
     673               0 : void CircleArea::GetRect(nsIFrame* aFrame, nsRect& aRect)
     674                 : {
     675               0 :   if (mNumCoords >= 3) {
     676               0 :     nscoord x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
     677               0 :     nscoord y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
     678               0 :     nscoord radius = nsPresContext::CSSPixelsToAppUnits(mCoords[2]);
     679               0 :     if (radius < 0) {
     680               0 :       return;
     681                 :     }
     682                 : 
     683               0 :     aRect.SetRect(x1 - radius, y1 - radius, x1 + radius, y1 + radius);
     684                 :   }
     685                 : }
     686                 : 
     687                 : //----------------------------------------------------------------------
     688                 : 
     689                 : 
     690               0 : nsImageMap::nsImageMap() :
     691                 :   mImageFrame(nsnull),
     692               0 :   mContainsBlockContents(false)
     693                 : {
     694               0 : }
     695                 : 
     696               0 : nsImageMap::~nsImageMap()
     697                 : {
     698               0 :   NS_ASSERTION(mAreas.Length() == 0, "Destroy was not called");
     699               0 : }
     700                 : 
     701               0 : NS_IMPL_ISUPPORTS2(nsImageMap,
     702                 :                    nsIMutationObserver,
     703                 :                    nsIDOMEventListener)
     704                 : 
     705                 : nsresult
     706               0 : nsImageMap::GetBoundsForAreaContent(nsIContent *aContent,
     707                 :                                     nsRect& aBounds)
     708                 : {
     709               0 :   NS_ENSURE_TRUE(aContent && mImageFrame, NS_ERROR_INVALID_ARG);
     710                 : 
     711                 :   // Find the Area struct associated with this content node, and return bounds
     712               0 :   PRUint32 i, n = mAreas.Length();
     713               0 :   for (i = 0; i < n; i++) {
     714               0 :     Area* area = mAreas.ElementAt(i);
     715               0 :     if (area->mArea == aContent) {
     716               0 :       aBounds = nsRect();
     717               0 :       area->GetRect(mImageFrame, aBounds);
     718               0 :       return NS_OK;
     719                 :     }
     720                 :   }
     721               0 :   return NS_ERROR_FAILURE;
     722                 : }
     723                 : 
     724                 : void
     725               0 : nsImageMap::FreeAreas()
     726                 : {
     727               0 :   PRUint32 i, n = mAreas.Length();
     728               0 :   for (i = 0; i < n; i++) {
     729               0 :     Area* area = mAreas.ElementAt(i);
     730               0 :     NS_ASSERTION(area->mArea->GetPrimaryFrame() == mImageFrame,
     731                 :                  "Unexpected primary frame");
     732               0 :     area->mArea->SetPrimaryFrame(nsnull);
     733                 : 
     734               0 :     area->mArea->RemoveSystemEventListener(NS_LITERAL_STRING("focus"), this,
     735               0 :                                            false);
     736               0 :     area->mArea->RemoveSystemEventListener(NS_LITERAL_STRING("blur"), this,
     737               0 :                                            false);
     738               0 :     delete area;
     739                 :   }
     740               0 :   mAreas.Clear();
     741               0 : }
     742                 : 
     743                 : nsresult
     744               0 : nsImageMap::Init(nsImageFrame* aImageFrame, nsIContent* aMap)
     745                 : {
     746               0 :   NS_PRECONDITION(aMap, "null ptr");
     747               0 :   if (!aMap) {
     748               0 :     return NS_ERROR_NULL_POINTER;
     749                 :   }
     750               0 :   mImageFrame = aImageFrame;
     751                 : 
     752               0 :   mMap = aMap;
     753               0 :   mMap->AddMutationObserver(this);
     754                 : 
     755                 :   // "Compile" the areas in the map into faster access versions
     756               0 :   return UpdateAreas();
     757                 : }
     758                 : 
     759                 : 
     760                 : nsresult
     761               0 : nsImageMap::SearchForAreas(nsIContent* aParent, bool& aFoundArea,
     762                 :                            bool& aFoundAnchor)
     763                 : {
     764               0 :   nsresult rv = NS_OK;
     765               0 :   PRUint32 i, n = aParent->GetChildCount();
     766                 : 
     767                 :   // Look for <area> or <a> elements. We'll use whichever type we find first.
     768               0 :   for (i = 0; i < n; i++) {
     769               0 :     nsIContent *child = aParent->GetChildAt(i);
     770                 : 
     771               0 :     if (child->IsHTML()) {
     772                 :       // If we haven't determined that the map element contains an
     773                 :       // <a> element yet, then look for <area>.
     774               0 :       if (!aFoundAnchor && child->Tag() == nsGkAtoms::area) {
     775               0 :         aFoundArea = true;
     776               0 :         rv = AddArea(child);
     777               0 :         NS_ENSURE_SUCCESS(rv, rv);
     778                 : 
     779                 :         // Continue to next child. This stops mContainsBlockContents from
     780                 :         // getting set. It also makes us ignore children of <area>s which
     781                 :         // is consistent with how we react to dynamic insertion of such
     782                 :         // children.
     783               0 :         continue;
     784                 :       }
     785                 :       // If we haven't determined that the map element contains an
     786                 :       // <area> element yet, then look for <a>.
     787               0 :       if (!aFoundArea && child->Tag() == nsGkAtoms::a) {
     788               0 :         aFoundAnchor = true;
     789               0 :         rv = AddArea(child);
     790               0 :         NS_ENSURE_SUCCESS(rv, rv);
     791                 :       }
     792                 :     }
     793                 : 
     794               0 :     if (child->IsElement()) {
     795               0 :       mContainsBlockContents = true;
     796               0 :       rv = SearchForAreas(child, aFoundArea, aFoundAnchor);
     797               0 :       NS_ENSURE_SUCCESS(rv, rv);
     798                 :     }
     799                 :   }
     800                 : 
     801               0 :   return NS_OK;
     802                 : }
     803                 : 
     804                 : nsresult
     805               0 : nsImageMap::UpdateAreas()
     806                 : {
     807                 :   // Get rid of old area data
     808               0 :   FreeAreas();
     809                 : 
     810               0 :   bool foundArea = false;
     811               0 :   bool foundAnchor = false;
     812               0 :   mContainsBlockContents = false;
     813                 : 
     814               0 :   return SearchForAreas(mMap, foundArea, foundAnchor);
     815                 : }
     816                 : 
     817                 : nsresult
     818               0 : nsImageMap::AddArea(nsIContent* aArea)
     819                 : {
     820                 :   static nsIContent::AttrValuesArray strings[] =
     821                 :     {&nsGkAtoms::rect, &nsGkAtoms::rectangle,
     822                 :      &nsGkAtoms::circle, &nsGkAtoms::circ,
     823                 :      &nsGkAtoms::_default,
     824                 :      &nsGkAtoms::poly, &nsGkAtoms::polygon,
     825                 :      nsnull};
     826                 : 
     827                 :   Area* area;
     828               0 :   switch (aArea->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::shape,
     829               0 :                                  strings, eIgnoreCase)) {
     830                 :   case nsIContent::ATTR_VALUE_NO_MATCH:
     831                 :   case nsIContent::ATTR_MISSING:
     832                 :   case 0:
     833                 :   case 1:
     834               0 :     area = new RectArea(aArea);
     835               0 :     break;
     836                 :   case 2:
     837                 :   case 3:
     838               0 :     area = new CircleArea(aArea);
     839               0 :     break;
     840                 :   case 4:
     841               0 :     area = new DefaultArea(aArea);
     842               0 :     break;
     843                 :   case 5:
     844                 :   case 6:
     845               0 :     area = new PolyArea(aArea);
     846               0 :     break;
     847                 :   default:
     848               0 :     NS_NOTREACHED("FindAttrValueIn returned an unexpected value.");
     849               0 :     break;
     850                 :   }
     851               0 :   if (!area)
     852               0 :     return NS_ERROR_OUT_OF_MEMORY;
     853                 : 
     854                 :   //Add focus listener to track area focus changes
     855               0 :   aArea->AddSystemEventListener(NS_LITERAL_STRING("focus"), this, false,
     856               0 :                                 false);
     857               0 :   aArea->AddSystemEventListener(NS_LITERAL_STRING("blur"), this, false,
     858               0 :                                 false);
     859                 : 
     860                 :   // This is a nasty hack.  It needs to go away: see bug 135040.  Once this is
     861                 :   // removed, the code added to nsCSSFrameConstructor::RestyleElement,
     862                 :   // nsCSSFrameConstructor::ContentRemoved (both hacks there), and
     863                 :   // nsCSSFrameConstructor::ProcessRestyledFrames to work around this issue can
     864                 :   // be removed.
     865               0 :   aArea->SetPrimaryFrame(mImageFrame);
     866                 : 
     867               0 :   nsAutoString coords;
     868               0 :   aArea->GetAttr(kNameSpaceID_None, nsGkAtoms::coords, coords);
     869               0 :   area->ParseCoords(coords);
     870               0 :   mAreas.AppendElement(area);
     871               0 :   return NS_OK;
     872                 : }
     873                 : 
     874                 : nsIContent*
     875               0 : nsImageMap::GetArea(nscoord aX, nscoord aY) const
     876                 : {
     877               0 :   NS_ASSERTION(mMap, "Not initialized");
     878               0 :   PRUint32 i, n = mAreas.Length();
     879               0 :   for (i = 0; i < n; i++) {
     880               0 :     Area* area = mAreas.ElementAt(i);
     881               0 :     if (area->IsInside(aX, aY)) {
     882               0 :       return area->mArea;
     883                 :     }
     884                 :   }
     885                 : 
     886               0 :   return nsnull;
     887                 : }
     888                 : 
     889                 : void
     890               0 : nsImageMap::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
     891                 : {
     892               0 :   PRUint32 i, n = mAreas.Length();
     893               0 :   for (i = 0; i < n; i++) {
     894               0 :     Area* area = mAreas.ElementAt(i);
     895               0 :     area->Draw(aFrame, aRC);
     896                 :   }
     897               0 : }
     898                 : 
     899                 : void
     900               0 : nsImageMap::MaybeUpdateAreas(nsIContent *aContent)
     901                 : {
     902               0 :   if (aContent == mMap || mContainsBlockContents) {
     903               0 :     UpdateAreas();
     904                 :   }
     905               0 : }
     906                 : 
     907                 : void
     908               0 : nsImageMap::AttributeChanged(nsIDocument*  aDocument,
     909                 :                              dom::Element* aElement,
     910                 :                              PRInt32       aNameSpaceID,
     911                 :                              nsIAtom*      aAttribute,
     912                 :                              PRInt32       aModType)
     913                 : {
     914                 :   // If the parent of the changing content node is our map then update
     915                 :   // the map.  But only do this if the node is an HTML <area> or <a>
     916                 :   // and the attribute that's changing is "shape" or "coords" -- those
     917                 :   // are the only cases we care about.
     918               0 :   if ((aElement->NodeInfo()->Equals(nsGkAtoms::area) ||
     919               0 :        aElement->NodeInfo()->Equals(nsGkAtoms::a)) &&
     920               0 :       aElement->IsHTML() &&
     921                 :       aNameSpaceID == kNameSpaceID_None &&
     922                 :       (aAttribute == nsGkAtoms::shape ||
     923                 :        aAttribute == nsGkAtoms::coords)) {
     924               0 :     MaybeUpdateAreas(aElement->GetParent());
     925               0 :   } else if (aElement == mMap &&
     926                 :              aNameSpaceID == kNameSpaceID_None &&
     927                 :              (aAttribute == nsGkAtoms::name ||
     928                 :               aAttribute == nsGkAtoms::id) &&
     929                 :              mImageFrame) {
     930                 :     // ID or name has changed. Let ImageFrame recreate ImageMap.
     931               0 :     mImageFrame->DisconnectMap();
     932                 :   }
     933               0 : }
     934                 : 
     935                 : void
     936               0 : nsImageMap::ContentAppended(nsIDocument *aDocument,
     937                 :                             nsIContent* aContainer,
     938                 :                             nsIContent* aFirstNewContent,
     939                 :                             PRInt32     /* unused */)
     940                 : {
     941               0 :   MaybeUpdateAreas(aContainer);
     942               0 : }
     943                 : 
     944                 : void
     945               0 : nsImageMap::ContentInserted(nsIDocument *aDocument,
     946                 :                             nsIContent* aContainer,
     947                 :                             nsIContent* aChild,
     948                 :                             PRInt32 /* unused */)
     949                 : {
     950               0 :   MaybeUpdateAreas(aContainer);
     951               0 : }
     952                 : 
     953                 : void
     954               0 : nsImageMap::ContentRemoved(nsIDocument *aDocument,
     955                 :                            nsIContent* aContainer,
     956                 :                            nsIContent* aChild,
     957                 :                            PRInt32 aIndexInContainer,
     958                 :                            nsIContent* aPreviousSibling)
     959                 : {
     960               0 :   MaybeUpdateAreas(aContainer);
     961               0 : }
     962                 : 
     963                 : void
     964               0 : nsImageMap::ParentChainChanged(nsIContent* aContent)
     965                 : {
     966               0 :   NS_ASSERTION(aContent == mMap,
     967                 :                "Unexpected ParentChainChanged notification!");
     968               0 :   if (mImageFrame) {
     969               0 :     mImageFrame->DisconnectMap();
     970                 :   }
     971               0 : }
     972                 : 
     973                 : nsresult
     974               0 : nsImageMap::HandleEvent(nsIDOMEvent* aEvent)
     975                 : {
     976               0 :   nsAutoString eventType;
     977               0 :   aEvent->GetType(eventType);
     978               0 :   bool focus = eventType.EqualsLiteral("focus");
     979               0 :   NS_ABORT_IF_FALSE(focus == !eventType.EqualsLiteral("blur"),
     980                 :                     "Unexpected event type");
     981                 : 
     982                 :   //Set which one of our areas changed focus
     983               0 :   nsCOMPtr<nsIDOMEventTarget> target;
     984               0 :   if (NS_SUCCEEDED(aEvent->GetTarget(getter_AddRefs(target))) && target) {
     985               0 :     nsCOMPtr<nsIContent> targetContent(do_QueryInterface(target));
     986               0 :     if (targetContent) {
     987               0 :       PRUint32 i, n = mAreas.Length();
     988               0 :       for (i = 0; i < n; i++) {
     989               0 :         Area* area = mAreas.ElementAt(i);
     990               0 :         if (area->mArea == targetContent) {
     991                 :           //Set or Remove internal focus
     992               0 :           area->HasFocus(focus);
     993                 :           //Now invalidate the rect
     994               0 :           if (mImageFrame) {
     995               0 :             nsRect dmgRect;
     996               0 :             area->GetRect(mImageFrame, dmgRect);
     997               0 :             mImageFrame->Invalidate(dmgRect);
     998                 :           }
     999               0 :           break;
    1000                 :         }
    1001                 :       }
    1002                 :     }
    1003                 :   }
    1004               0 :   return NS_OK;
    1005                 : }
    1006                 : 
    1007                 : void
    1008               0 : nsImageMap::Destroy(void)
    1009                 : {
    1010               0 :   FreeAreas();
    1011               0 :   mImageFrame = nsnull;
    1012               0 :   mMap->RemoveMutationObserver(this);
    1013               0 : }

Generated by: LCOV version 1.7