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
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/
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
15 * The Original Code is mozilla.org code.
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.
23 * Mats Palmgren <mats.palmgren@bredband.net>
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.
37 * ***** END LICENSE BLOCK ***** */
39 /* code for HTML client-side image maps */
41 #include "nsImageMap.h"
43 #include "nsReadableUtils.h"
44 #include "nsIRenderingContext.h"
45 #include "nsPresContext.h"
48 #include "nsIServiceManager.h"
49 #include "nsNetUtil.h"
50 #include "nsTextFragment.h"
51 #include "mozilla/dom/Element.h"
52 #include "nsIDOMHTMLElement.h"
53 #include "nsIDOMHTMLMapElement.h"
54 #include "nsIDOMHTMLAreaElement.h"
55 #include "nsIDOMHTMLAnchorElement.h"
56 #include "nsIDOMHTMLCollection.h"
57 #include "nsIDocument.h"
58 #include "nsINameSpaceManager.h"
59 #include "nsGkAtoms.h"
60 #include "nsIDOMEventTarget.h"
61 #include "nsIPresShell.h"
64 #include "nsIImageMap.h"
65 #include "nsIConsoleService.h"
66 #include "nsIScriptError.h"
67 #include "nsIStringBundle.h"
68 #include "nsIDocument.h"
69 #include "nsContentUtils.h"
71 namespace dom
= mozilla::dom
;
73 static NS_DEFINE_CID(kCStringBundleServiceCID
, NS_STRINGBUNDLESERVICE_CID
);
77 Area(nsIContent
* aArea
);
80 virtual void ParseCoords(const nsAString
& aSpec
);
82 virtual PRBool
IsInside(nscoord x
, nscoord y
) const = 0;
83 virtual void Draw(nsIFrame
* aFrame
, nsIRenderingContext
& aRC
) = 0;
84 virtual void GetRect(nsIFrame
* aFrame
, nsRect
& aRect
) = 0;
86 void HasFocus(PRBool aHasFocus
);
88 nsCOMPtr
<nsIContent
> mArea
;
91 PRPackedBool mHasFocus
;
94 Area::Area(nsIContent
* aArea
)
98 NS_PRECONDITION(mArea
, "How did that happen?");
101 mHasFocus
= PR_FALSE
;
106 MOZ_COUNT_DTOR(Area
);
123 static void logMessage(nsIContent
* aContent
,
124 const nsAString
& aCoordsSpec
,
126 const char* aMessageName
) {
127 nsIDocument
* doc
= aContent
->GetOwnerDoc();
129 nsContentUtils::ReportToConsole(
130 nsContentUtils::eLAYOUT_PROPERTIES
,
133 0, /* params length */
135 PromiseFlatString(NS_LITERAL_STRING("coords=\"") +
137 NS_LITERAL_STRING("\"")), /* source line */
139 0, /* column number */
144 void Area::ParseCoords(const nsAString
& aSpec
)
146 char* cp
= ToNewCString(aSpec
);
154 * Nothing in an empty list
164 * Skip beginning whitespace, all whitespace is empty list.
167 while (is_space(*n_str
))
177 * Make a pass where any two numbers separated by just whitespace
178 * are given a comma separator. Count entries while passing.
181 while (*n_str
!= '\0')
186 * Skip to a separator
189 while (!is_space(*tptr
) && *tptr
!= ',' && *tptr
!= '\0')
196 * If no more entries, break out here
204 * Skip to the end of the separator, noting if we have a
207 has_comma
= PR_FALSE
;
208 while (is_space(*tptr
) || *tptr
== ',')
224 * If this was trailing whitespace we skipped, we are done.
226 if ((*tptr
== '\0') && !has_comma
)
231 * Else if the separator is all whitespace, and this is not the
232 * end of the string, add a comma to the separator.
240 * count the entry skipped.
247 * count the last entry in the list.
252 * Allocate space for the coordinate array.
254 value_list
= new nscoord
[cnt
];
261 * Second pass to copy integer values into list.
264 for (i
=0; i
<cnt
; i
++)
268 ptr
= strchr(tptr
, ',');
274 * Strip whitespace in front of number because I don't
275 * trust atoi to do it on all platforms.
277 while (is_space(*tptr
))
287 value_list
[i
] = (nscoord
) ::atoi(tptr
);
297 mCoords
= value_list
;
303 void Area::HasFocus(PRBool aHasFocus
)
305 mHasFocus
= aHasFocus
;
308 //----------------------------------------------------------------------
310 class DefaultArea
: public Area
{
312 DefaultArea(nsIContent
* aArea
);
314 virtual PRBool
IsInside(nscoord x
, nscoord y
) const;
315 virtual void Draw(nsIFrame
* aFrame
, nsIRenderingContext
& aRC
);
316 virtual void GetRect(nsIFrame
* aFrame
, nsRect
& aRect
);
319 DefaultArea::DefaultArea(nsIContent
* aArea
)
324 PRBool
DefaultArea::IsInside(nscoord x
, nscoord y
) const
329 void DefaultArea::Draw(nsIFrame
* aFrame
, nsIRenderingContext
& aRC
)
332 nsRect r
= aFrame
->GetRect();
336 const nscoord kOnePixel
= nsPresContext::CSSPixelsToAppUnits(1);
337 nscoord x2
= r
.XMost() - kOnePixel
;
338 nscoord y2
= r
.YMost() - kOnePixel
;
339 // XXX aRC.DrawRect(r) result is ugly, that's why we use DrawLine.
340 aRC
.DrawLine(x1
, y1
, x1
, y2
);
341 aRC
.DrawLine(x1
, y2
, x2
, y2
);
342 aRC
.DrawLine(x1
, y1
, x2
, y1
);
343 aRC
.DrawLine(x2
, y1
, x2
, y2
);
347 void DefaultArea::GetRect(nsIFrame
* aFrame
, nsRect
& aRect
)
349 aRect
= aFrame
->GetRect();
353 //----------------------------------------------------------------------
355 class RectArea
: public Area
{
357 RectArea(nsIContent
* aArea
);
359 virtual void ParseCoords(const nsAString
& aSpec
);
360 virtual PRBool
IsInside(nscoord x
, nscoord y
) const;
361 virtual void Draw(nsIFrame
* aFrame
, nsIRenderingContext
& aRC
);
362 virtual void GetRect(nsIFrame
* aFrame
, nsRect
& aRect
);
365 RectArea::RectArea(nsIContent
* aArea
)
370 void RectArea::ParseCoords(const nsAString
& aSpec
)
372 Area::ParseCoords(aSpec
);
374 PRBool saneRect
= PR_TRUE
;
375 PRInt32 flag
= nsIScriptError::warningFlag
;
376 if (mNumCoords
>= 4) {
377 if (mCoords
[0] > mCoords
[2]) {
378 // x-coords in reversed order
379 nscoord x
= mCoords
[2];
380 mCoords
[2] = mCoords
[0];
385 if (mCoords
[1] > mCoords
[3]) {
386 // y-coords in reversed order
387 nscoord y
= mCoords
[3];
388 mCoords
[3] = mCoords
[1];
393 if (mNumCoords
> 4) {
394 // Someone missed the concept of a rect here
399 flag
= nsIScriptError::errorFlag
;
403 logMessage(mArea
, aSpec
, flag
, "ImageMapRectBoundsError");
407 PRBool
RectArea::IsInside(nscoord x
, nscoord y
) const
409 if (mNumCoords
>= 4) { // Note: > is for nav compatability
410 nscoord x1
= mCoords
[0];
411 nscoord y1
= mCoords
[1];
412 nscoord x2
= mCoords
[2];
413 nscoord y2
= mCoords
[3];
414 NS_ASSERTION(x1
<= x2
&& y1
<= y2
,
415 "Someone screwed up RectArea::ParseCoords");
416 if ((x
>= x1
) && (x
<= x2
) && (y
>= y1
) && (y
<= y2
)) {
423 void RectArea::Draw(nsIFrame
* aFrame
, nsIRenderingContext
& aRC
)
426 if (mNumCoords
>= 4) {
427 nscoord x1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
428 nscoord y1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
429 nscoord x2
= nsPresContext::CSSPixelsToAppUnits(mCoords
[2]);
430 nscoord y2
= nsPresContext::CSSPixelsToAppUnits(mCoords
[3]);
431 NS_ASSERTION(x1
<= x2
&& y1
<= y2
,
432 "Someone screwed up RectArea::ParseCoords");
433 aRC
.DrawLine(x1
, y1
, x1
, y2
);
434 aRC
.DrawLine(x1
, y2
, x2
, y2
);
435 aRC
.DrawLine(x1
, y1
, x2
, y1
);
436 aRC
.DrawLine(x2
, y1
, x2
, y2
);
441 void RectArea::GetRect(nsIFrame
* aFrame
, nsRect
& aRect
)
443 if (mNumCoords
>= 4) {
444 nscoord x1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
445 nscoord y1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
446 nscoord x2
= nsPresContext::CSSPixelsToAppUnits(mCoords
[2]);
447 nscoord y2
= nsPresContext::CSSPixelsToAppUnits(mCoords
[3]);
448 NS_ASSERTION(x1
<= x2
&& y1
<= y2
,
449 "Someone screwed up RectArea::ParseCoords");
451 aRect
.SetRect(x1
, y1
, x2
, y2
);
455 //----------------------------------------------------------------------
457 class PolyArea
: public Area
{
459 PolyArea(nsIContent
* aArea
);
461 virtual void ParseCoords(const nsAString
& aSpec
);
462 virtual PRBool
IsInside(nscoord x
, nscoord y
) const;
463 virtual void Draw(nsIFrame
* aFrame
, nsIRenderingContext
& aRC
);
464 virtual void GetRect(nsIFrame
* aFrame
, nsRect
& aRect
);
467 PolyArea::PolyArea(nsIContent
* aArea
)
472 void PolyArea::ParseCoords(const nsAString
& aSpec
)
474 Area::ParseCoords(aSpec
);
476 if (mNumCoords
>= 2) {
477 if (mNumCoords
& 1U) {
480 nsIScriptError::warningFlag
,
481 "ImageMapPolyOddNumberOfCoords");
486 nsIScriptError::errorFlag
,
487 "ImageMapPolyWrongNumberOfCoords");
491 PRBool
PolyArea::IsInside(nscoord x
, nscoord y
) const
493 if (mNumCoords
>= 6) {
494 PRInt32 intersects
= 0;
497 PRInt32 totalv
= mNumCoords
/ 2;
498 PRInt32 totalc
= totalv
* 2;
499 nscoord xval
= mCoords
[totalc
- 2];
500 nscoord yval
= mCoords
[totalc
- 1];
501 PRInt32 end
= totalc
;
504 if ((yval
>= wherey
) != (mCoords
[pointer
] >= wherey
)) {
505 if ((xval
>= wherex
) == (mCoords
[0] >= wherex
)) {
506 intersects
+= (xval
>= wherex
) ? 1 : 0;
508 intersects
+= ((xval
- (yval
- wherey
) *
509 (mCoords
[0] - xval
) /
510 (mCoords
[pointer
] - yval
)) >= wherex
) ? 1 : 0;
514 // XXX I wonder what this is doing; this is a translation of ptinpoly.c
515 while (pointer
< end
) {
516 yval
= mCoords
[pointer
];
518 if (yval
>= wherey
) {
519 while((pointer
< end
) && (mCoords
[pointer
] >= wherey
))
523 if ((mCoords
[pointer
-3] >= wherex
) ==
524 (mCoords
[pointer
-1] >= wherex
)) {
525 intersects
+= (mCoords
[pointer
-3] >= wherex
) ? 1 : 0;
528 ((mCoords
[pointer
-3] - (mCoords
[pointer
-2] - wherey
) *
529 (mCoords
[pointer
-1] - mCoords
[pointer
-3]) /
530 (mCoords
[pointer
] - mCoords
[pointer
- 2])) >= wherex
) ? 1:0;
533 while((pointer
< end
) && (mCoords
[pointer
] < wherey
))
537 if ((mCoords
[pointer
-3] >= wherex
) ==
538 (mCoords
[pointer
-1] >= wherex
)) {
539 intersects
+= (mCoords
[pointer
-3] >= wherex
) ? 1:0;
542 ((mCoords
[pointer
-3] - (mCoords
[pointer
-2] - wherey
) *
543 (mCoords
[pointer
-1] - mCoords
[pointer
-3]) /
544 (mCoords
[pointer
] - mCoords
[pointer
- 2])) >= wherex
) ? 1:0;
548 if ((intersects
& 1) != 0) {
555 void PolyArea::Draw(nsIFrame
* aFrame
, nsIRenderingContext
& aRC
)
558 if (mNumCoords
>= 6) {
559 nscoord x0
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
560 nscoord y0
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
562 for (PRInt32 i
= 2; i
< mNumCoords
; i
+= 2) {
563 x1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[i
]);
564 y1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[i
+1]);
565 aRC
.DrawLine(x0
, y0
, x1
, y1
);
569 x1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
570 y1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
571 aRC
.DrawLine(x0
, y0
, x1
, y1
);
576 void PolyArea::GetRect(nsIFrame
* aFrame
, nsRect
& aRect
)
578 if (mNumCoords
>= 6) {
579 nscoord x1
, x2
, y1
, y2
, xtmp
, ytmp
;
580 x1
= x2
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
581 y1
= y2
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
582 for (PRInt32 i
= 2; i
< mNumCoords
; i
+= 2) {
583 xtmp
= nsPresContext::CSSPixelsToAppUnits(mCoords
[i
]);
584 ytmp
= nsPresContext::CSSPixelsToAppUnits(mCoords
[i
+1]);
585 x1
= x1
< xtmp
? x1
: xtmp
;
586 y1
= y1
< ytmp
? y1
: ytmp
;
587 x2
= x2
> xtmp
? x2
: xtmp
;
588 y2
= y2
> ytmp
? y2
: ytmp
;
591 aRect
.SetRect(x1
, y1
, x2
, y2
);
595 //----------------------------------------------------------------------
597 class CircleArea
: public Area
{
599 CircleArea(nsIContent
* aArea
);
601 virtual void ParseCoords(const nsAString
& aSpec
);
602 virtual PRBool
IsInside(nscoord x
, nscoord y
) const;
603 virtual void Draw(nsIFrame
* aFrame
, nsIRenderingContext
& aRC
);
604 virtual void GetRect(nsIFrame
* aFrame
, nsRect
& aRect
);
607 CircleArea::CircleArea(nsIContent
* aArea
)
612 void CircleArea::ParseCoords(const nsAString
& aSpec
)
614 Area::ParseCoords(aSpec
);
616 PRBool wrongNumberOfCoords
= PR_FALSE
;
617 PRInt32 flag
= nsIScriptError::warningFlag
;
618 if (mNumCoords
>= 3) {
619 if (mCoords
[2] < 0) {
622 nsIScriptError::errorFlag
,
623 "ImageMapCircleNegativeRadius");
626 if (mNumCoords
> 3) {
627 wrongNumberOfCoords
= PR_TRUE
;
630 wrongNumberOfCoords
= PR_TRUE
;
631 flag
= nsIScriptError::errorFlag
;
634 if (wrongNumberOfCoords
) {
638 "ImageMapCircleWrongNumberOfCoords");
642 PRBool
CircleArea::IsInside(nscoord x
, nscoord y
) const
644 // Note: > is for nav compatability
645 if (mNumCoords
>= 3) {
646 nscoord x1
= mCoords
[0];
647 nscoord y1
= mCoords
[1];
648 nscoord radius
= mCoords
[2];
654 nscoord dist
= (dx
* dx
) + (dy
* dy
);
655 if (dist
<= (radius
* radius
)) {
662 void CircleArea::Draw(nsIFrame
* aFrame
, nsIRenderingContext
& aRC
)
665 if (mNumCoords
>= 3) {
666 nscoord x1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
667 nscoord y1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
668 nscoord radius
= nsPresContext::CSSPixelsToAppUnits(mCoords
[2]);
672 nscoord x
= x1
- radius
;
673 nscoord y
= y1
- radius
;
674 nscoord w
= 2 * radius
;
675 aRC
.DrawEllipse(x
, y
, w
, w
);
680 void CircleArea::GetRect(nsIFrame
* aFrame
, nsRect
& aRect
)
682 if (mNumCoords
>= 3) {
683 nscoord x1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
684 nscoord y1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
685 nscoord radius
= nsPresContext::CSSPixelsToAppUnits(mCoords
[2]);
690 aRect
.SetRect(x1
- radius
, y1
- radius
, x1
+ radius
, y1
+ radius
);
694 //----------------------------------------------------------------------
697 nsImageMap::nsImageMap() :
700 mContainsBlockContents(PR_FALSE
)
704 nsImageMap::~nsImageMap()
706 NS_ASSERTION(mAreas
.Length() == 0, "Destroy was not called");
709 NS_IMPL_ISUPPORTS4(nsImageMap
,
716 nsImageMap::GetBoundsForAreaContent(nsIContent
*aContent
,
719 NS_ENSURE_TRUE(aContent
, NS_ERROR_INVALID_ARG
);
721 // Find the Area struct associated with this content node, and return bounds
722 PRUint32 i
, n
= mAreas
.Length();
723 for (i
= 0; i
< n
; i
++) {
724 Area
* area
= mAreas
.ElementAt(i
);
725 if (area
->mArea
== aContent
) {
727 nsIFrame
* frame
= aContent
->GetPrimaryFrame();
729 area
->GetRect(frame
, aBounds
);
734 return NS_ERROR_FAILURE
;
738 nsImageMap::FreeAreas()
740 PRUint32 i
, n
= mAreas
.Length();
741 for (i
= 0; i
< n
; i
++) {
742 Area
* area
= mAreas
.ElementAt(i
);
743 NS_ASSERTION(area
->mArea
->GetPrimaryFrame() == mImageFrame
,
744 "Unexpected primary frame");
745 area
->mArea
->SetPrimaryFrame(nsnull
);
747 area
->mArea
->RemoveEventListenerByIID(this, NS_GET_IID(nsIDOMFocusListener
));
754 nsImageMap::Init(nsIPresShell
* aPresShell
, nsIFrame
* aImageFrame
, nsIDOMHTMLMapElement
* aMap
)
756 NS_PRECONDITION(nsnull
!= aMap
, "null ptr");
757 if (nsnull
== aMap
) {
758 return NS_ERROR_NULL_POINTER
;
760 mPresShell
= aPresShell
;
761 mImageFrame
= aImageFrame
;
763 mMap
= do_QueryInterface(aMap
);
764 NS_ASSERTION(mMap
, "aMap is not an nsIContent!");
765 mMap
->AddMutationObserver(this);
767 // "Compile" the areas in the map into faster access versions
768 return UpdateAreas();
773 nsImageMap::SearchForAreas(nsIContent
* aParent
, PRBool
& aFoundArea
,
774 PRBool
& aFoundAnchor
)
777 PRUint32 i
, n
= aParent
->GetChildCount();
779 // Look for <area> or <a> elements. We'll use whichever type we find first.
780 for (i
= 0; i
< n
; i
++) {
781 nsIContent
*child
= aParent
->GetChildAt(i
);
783 if (child
->IsHTML()) {
784 // If we haven't determined that the map element contains an
785 // <a> element yet, then look for <area>.
786 if (!aFoundAnchor
&& child
->Tag() == nsGkAtoms::area
) {
787 aFoundArea
= PR_TRUE
;
789 NS_ENSURE_SUCCESS(rv
, rv
);
791 // Continue to next child. This stops mContainsBlockContents from
792 // getting set. It also makes us ignore children of <area>s which
793 // is consistent with how we react to dynamic insertion of such
797 // If we haven't determined that the map element contains an
798 // <area> element yet, then look for <a>.
799 if (!aFoundArea
&& child
->Tag() == nsGkAtoms::a
) {
800 aFoundAnchor
= PR_TRUE
;
802 NS_ENSURE_SUCCESS(rv
, rv
);
806 if (child
->IsElement()) {
807 mContainsBlockContents
= PR_TRUE
;
808 rv
= SearchForAreas(child
, aFoundArea
, aFoundAnchor
);
809 NS_ENSURE_SUCCESS(rv
, rv
);
817 nsImageMap::UpdateAreas()
819 // Get rid of old area data
822 PRBool foundArea
= PR_FALSE
;
823 PRBool foundAnchor
= PR_FALSE
;
824 mContainsBlockContents
= PR_FALSE
;
826 return SearchForAreas(mMap
, foundArea
, foundAnchor
);
830 nsImageMap::AddArea(nsIContent
* aArea
)
832 static nsIContent::AttrValuesArray strings
[] =
833 {&nsGkAtoms::rect
, &nsGkAtoms::rectangle
,
834 &nsGkAtoms::circle
, &nsGkAtoms::circ
,
835 &nsGkAtoms::_default
,
836 &nsGkAtoms::poly
, &nsGkAtoms::polygon
,
840 switch (aArea
->FindAttrValueIn(kNameSpaceID_None
, nsGkAtoms::shape
,
841 strings
, eIgnoreCase
)) {
842 case nsIContent::ATTR_VALUE_NO_MATCH
:
843 case nsIContent::ATTR_MISSING
:
846 area
= new RectArea(aArea
);
850 area
= new CircleArea(aArea
);
853 area
= new DefaultArea(aArea
);
857 area
= new PolyArea(aArea
);
860 NS_NOTREACHED("FindAttrValueIn returned an unexpected value.");
864 return NS_ERROR_OUT_OF_MEMORY
;
866 //Add focus listener to track area focus changes
867 aArea
->AddEventListenerByIID(this, NS_GET_IID(nsIDOMFocusListener
));
869 // This is a nasty hack. It needs to go away: see bug 135040. Once this is
870 // removed, the code added to nsCSSFrameConstructor::RestyleElement,
871 // nsCSSFrameConstructor::ContentRemoved (both hacks there), and
872 // nsCSSFrameConstructor::ProcessRestyledFrames to work around this issue can
874 aArea
->SetPrimaryFrame(mImageFrame
);
877 aArea
->GetAttr(kNameSpaceID_None
, nsGkAtoms::coords
, coords
);
878 area
->ParseCoords(coords
);
879 mAreas
.AppendElement(area
);
884 nsImageMap::IsInside(nscoord aX
, nscoord aY
,
885 nsIContent
** aContent
) const
887 NS_ASSERTION(mMap
, "Not initialized");
888 PRUint32 i
, n
= mAreas
.Length();
889 for (i
= 0; i
< n
; i
++) {
890 Area
* area
= mAreas
.ElementAt(i
);
891 if (area
->IsInside(aX
, aY
)) {
892 NS_ADDREF(*aContent
= area
->mArea
);
902 nsImageMap::Draw(nsIFrame
* aFrame
, nsIRenderingContext
& aRC
)
904 PRUint32 i
, n
= mAreas
.Length();
905 for (i
= 0; i
< n
; i
++) {
906 Area
* area
= mAreas
.ElementAt(i
);
907 area
->Draw(aFrame
, aRC
);
912 nsImageMap::MaybeUpdateAreas(nsIContent
*aContent
)
914 if (aContent
== mMap
|| mContainsBlockContents
) {
920 nsImageMap::AttributeChanged(nsIDocument
* aDocument
,
921 dom::Element
* aElement
,
922 PRInt32 aNameSpaceID
,
926 // If the parent of the changing content node is our map then update
927 // the map. But only do this if the node is an HTML <area> or <a>
928 // and the attribute that's changing is "shape" or "coords" -- those
929 // are the only cases we care about.
930 if ((aElement
->NodeInfo()->Equals(nsGkAtoms::area
) ||
931 aElement
->NodeInfo()->Equals(nsGkAtoms::a
)) &&
932 aElement
->IsHTML() &&
933 aNameSpaceID
== kNameSpaceID_None
&&
934 (aAttribute
== nsGkAtoms::shape
||
935 aAttribute
== nsGkAtoms::coords
)) {
936 MaybeUpdateAreas(aElement
->GetParent());
941 nsImageMap::ContentAppended(nsIDocument
*aDocument
,
942 nsIContent
* aContainer
,
943 nsIContent
* aFirstNewContent
,
944 PRInt32
/* unused */)
946 MaybeUpdateAreas(aContainer
);
950 nsImageMap::ContentInserted(nsIDocument
*aDocument
,
951 nsIContent
* aContainer
,
953 PRInt32
/* unused */)
955 MaybeUpdateAreas(aContainer
);
959 nsImageMap::ContentRemoved(nsIDocument
*aDocument
,
960 nsIContent
* aContainer
,
962 PRInt32 aIndexInContainer
,
963 nsIContent
* aPreviousSibling
)
965 MaybeUpdateAreas(aContainer
);
969 nsImageMap::Focus(nsIDOMEvent
* aEvent
)
971 return ChangeFocus(aEvent
, PR_TRUE
);
975 nsImageMap::Blur(nsIDOMEvent
* aEvent
)
977 return ChangeFocus(aEvent
, PR_FALSE
);
981 nsImageMap::ChangeFocus(nsIDOMEvent
* aEvent
, PRBool aFocus
)
983 //Set which one of our areas changed focus
984 nsCOMPtr
<nsIDOMEventTarget
> target
;
985 if (NS_SUCCEEDED(aEvent
->GetTarget(getter_AddRefs(target
))) && target
) {
986 nsCOMPtr
<nsIContent
> targetContent(do_QueryInterface(target
));
988 PRUint32 i
, n
= mAreas
.Length();
989 for (i
= 0; i
< n
; i
++) {
990 Area
* area
= mAreas
.ElementAt(i
);
991 if (area
->mArea
== targetContent
) {
992 //Set or Remove internal focus
993 area
->HasFocus(aFocus
);
994 //Now invalidate the rect
995 nsIFrame
* imgFrame
= targetContent
->GetPrimaryFrame();
998 area
->GetRect(imgFrame
, dmgRect
);
999 imgFrame
->Invalidate(dmgRect
);
1010 nsImageMap::HandleEvent(nsIDOMEvent
* aEvent
)
1016 nsImageMap::Destroy(void)
1019 mMap
->RemoveMutationObserver(this);