/* * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #import "WebBackForwardList.h" #import "WebBackForwardListInternal.h" #import "BackForwardList.h" #import "WebFrameInternal.h" #import "WebHistoryItemInternal.h" #import "WebHistoryItemPrivate.h" #import "WebKitLogging.h" #import "WebKitVersionChecks.h" #import "WebNSObjectExtras.h" #import "WebPreferencesPrivate.h" #import "WebViewPrivate.h" #import #import #import #import #import #import #import #import #import #import #import #import #import typedef HashMap BackForwardListMap; // FIXME: Instead of this we could just create a class derived from BackForwardList // with a pointer to a WebBackForwardList in it. static BackForwardListMap& backForwardLists() { static NeverDestroyed staticBackForwardLists; return staticBackForwardLists; } @implementation WebBackForwardList BackForwardList* core(WebBackForwardList *webBackForwardList) { if (!webBackForwardList) return 0; return reinterpret_cast(webBackForwardList->_private); } WebBackForwardList *kit(BackForwardList* backForwardList) { if (!backForwardList) return nil; if (WebBackForwardList *webBackForwardList = backForwardLists().get(backForwardList)) return webBackForwardList; return adoptNS([[WebBackForwardList alloc] initWithBackForwardList:*backForwardList]).autorelease(); } - (id)initWithBackForwardList:(Ref&&)backForwardList { WebCoreThreadViolationCheckRoundOne(); self = [super init]; if (!self) return nil; _private = reinterpret_cast(&backForwardList.leakRef()); backForwardLists().set(core(self), self); return self; } + (void)initialize { #if !PLATFORM(IOS_FAMILY) JSC::initialize(); WTF::initializeMainThread(); WebCore::populateJITOperations(); #endif } - (id)init { return [self initWithBackForwardList:BackForwardList::create(nullptr)]; } - (void)dealloc { if (WebCoreObjCScheduleDeallocateOnMainThread([WebBackForwardList class], self)) return; BackForwardList* backForwardList = core(self); ASSERT(backForwardList); if (backForwardList) { ASSERT(backForwardList->closed()); backForwardLists().remove(backForwardList); backForwardList->deref(); } [super dealloc]; } - (void)_close { core(self)->close(); } - (void)addItem:(WebHistoryItem *)entry { ASSERT(entry); core(self)->addItem(*core(entry)); // Since the assumed contract with WebBackForwardList is that it retains its WebHistoryItems, // the following line prevents a whole class of problems where a history item will be created in // a function, added to the BFlist, then used in the rest of that function. retainPtr(entry).autorelease(); } - (void)removeItem:(WebHistoryItem *)item { if (!item) return; core(self)->removeItem(*core(item)); } #if PLATFORM(IOS_FAMILY) // FIXME: Move into WebCore the code that deals directly with WebCore::BackForwardList. constexpr auto WebBackForwardListDictionaryEntriesKey = @"entries"; constexpr auto WebBackForwardListDictionaryCapacityKey = @"capacity"; constexpr auto WebBackForwardListDictionaryCurrentKey = @"current"; - (NSDictionary *)dictionaryRepresentation { auto& list = *core(self); auto entries = createNSArray(list.entries(), [] (auto& item) { return [kit(const_cast(item.ptr())) dictionaryRepresentationIncludingChildren:NO]; }); return @{ WebBackForwardListDictionaryEntriesKey: entries.get(), WebBackForwardListDictionaryCurrentKey: @(list.current()), WebBackForwardListDictionaryCapacityKey: @(list.capacity()), }; } - (void)setToMatchDictionaryRepresentation:(NSDictionary *)dictionary { auto& list = *core(self); list.setCapacity([[dictionary objectForKey:WebBackForwardListDictionaryCapacityKey] unsignedIntValue]); for (NSDictionary *itemDictionary in [dictionary objectForKey:WebBackForwardListDictionaryEntriesKey]) list.addItem(*core(adoptNS([[WebHistoryItem alloc] initFromDictionaryRepresentation:itemDictionary]).get())); unsigned currentIndex = [[dictionary objectForKey:WebBackForwardListDictionaryCurrentKey] unsignedIntValue]; size_t listSize = list.entries().size(); if (currentIndex >= listSize) currentIndex = listSize - 1; list.setCurrent(currentIndex); } #endif // PLATFORM(IOS_FAMILY) - (BOOL)containsItem:(WebHistoryItem *)item { if (!item) return NO; return core(self)->containsItem(*core(item)); } - (void)goBack { core(self)->goBack(); } - (void)goForward { core(self)->goForward(); } - (void)goToItem:(WebHistoryItem *)item { if (item) core(self)->goToItem(*core(item)); } - (WebHistoryItem *)backItem { return retainPtr(kit(core(self)->backItem().get())).autorelease(); } - (WebHistoryItem *)currentItem { return retainPtr(kit(core(self)->currentItem().get())).autorelease(); } - (WebHistoryItem *)forwardItem { return retainPtr(kit(core(self)->forwardItem().get())).autorelease(); } static bool bumperCarBackForwardHackNeeded() { #if !PLATFORM(IOS_FAMILY) static bool hackNeeded = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.freeverse.bumpercar"] && !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_BUMPERCAR_BACK_FORWARD_QUIRK); return hackNeeded; #else return false; #endif } - (NSArray *)backListWithLimit:(int)limit { Vector> list; core(self)->backListWithLimit(limit, list); auto result = createNSArray(list, [] (auto& item) { return kit(item.ptr()); }); if (bumperCarBackForwardHackNeeded()) { static NeverDestroyed> lastBackListArray; lastBackListArray.get() = result; } return result.autorelease(); } - (NSArray *)forwardListWithLimit:(int)limit { Vector> list; core(self)->forwardListWithLimit(limit, list); auto result = createNSArray(list, [] (auto& item) { return kit(item.ptr()); }); if (bumperCarBackForwardHackNeeded()) { static NeverDestroyed> lastForwardListArray; lastForwardListArray.get() = result; } return result.autorelease(); } - (int)capacity { return core(self)->capacity(); } - (void)setCapacity:(int)size { core(self)->setCapacity(size); } -(NSString *)description { NSMutableString *result; result = [NSMutableString stringWithCapacity:512]; [result appendString:@"\n--------------------------------------------\n"]; [result appendString:@"WebBackForwardList:\n"]; BackForwardList* backForwardList = core(self); auto& entries = backForwardList->entries(); for (unsigned i = 0; i < entries.size(); ++i) { if (entries[i].ptr() == backForwardList->currentItem()) { [result appendString:@" >>>"]; } else { [result appendString:@" "]; } [result appendFormat:@"%2d) ", i]; int currPos = [result length]; [result appendString:[kit(const_cast(entries[i].ptr())) description]]; // shift all the contents over. a bit slow, but this is for debugging NSRange replRange = { static_cast(currPos), [result length] - currPos }; [result replaceOccurrencesOfString:@"\n" withString:@"\n " options:0 range:replRange]; [result appendString:@"\n"]; } [result appendString:@"\n--------------------------------------------\n"]; return result; } - (void)setPageCacheSize:(NSUInteger)size { [core(self)->webView() setUsesPageCache:size != 0]; } - (NSUInteger)pageCacheSize { return [core(self)->webView() usesPageCache] ? WebCore::BackForwardCache::singleton().maxSize() : 0; } - (int)backListCount { return core(self)->backListCount(); } - (int)forwardListCount { return core(self)->forwardListCount(); } - (WebHistoryItem *)itemAtIndex:(int)index { return retainPtr(kit(core(self)->itemAtIndex(index).get())).autorelease(); } @end