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 "nsIContent.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"
63 #include "nsFrameManager.h"
65 #include "nsIImageMap.h"
66 #include "nsIConsoleService.h"
67 #include "nsIScriptError.h"
68 #include "nsIStringBundle.h"
69 #include "nsIDocument.h"
70 #include "nsContentUtils.h"
72 static NS_DEFINE_CID(kCStringBundleServiceCID
, NS_STRINGBUNDLESERVICE_CID
);
76 Area(nsIContent
* aArea
);
79 virtual void ParseCoords(const nsAString
& aSpec
);
81 virtual PRBool
IsInside(nscoord x
, nscoord y
) const = 0;
82 virtual void Draw(nsPresContext
* aCX
,
83 nsIRenderingContext
& aRC
) = 0;
84 virtual void GetRect(nsPresContext
* aCX
, nsRect
& aRect
) = 0;
86 void HasFocus(PRBool aHasFocus
);
88 void GetHREF(nsAString
& aHref
) const;
89 void GetArea(nsIContent
** aArea
) const;
91 nsCOMPtr
<nsIContent
> mArea
;
94 PRPackedBool mHasFocus
;
97 Area::Area(nsIContent
* aArea
)
100 MOZ_COUNT_CTOR(Area
);
103 mHasFocus
= PR_FALSE
;
108 MOZ_COUNT_DTOR(Area
);
113 Area::GetHREF(nsAString
& aHref
) const
117 mArea
->GetAttr(kNameSpaceID_None
, nsGkAtoms::href
, aHref
);
122 Area::GetArea(nsIContent
** aArea
) const
125 NS_IF_ADDREF(*aArea
);
141 static void logMessage(nsIContent
* aContent
,
142 const nsAString
& aCoordsSpec
,
144 const char* aMessageName
) {
145 nsIURI
* documentURI
= nsnull
;
146 nsIDocument
* doc
= aContent
->GetOwnerDoc();
148 documentURI
= doc
->GetDocumentURI();
150 nsContentUtils::ReportToConsole(
151 nsContentUtils::eLAYOUT_PROPERTIES
,
154 0, /* params length */
156 PromiseFlatString(NS_LITERAL_STRING("coords=\"") +
158 NS_LITERAL_STRING("\"")), /* source line */
160 0, /* column number */
165 // XXX straight copy from laymap.c
166 static nscoord
* lo_parse_coord_list(char *str
, PRInt32
* value_cnt
)
174 * Nothing in an empty list
177 if (!str
|| *str
== '\0')
183 * Skip beginning whitespace, all whitespace is empty list.
186 while (is_space(*n_str
))
196 * Make a pass where any two numbers separated by just whitespace
197 * are given a comma separator. Count entries while passing.
200 while (*n_str
!= '\0')
205 * Skip to a separator
208 while (!is_space(*tptr
) && *tptr
!= ',' && *tptr
!= '\0')
215 * If no more entries, break out here
223 * Skip to the end of the separator, noting if we have a
226 has_comma
= PR_FALSE
;
227 while (is_space(*tptr
) || *tptr
== ',')
231 if (has_comma
== PR_FALSE
)
243 * If this was trailing whitespace we skipped, we are done.
245 if ((*tptr
== '\0')&&(has_comma
== PR_FALSE
))
250 * Else if the separator is all whitespace, and this is not the
251 * end of the string, add a comma to the separator.
253 else if (has_comma
== PR_FALSE
)
259 * count the entry skipped.
266 * count the last entry in the list.
271 * Allocate space for the coordinate array.
273 value_list
= new nscoord
[cnt
];
280 * Second pass to copy integer values into list.
283 for (i
=0; i
<cnt
; i
++)
287 ptr
= strchr(tptr
, ',');
293 * Strip whitespace in front of number because I don't
294 * trust atoi to do it on all platforms.
296 while (is_space(*tptr
))
306 value_list
[i
] = (nscoord
) ::atoi(tptr
);
319 void Area::ParseCoords(const nsAString
& aSpec
)
321 char* cp
= ToNewCString(aSpec
);
323 mCoords
= lo_parse_coord_list(cp
, &mNumCoords
);
328 void Area::HasFocus(PRBool aHasFocus
)
330 mHasFocus
= aHasFocus
;
333 //----------------------------------------------------------------------
335 class DefaultArea
: public Area
{
337 DefaultArea(nsIContent
* aArea
);
339 virtual PRBool
IsInside(nscoord x
, nscoord y
) const;
340 virtual void Draw(nsPresContext
* aCX
,
341 nsIRenderingContext
& aRC
);
342 virtual void GetRect(nsPresContext
* aCX
, nsRect
& aRect
);
345 DefaultArea::DefaultArea(nsIContent
* aArea
)
350 PRBool
DefaultArea::IsInside(nscoord x
, nscoord y
) const
355 void DefaultArea::Draw(nsPresContext
* aCX
, nsIRenderingContext
& aRC
)
359 void DefaultArea::GetRect(nsPresContext
* aCX
, nsRect
& aRect
)
363 //----------------------------------------------------------------------
365 class RectArea
: public Area
{
367 RectArea(nsIContent
* aArea
);
369 virtual void ParseCoords(const nsAString
& aSpec
);
370 virtual PRBool
IsInside(nscoord x
, nscoord y
) const;
371 virtual void Draw(nsPresContext
* aCX
,
372 nsIRenderingContext
& aRC
);
373 virtual void GetRect(nsPresContext
* aCX
, nsRect
& aRect
);
376 RectArea::RectArea(nsIContent
* aArea
)
381 void RectArea::ParseCoords(const nsAString
& aSpec
)
383 Area::ParseCoords(aSpec
);
385 PRBool saneRect
= PR_TRUE
;
386 PRInt32 flag
= nsIScriptError::warningFlag
;
387 if (mNumCoords
>= 4) {
388 if (mCoords
[0] > mCoords
[2]) {
389 // x-coords in reversed order
390 nscoord x
= mCoords
[2];
391 mCoords
[2] = mCoords
[0];
396 if (mCoords
[1] > mCoords
[3]) {
397 // y-coords in reversed order
398 nscoord y
= mCoords
[3];
399 mCoords
[3] = mCoords
[1];
404 if (mNumCoords
> 4) {
405 // Someone missed the concept of a rect here
410 flag
= nsIScriptError::errorFlag
;
414 logMessage(mArea
, aSpec
, flag
, "ImageMapRectBoundsError");
418 PRBool
RectArea::IsInside(nscoord x
, nscoord y
) const
420 if (mNumCoords
>= 4) { // Note: > is for nav compatability
421 nscoord x1
= mCoords
[0];
422 nscoord y1
= mCoords
[1];
423 nscoord x2
= mCoords
[2];
424 nscoord y2
= mCoords
[3];
425 NS_ASSERTION(x1
<= x2
&& y1
<= y2
,
426 "Someone screwed up RectArea::ParseCoords");
427 if ((x
>= x1
) && (x
<= x2
) && (y
>= y1
) && (y
<= y2
)) {
434 void RectArea::Draw(nsPresContext
* aCX
, nsIRenderingContext
& aRC
)
437 if (mNumCoords
>= 4) {
438 nscoord x1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
439 nscoord y1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
440 nscoord x2
= nsPresContext::CSSPixelsToAppUnits(mCoords
[2]);
441 nscoord y2
= nsPresContext::CSSPixelsToAppUnits(mCoords
[3]);
442 NS_ASSERTION(x1
<= x2
&& y1
<= y2
,
443 "Someone screwed up RectArea::ParseCoords");
444 aRC
.DrawLine(x1
, y1
, x1
, y2
);
445 aRC
.DrawLine(x1
, y2
, x2
, y2
);
446 aRC
.DrawLine(x1
, y1
, x2
, y1
);
447 aRC
.DrawLine(x2
, y1
, x2
, y2
);
452 void RectArea::GetRect(nsPresContext
* aCX
, nsRect
& aRect
)
454 if (mNumCoords
>= 4) {
455 nscoord x1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
456 nscoord y1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
457 nscoord x2
= nsPresContext::CSSPixelsToAppUnits(mCoords
[2]);
458 nscoord y2
= nsPresContext::CSSPixelsToAppUnits(mCoords
[3]);
459 NS_ASSERTION(x1
<= x2
&& y1
<= y2
,
460 "Someone screwed up RectArea::ParseCoords");
462 aRect
.SetRect(x1
, y1
, x2
, y2
);
466 //----------------------------------------------------------------------
468 class PolyArea
: public Area
{
470 PolyArea(nsIContent
* aArea
);
472 virtual void ParseCoords(const nsAString
& aSpec
);
473 virtual PRBool
IsInside(nscoord x
, nscoord y
) const;
474 virtual void Draw(nsPresContext
* aCX
,
475 nsIRenderingContext
& aRC
);
476 virtual void GetRect(nsPresContext
* aCX
, nsRect
& aRect
);
479 PolyArea::PolyArea(nsIContent
* aArea
)
484 void PolyArea::ParseCoords(const nsAString
& aSpec
)
486 Area::ParseCoords(aSpec
);
488 if (mNumCoords
>= 2) {
489 if (mNumCoords
& 1U) {
492 nsIScriptError::warningFlag
,
493 "ImageMapPolyOddNumberOfCoords");
498 nsIScriptError::errorFlag
,
499 "ImageMapPolyWrongNumberOfCoords");
503 PRBool
PolyArea::IsInside(nscoord x
, nscoord y
) const
505 if (mNumCoords
>= 6) {
506 PRInt32 intersects
= 0;
509 PRInt32 totalv
= mNumCoords
/ 2;
510 PRInt32 totalc
= totalv
* 2;
511 nscoord xval
= mCoords
[totalc
- 2];
512 nscoord yval
= mCoords
[totalc
- 1];
513 PRInt32 end
= totalc
;
516 if ((yval
>= wherey
) != (mCoords
[pointer
] >= wherey
))
517 if ((xval
>= wherex
) == (mCoords
[0] >= wherex
))
518 intersects
+= (xval
>= wherex
) ? 1 : 0;
520 intersects
+= ((xval
- (yval
- wherey
) *
521 (mCoords
[0] - xval
) /
522 (mCoords
[pointer
] - yval
)) >= wherex
) ? 1 : 0;
524 // XXX I wonder what this is doing; this is a translation of ptinpoly.c
525 while (pointer
< end
) {
526 yval
= mCoords
[pointer
];
528 if (yval
>= wherey
) {
529 while((pointer
< end
) && (mCoords
[pointer
] >= wherey
))
533 if ((mCoords
[pointer
-3] >= wherex
) ==
534 (mCoords
[pointer
-1] >= wherex
)) {
535 intersects
+= (mCoords
[pointer
-3] >= wherex
) ? 1 : 0;
538 ((mCoords
[pointer
-3] - (mCoords
[pointer
-2] - wherey
) *
539 (mCoords
[pointer
-1] - mCoords
[pointer
-3]) /
540 (mCoords
[pointer
] - mCoords
[pointer
- 2])) >= wherex
) ? 1:0;
543 while((pointer
< end
) && (mCoords
[pointer
] < wherey
))
547 if ((mCoords
[pointer
-3] >= wherex
) ==
548 (mCoords
[pointer
-1] >= wherex
)) {
549 intersects
+= (mCoords
[pointer
-3] >= wherex
) ? 1:0;
552 ((mCoords
[pointer
-3] - (mCoords
[pointer
-2] - wherey
) *
553 (mCoords
[pointer
-1] - mCoords
[pointer
-3]) /
554 (mCoords
[pointer
] - mCoords
[pointer
- 2])) >= wherex
) ? 1:0;
558 if ((intersects
& 1) != 0) {
565 void PolyArea::Draw(nsPresContext
* aCX
, nsIRenderingContext
& aRC
)
568 if (mNumCoords
>= 6) {
569 nscoord x0
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
570 nscoord y0
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
572 for (PRInt32 i
= 2; i
< mNumCoords
; i
+= 2) {
573 x1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[i
]);
574 y1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[i
+1]);
575 aRC
.DrawLine(x0
, y0
, x1
, y1
);
579 x1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
580 y1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
581 aRC
.DrawLine(x0
, y0
, x1
, y1
);
586 void PolyArea::GetRect(nsPresContext
* aCX
, nsRect
& aRect
)
588 if (mNumCoords
>= 6) {
589 nscoord x1
, x2
, y1
, y2
, xtmp
, ytmp
;
590 x1
= x2
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
591 y1
= y2
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
592 for (PRInt32 i
= 2; i
< mNumCoords
; i
+= 2) {
593 xtmp
= nsPresContext::CSSPixelsToAppUnits(mCoords
[i
]);
594 ytmp
= nsPresContext::CSSPixelsToAppUnits(mCoords
[i
+1]);
595 x1
= x1
< xtmp
? x1
: xtmp
;
596 y1
= y1
< ytmp
? y1
: ytmp
;
597 x2
= x2
> xtmp
? x2
: xtmp
;
598 y2
= y2
> ytmp
? y2
: ytmp
;
601 aRect
.SetRect(x1
, y1
, x2
, y2
);
605 //----------------------------------------------------------------------
607 class CircleArea
: public Area
{
609 CircleArea(nsIContent
* aArea
);
611 virtual void ParseCoords(const nsAString
& aSpec
);
612 virtual PRBool
IsInside(nscoord x
, nscoord y
) const;
613 virtual void Draw(nsPresContext
* aCX
,
614 nsIRenderingContext
& aRC
);
615 virtual void GetRect(nsPresContext
* aCX
, nsRect
& aRect
);
618 CircleArea::CircleArea(nsIContent
* aArea
)
623 void CircleArea::ParseCoords(const nsAString
& aSpec
)
625 Area::ParseCoords(aSpec
);
627 PRBool wrongNumberOfCoords
= PR_FALSE
;
628 PRInt32 flag
= nsIScriptError::warningFlag
;
629 if (mNumCoords
>= 3) {
630 if (mCoords
[2] < 0) {
633 nsIScriptError::errorFlag
,
634 "ImageMapCircleNegativeRadius");
637 if (mNumCoords
> 3) {
638 wrongNumberOfCoords
= PR_TRUE
;
641 wrongNumberOfCoords
= PR_TRUE
;
642 flag
= nsIScriptError::errorFlag
;
645 if (wrongNumberOfCoords
) {
649 "ImageMapCircleWrongNumberOfCoords");
653 PRBool
CircleArea::IsInside(nscoord x
, nscoord y
) const
655 // Note: > is for nav compatability
656 if (mNumCoords
>= 3) {
657 nscoord x1
= mCoords
[0];
658 nscoord y1
= mCoords
[1];
659 nscoord radius
= mCoords
[2];
665 nscoord dist
= (dx
* dx
) + (dy
* dy
);
666 if (dist
<= (radius
* radius
)) {
673 void CircleArea::Draw(nsPresContext
* aCX
, nsIRenderingContext
& aRC
)
676 if (mNumCoords
>= 3) {
677 nscoord x1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
678 nscoord y1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
679 nscoord radius
= nsPresContext::CSSPixelsToAppUnits(mCoords
[2]);
683 nscoord x
= x1
- radius
;
684 nscoord y
= y1
- radius
;
685 nscoord w
= 2 * radius
;
686 aRC
.DrawEllipse(x
, y
, w
, w
);
691 void CircleArea::GetRect(nsPresContext
* aCX
, nsRect
& aRect
)
693 if (mNumCoords
>= 3) {
694 nscoord x1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[0]);
695 nscoord y1
= nsPresContext::CSSPixelsToAppUnits(mCoords
[1]);
696 nscoord radius
= nsPresContext::CSSPixelsToAppUnits(mCoords
[2]);
701 aRect
.SetRect(x1
- radius
, y1
- radius
, x1
+ radius
, y1
+ radius
);
705 //----------------------------------------------------------------------
708 nsImageMap::nsImageMap() :
711 mContainsBlockContents(PR_FALSE
)
715 nsImageMap::~nsImageMap()
717 NS_ASSERTION(mAreas
.Count() == 0, "Destroy was not called");
720 NS_IMPL_ISUPPORTS4(nsImageMap
,
727 nsImageMap::GetBoundsForAreaContent(nsIContent
*aContent
,
728 nsPresContext
* aPresContext
,
731 // Find the Area struct associated with this content node, and return bounds
732 PRInt32 i
, n
= mAreas
.Count();
733 for (i
= 0; i
< n
; i
++) {
734 Area
* area
= (Area
*) mAreas
.ElementAt(i
);
735 if (area
->mArea
== aContent
) {
736 area
->GetRect(aPresContext
, aBounds
);
740 return NS_ERROR_FAILURE
;
744 nsImageMap::FreeAreas()
746 nsFrameManager
*frameManager
= mPresShell
->FrameManager();
748 PRInt32 i
, n
= mAreas
.Count();
749 for (i
= 0; i
< n
; i
++) {
750 Area
* area
= (Area
*) mAreas
.ElementAt(i
);
751 frameManager
->RemoveAsPrimaryFrame(area
->mArea
, mImageFrame
);
753 nsCOMPtr
<nsIContent
> areaContent
;
754 area
->GetArea(getter_AddRefs(areaContent
));
756 areaContent
->RemoveEventListenerByIID(this, NS_GET_IID(nsIDOMFocusListener
));
764 nsImageMap::Init(nsIPresShell
* aPresShell
, nsIFrame
* aImageFrame
, nsIDOMHTMLMapElement
* aMap
)
766 NS_PRECONDITION(nsnull
!= aMap
, "null ptr");
767 if (nsnull
== aMap
) {
768 return NS_ERROR_NULL_POINTER
;
770 mPresShell
= aPresShell
;
771 mImageFrame
= aImageFrame
;
773 mMap
= do_QueryInterface(aMap
);
774 NS_ASSERTION(mMap
, "aMap is not an nsIContent!");
775 mMap
->AddMutationObserver(this);
777 // "Compile" the areas in the map into faster access versions
778 return UpdateAreas();
783 nsImageMap::SearchForAreas(nsIContent
* aParent
, PRBool
& aFoundArea
,
784 PRBool
& aFoundAnchor
)
787 PRUint32 i
, n
= aParent
->GetChildCount();
789 // Look for <area> or <a> elements. We'll use whichever type we find first.
790 for (i
= 0; i
< n
; i
++) {
791 nsIContent
*child
= aParent
->GetChildAt(i
);
793 if (child
->IsNodeOfType(nsINode::eHTML
)) {
794 // If we haven't determined that the map element contains an
795 // <a> element yet, then look for <area>.
796 if (!aFoundAnchor
&& child
->Tag() == nsGkAtoms::area
) {
797 aFoundArea
= PR_TRUE
;
799 NS_ENSURE_SUCCESS(rv
, rv
);
801 // Continue to next child. This stops mContainsBlockContents from
802 // getting set. It also makes us ignore children of <area>s which
803 // is consistent with how we react to dynamic insertion of such
807 // If we haven't determined that the map element contains an
808 // <area> element yet, then look for <a>.
809 if (!aFoundArea
&& child
->Tag() == nsGkAtoms::a
) {
810 aFoundAnchor
= PR_TRUE
;
812 NS_ENSURE_SUCCESS(rv
, rv
);
816 if (child
->IsNodeOfType(nsINode::eELEMENT
)) {
817 mContainsBlockContents
= PR_TRUE
;
818 rv
= SearchForAreas(child
, aFoundArea
, aFoundAnchor
);
819 NS_ENSURE_SUCCESS(rv
, rv
);
827 nsImageMap::UpdateAreas()
829 // Get rid of old area data
832 PRBool foundArea
= PR_FALSE
;
833 PRBool foundAnchor
= PR_FALSE
;
834 mContainsBlockContents
= PR_FALSE
;
836 return SearchForAreas(mMap
, foundArea
, foundAnchor
);
840 nsImageMap::AddArea(nsIContent
* aArea
)
843 static nsIContent::AttrValuesArray strings
[] =
844 {&nsGkAtoms::_empty
, &nsGkAtoms::rect
, &nsGkAtoms::rectangle
,
845 &nsGkAtoms::poly
, &nsGkAtoms::polygon
, &nsGkAtoms::circle
,
846 &nsGkAtoms::circ
, &nsGkAtoms::_default
, nsnull
};
848 aArea
->GetAttr(kNameSpaceID_None
, nsGkAtoms::coords
, coords
);
851 switch (aArea
->FindAttrValueIn(kNameSpaceID_None
, nsGkAtoms::shape
,
852 strings
, eIgnoreCase
)) {
853 case nsIContent::ATTR_MISSING
:
857 area
= new RectArea(aArea
);
861 area
= new PolyArea(aArea
);
865 area
= new CircleArea(aArea
);
868 area
= new DefaultArea(aArea
);
871 // Unknown area type; bail
875 return NS_ERROR_OUT_OF_MEMORY
;
877 //Add focus listener to track area focus changes
878 aArea
->AddEventListenerByIID(this, NS_GET_IID(nsIDOMFocusListener
));
880 mPresShell
->FrameManager()->SetPrimaryFrameFor(aArea
, mImageFrame
);
881 aArea
->SetMayHaveFrame(PR_TRUE
);
882 NS_ASSERTION(aArea
->MayHaveFrame(), "SetMayHaveFrame failed?");
884 area
->ParseCoords(coords
);
885 mAreas
.AppendElement(area
);
890 nsImageMap::IsInside(nscoord aX
, nscoord aY
,
891 nsIContent
** aContent
) const
893 NS_ASSERTION(mMap
, "Not initialized");
894 PRInt32 i
, n
= mAreas
.Count();
895 for (i
= 0; i
< n
; i
++) {
896 Area
* area
= (Area
*) mAreas
.ElementAt(i
);
897 if (area
->IsInside(aX
, aY
)) {
898 area
->GetArea(aContent
);
908 nsImageMap::Draw(nsPresContext
* aCX
, nsIRenderingContext
& aRC
)
910 PRInt32 i
, n
= mAreas
.Count();
911 for (i
= 0; i
< n
; i
++) {
912 Area
* area
= (Area
*) mAreas
.ElementAt(i
);
913 area
->Draw(aCX
, aRC
);
918 nsImageMap::MaybeUpdateAreas(nsIContent
*aContent
)
920 if (aContent
== mMap
|| mContainsBlockContents
) {
926 nsImageMap::AttributeChanged(nsIDocument
* aDocument
,
927 nsIContent
* aContent
,
928 PRInt32 aNameSpaceID
,
933 // If the parent of the changing content node is our map then update
934 // the map. But only do this if the node is an HTML <area> or <a>
935 // and the attribute that's changing is "shape" or "coords" -- those
936 // are the only cases we care about.
937 if ((aContent
->NodeInfo()->Equals(nsGkAtoms::area
) ||
938 aContent
->NodeInfo()->Equals(nsGkAtoms::a
)) &&
939 aContent
->IsNodeOfType(nsINode::eHTML
) &&
940 aNameSpaceID
== kNameSpaceID_None
&&
941 (aAttribute
== nsGkAtoms::shape
||
942 aAttribute
== nsGkAtoms::coords
)) {
943 MaybeUpdateAreas(aContent
->GetParent());
948 nsImageMap::ContentAppended(nsIDocument
*aDocument
,
949 nsIContent
* aContainer
,
950 PRInt32 aNewIndexInContainer
)
952 MaybeUpdateAreas(aContainer
);
956 nsImageMap::ContentInserted(nsIDocument
*aDocument
,
957 nsIContent
* aContainer
,
959 PRInt32 aIndexInContainer
)
961 MaybeUpdateAreas(aContainer
);
965 nsImageMap::ContentRemoved(nsIDocument
*aDocument
,
966 nsIContent
* aContainer
,
968 PRInt32 aIndexInContainer
)
970 MaybeUpdateAreas(aContainer
);
974 nsImageMap::Focus(nsIDOMEvent
* aEvent
)
976 return ChangeFocus(aEvent
, PR_TRUE
);
980 nsImageMap::Blur(nsIDOMEvent
* aEvent
)
982 return ChangeFocus(aEvent
, PR_FALSE
);
986 nsImageMap::ChangeFocus(nsIDOMEvent
* aEvent
, PRBool aFocus
) {
987 //Set which one of our areas changed focus
988 nsCOMPtr
<nsIDOMEventTarget
> target
;
989 if (NS_SUCCEEDED(aEvent
->GetTarget(getter_AddRefs(target
))) && target
) {
990 nsCOMPtr
<nsIContent
> targetContent(do_QueryInterface(target
));
992 PRInt32 i
, n
= mAreas
.Count();
993 for (i
= 0; i
< n
; i
++) {
994 Area
* area
= (Area
*) mAreas
.ElementAt(i
);
995 nsCOMPtr
<nsIContent
> areaContent
;
996 area
->GetArea(getter_AddRefs(areaContent
));
998 if (areaContent
.get() == targetContent
.get()) {
999 //Set or Remove internal focus
1000 area
->HasFocus(aFocus
);
1001 //Now invalidate the rect
1002 nsCOMPtr
<nsIDocument
> doc
= targetContent
->GetDocument();
1003 //This check is necessary to see if we're still attached to the doc
1005 nsIPresShell
*presShell
= doc
->GetPrimaryShell();
1007 nsIFrame
* imgFrame
= presShell
->GetPrimaryFrameFor(targetContent
);
1009 nsPresContext
*presContext
= presShell
->GetPresContext();
1012 area
->GetRect(presContext
, dmgRect
);
1013 imgFrame
->Invalidate(dmgRect
, PR_TRUE
);
1027 nsImageMap::HandleEvent(nsIDOMEvent
* aEvent
)
1033 nsImageMap::Destroy(void)
1036 mMap
->RemoveMutationObserver(this);