/* -*- Mode: objc; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Josh Aas * Mark Mentovai * HÃ¥kan Waara * Stuart Morgan * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include "nsChildView.h" #include "nsCocoaWindow.h" #include "nsCOMPtr.h" #include "nsToolkit.h" #include "prmem.h" #include "nsCRT.h" #include "nsplugindefs.h" #include "nsThreadUtils.h" #include "nsIPrefService.h" #include "nsIPrefBranch.h" #include "nsIFontMetrics.h" #include "nsIDeviceContext.h" #include "nsIRegion.h" #include "nsIRollupListener.h" #include "nsIEventSink.h" #include "nsIScrollableView.h" #include "nsIViewManager.h" #include "nsIInterfaceRequestor.h" #include "nsIServiceManager.h" #include "nsILocalFile.h" #include "nsILocalFileMac.h" #include "nsGfxCIID.h" #include "nsDragService.h" #include "nsCursorManager.h" #include "nsWindowMap.h" #include "nsCocoaUtils.h" #include "gfxContext.h" #include "gfxQuartzSurface.h" #undef DEBUG_IME #undef DEBUG_UPDATE #undef INVALIDATE_DEBUGGING // flash areas as they are invalidated #ifdef MOZ_LOGGING #define FORCE_PR_LOG #endif #include "prlog.h" #ifdef PR_LOGGING PRLogModuleInfo* sCocoaLog = nsnull; #endif // npapi.h defines NPEventType_AdjustCursorEvent but we don't want to include npapi.h here. // We need to send this in the "what" field for certain native plugin events. WebKit does // this as well. #define adjustCursorEvent 33 extern "C" { CG_EXTERN void CGContextResetCTM(CGContextRef); CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform); CG_EXTERN void CGContextResetClip(CGContextRef); } extern nsISupportsArray *gDraggedTransferables; PRBool nsTSMManager::sIsIMEEnabled = PR_TRUE; PRBool nsTSMManager::sIsRomanKeyboardsOnly = PR_FALSE; PRBool nsTSMManager::sIgnoreCommit = PR_FALSE; NSView* nsTSMManager::sComposingView = nsnull; TSMDocumentID nsTSMManager::sDocumentID = nsnull; NSString* nsTSMManager::sComposingString = nsnull; static NS_DEFINE_CID(kRegionCID, NS_REGION_CID); static NSView* sLastViewEntered = nil; #ifdef INVALIDATE_DEBUGGING static void blinkRect(Rect* r); static void blinkRgn(RgnHandle rgn); #endif nsIRollupListener * gRollupListener = nsnull; nsIWidget * gRollupWidget = nsnull; @interface ChildView(Private) // sets up our view, attaching it to its owning gecko view - (id)initWithFrame:(NSRect)inFrame geckoChild:(nsChildView*)inChild eventSink:(nsIEventSink*)inSink; // sends gecko an ime composition event - (nsRect) sendCompositionEvent:(PRInt32)aEventType; // sends gecko an ime text event - (void) sendTextEvent:(PRUnichar*) aBuffer attributedString:(NSAttributedString*) aString selectedRange:(NSRange)selRange markedRange:(NSRange)markRange doCommit:(BOOL)doCommit; // do generic gecko event setup with a generic cocoa event. accepts nil inEvent. - (void) convertGenericCocoaEvent:(NSEvent*)inEvent toGeckoEvent:(nsInputEvent*)outGeckoEvent; // set up a gecko mouse event based on a cocoa mouse event - (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent toGeckoEvent:(nsInputEvent*)outGeckoEvent; // set up a gecko key event based on a cocoa key event - (void) convertCocoaKeyEvent:(NSEvent*)aKeyEvent toGeckoEvent:(nsKeyEvent*)outGeckoEvent; - (NSMenu*)contextMenu; - (TopLevelWindowData*)ensureWindowData; - (void)setIsPluginView:(BOOL)aIsPlugin; - (BOOL)isPluginView; - (BOOL)childViewHasPlugin; - (BOOL)isRectObscuredBySubview:(NSRect)inRect; - (void)processPendingRedraws; - (BOOL)maybeRerouteMouseEventToRollupWidget:(NSEvent *)anEvent; + (BOOL)mouseEventIsOverRollupWidget:(NSEvent *)anEvent; - (void)maybeInitContextMenuTracking; - (nsChildView *)getGeckoChild; #if USE_CLICK_HOLD_CONTEXTMENU // called on a timer two seconds after a mouse down to see if we should display // a context menu (click-hold) - (void)clickHoldCallback:(id)inEvent; #endif #ifdef ACCESSIBILITY - (id)accessible; #endif @end #pragma mark - /* Convenience routines to go from a gecko rect to cocoa NSRects and back * * Gecko rects (nsRect) contain an origin (x,y) in a coordinate * system with (0,0) in the top-left of the screen. Cocoa rects * (NSRect) contain an origin (x,y) in a coordinate system with * (0,0) in the bottom-left of the screen. Both nsRect and NSRect * contain width/height info, with no difference in their use. * If a Cocoa rect is from a flipped view, there is no need to * convert coordinate systems. */ static inline void GeckoRectToNSRect(const nsRect & inGeckoRect, NSRect & outCocoaRect) { outCocoaRect.origin.x = inGeckoRect.x; outCocoaRect.origin.y = inGeckoRect.y; outCocoaRect.size.width = inGeckoRect.width; outCocoaRect.size.height = inGeckoRect.height; } static inline void NSRectToGeckoRect(const NSRect & inCocoaRect, nsRect & outGeckoRect) { outGeckoRect.x = static_cast(inCocoaRect.origin.x); outGeckoRect.y = static_cast(inCocoaRect.origin.y); outGeckoRect.width = static_cast(inCocoaRect.size.width); outGeckoRect.height = static_cast(inCocoaRect.size.height); } static inline void ConvertGeckoRectToMacRect(const nsRect& aRect, Rect& outMacRect) { outMacRect.left = aRect.x; outMacRect.top = aRect.y; outMacRect.right = aRect.x + aRect.width; outMacRect.bottom = aRect.y + aRect.height; } // Flips a screen coordinate from a point in the cocoa coordinate system (bottom-left rect) to a point // that is a "flipped" cocoa coordinate system (starts in the top-left). static inline void FlipCocoaScreenCoordinate (NSPoint &inPoint) { inPoint.y = FlippedScreenY(inPoint.y); } static PRUint32 UnderlineAttributeToTextRangeType(PRUint32 aUnderlineStyle, NSRange selRange) { #ifdef DEBUG_IME NSLog(@"****in underlineAttributeToTextRangeType = %d", aUnderlineStyle); #endif // For more info on the underline attribute, please see: // http://developer.apple.com/techpubs/macosx/Cocoa/TasksAndConcepts/ProgrammingTopics/AttributedStrings/Tasks/AccessingAttrs.html // We are not clear where the define for value 2 is right now. // To see this value in japanese ime, type 'aaaaaaaaa' and hit space to make the // ime send you some part of text in 1 (NSSingleUnderlineStyle) and some part in 2. // ftang will ask apple for more details // // it probably means show 1-pixel thickness underline vs 2-pixel thickness PRUint32 attr; if (selRange.length == 0) { switch (aUnderlineStyle) { case 1: attr = NS_TEXTRANGE_RAWINPUT; break; case 2: default: attr = NS_TEXTRANGE_SELECTEDRAWTEXT; break; } } else { switch (aUnderlineStyle) { case 1: attr = NS_TEXTRANGE_CONVERTEDTEXT; break; case 2: default: attr = NS_TEXTRANGE_SELECTEDCONVERTEDTEXT; break; } } return attr; } static PRUint32 CountRanges(NSAttributedString *aString) { // Iterate through aString for the NSUnderlineStyleAttributeName and count the // different segments adjusting limitRange as we go. PRUint32 count = 0; NSRange effectiveRange; NSRange limitRange = NSMakeRange(0, [aString length]); while (limitRange.length > 0) { [aString attribute:NSUnderlineStyleAttributeName atIndex:limitRange.location longestEffectiveRange:&effectiveRange inRange:limitRange]; limitRange = NSMakeRange(NSMaxRange(effectiveRange), NSMaxRange(limitRange) - NSMaxRange(effectiveRange)); count++; } return count; } static void ConvertAttributeToGeckoRange(NSAttributedString *aString, NSRange markRange, NSRange selRange, PRUint32 inCount, nsTextRange* aRanges) { // Convert the Cocoa range into the nsTextRange Array used in Gecko. // Iterate through the attributed string and map the underline attribute to Gecko IME textrange attributes. // We may need to change the code here if we change the implementation of validAttributesForMarkedText. PRUint32 i = 0; NSRange effectiveRange; NSRange limitRange = NSMakeRange(0, [aString length]); while ((limitRange.length > 0) && (i < inCount)) { id attributeValue = [aString attribute:NSUnderlineStyleAttributeName atIndex:limitRange.location longestEffectiveRange:&effectiveRange inRange:limitRange]; aRanges[i].mStartOffset = effectiveRange.location; aRanges[i].mEndOffset = NSMaxRange(effectiveRange); aRanges[i].mRangeType = UnderlineAttributeToTextRangeType([attributeValue intValue], selRange); limitRange = NSMakeRange(NSMaxRange(effectiveRange), NSMaxRange(limitRange) - NSMaxRange(effectiveRange)); i++; } // Get current caret position. // Caret is indicator of insertion point, so mEndOffset = 0. aRanges[i].mStartOffset = selRange.location + selRange.length; aRanges[i].mEndOffset = 0; aRanges[i].mRangeType = NS_TEXTRANGE_CARETPOSITION; } static void FillTextRangeInTextEvent(nsTextEvent *aTextEvent, NSAttributedString* aString, NSRange markRange, NSRange selRange) { // Count the number of segments in the attributed string and add one more count for sending current caret position to Gecko. // Allocate the right size of nsTextRange and draw caret at right position. // Convert the attributed string into an array of nsTextRange and get current caret position by calling above functions. PRUint32 count = CountRanges(aString) + 1; aTextEvent->rangeArray = new nsTextRange[count]; if (aTextEvent->rangeArray) { aTextEvent->rangeCount = count; ConvertAttributeToGeckoRange(aString, markRange, selRange, aTextEvent->rangeCount, aTextEvent->rangeArray); } } #pragma mark - nsChildView::nsChildView() : nsBaseWidget() , mView(nsnull) , mParentView(nsnull) , mParentWidget(nsnull) , mDestructorCalled(PR_FALSE) , mVisible(PR_FALSE) , mDrawing(PR_FALSE) , mAcceptFocusOnClick(PR_TRUE) , mLiveResizeInProgress(PR_FALSE) , mIsPluginView(PR_FALSE) , mPluginDrawing(PR_FALSE) , mPluginIsCG(PR_FALSE) { #ifdef PR_LOGGING if (!sCocoaLog) sCocoaLog = PR_NewLogModule("nsCocoaWidgets"); #endif SetBackgroundColor(NS_RGB(255, 255, 255)); SetForegroundColor(NS_RGB(0, 0, 0)); } nsChildView::~nsChildView() { // notify the children that we're gone for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) { nsChildView* childView = static_cast(kid); childView->mParentWidget = nsnull; } TearDownView(); // should have already been done from Destroy } NS_IMPL_ISUPPORTS_INHERITED3(nsChildView, nsBaseWidget, nsIPluginWidget, nsIKBStateControl, nsIEventSink) // Utility method for implementing both Create(nsIWidget ...) // and Create(nsNativeWidget...) nsresult nsChildView::StandardCreate(nsIWidget *aParent, const nsRect &aRect, EVENT_CALLBACK aHandleEventFunction, nsIDeviceContext *aContext, nsIAppShell *aAppShell, nsIToolkit *aToolkit, nsWidgetInitData *aInitData, nsNativeWidget aNativeParent) { mBounds = aRect; BaseCreate(aParent, aRect, aHandleEventFunction, aContext, aAppShell, aToolkit, aInitData); // inherit things from the parent view and create our parallel // NSView in the Cocoa display system mParentView = nil; if (aParent) { SetBackgroundColor(aParent->GetBackgroundColor()); SetForegroundColor(aParent->GetForegroundColor()); // inherit the top-level window. NS_NATIVE_WIDGET is always a NSView // regardless of if we're asking a window or a view (for compatibility // with windows). mParentView = (NSView*)aParent->GetNativeData(NS_NATIVE_WIDGET); mParentWidget = aParent; } else mParentView = reinterpret_cast(aNativeParent); // create our parallel NSView and hook it up to our parent. Recall // that NS_NATIVE_WIDGET is the NSView. NSRect r; GeckoRectToNSRect(mBounds, r); mView = [CreateCocoaView(r) retain]; if (!mView) return NS_ERROR_FAILURE; #if DEBUG // if our parent is a popup window, we're most certainly coming from a