<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import Foundation
import WebKit
import Shared
import JavaScriptCore

let kNotificationPageUnload = "kNotificationPageUnload"
let kNotificationAllWebViewsDeallocated = "kNotificationAllWebViewsDeallocated"

func convertNavActionToWKType(_ type:UIWebViewNavigationType) -> WKNavigationType {
    return WKNavigationType(rawValue: type.rawValue)!
}

class ContainerWebView : WKWebView {
    weak var legacyWebView: BraveWebView?
}

var globalContainerWebView = ContainerWebView()

protocol WebPageStateDelegate : class {
    func webView(_ webView: UIWebView, progressChanged: Float)
    func webView(_ webView: UIWebView, isLoading: Bool)
    func webView(_ webView: UIWebView, urlChanged: String)
    func webView(_ webView: UIWebView, canGoBack: Bool)
    func webView(_ webView: UIWebView, canGoForward: Bool)
}


@objc class HandleJsWindowOpen : NSObject {
    static func open(_ url: String) {
        postAsyncToMain(0) { // we now know JS callbacks can be off main
            guard let wv = BraveApp.getCurrentWebView() else { return }
            let current = wv.URL
            print("window.open")
            if BraveApp.getPrefs()?.boolForKey("blockPopups") ?? true {
                guard let lastTappedTime = wv.lastTappedTime else { return }
                if fabs(lastTappedTime.timeIntervalSinceNow) > 0.75 { // outside of the 3/4 sec time window and we ignore it
                    print(lastTappedTime.timeIntervalSinceNow)
                    return
                }
            }
            wv.lastTappedTime = nil
            if let _url = URL(string: url, relativeTo: current) {
                getApp().browserViewController.openURLInNewTab(_url)
            }
        }
    }
}

class BrowserTabToUAMapper {
    static fileprivate let idToBrowserTab = NSMapTable<NSString, AnyObject>(keyOptions: NSPointerFunctions.Options.strongMemory, valueOptions: NSPointerFunctions.Options.weakMemory)

    static func setId(_ uniqueId: Int, tab: Browser) {
        objc_sync_enter(self)
        defer { objc_sync_exit(self) }
        idToBrowserTab.setObject(tab, forKey: "\(uniqueId)" as NSString)
    }

    static func userAgentToBrowserTab(_ ua: String?) -> Browser? {
        // synchronize code from this point on.
        objc_sync_enter(self)
        defer { objc_sync_exit(self) }

        guard let ua = ua else { return nil }
        guard let loc = ua.range(of: "_id/") else {
            // the first created webview doesn't have this id set (see webviewBuiltinUserAgent to explain)
            return idToBrowserTab.object(forKey: "1") as? Browser
        }

        let to = ua.index(loc.upperBound, offsetBy: 6)
        let keyString = ua.substring(with: loc.upperBound..<to)
        guard let key = Int(keyString) else { return nil }
        // Cast to an int and back again
        return idToBrowserTab.object(forKey: "\(key)" as NSString) as? Browser
    }
}

struct BraveWebViewConstants {
    static let kNotificationWebViewLoadCompleteOrFailed = "kNotificationWebViewLoadCompleteOrFailed"
    static let kNotificationPageInteractive = "kNotificationPageInteractive"
    static let kContextMenuBlockNavigation = 8675309
}

class BraveWebView: UIWebView {
    class Weak_WebPageStateDelegate {     // We can't use a WeakList here because this is a protocol.
        weak var value : WebPageStateDelegate?
        init (value: WebPageStateDelegate) { self.value = value }
    }
    var delegatesForPageState = [Weak_WebPageStateDelegate]()

    let usingDesktopUserAgent: Bool
    let specialStopLoadUrl = "http://localhost.stop.load"
    weak var navigationDelegate: WKCompatNavigationDelegate?

    lazy var configuration: BraveWebViewConfiguration = { return BraveWebViewConfiguration(webView: self) }()
    lazy var backForwardList: WebViewBackForwardList = { return WebViewBackForwardList(webView: self) } ()
    var progress: WebViewProgress?
    var certificateInvalidConnection:NSURLConnection?

    var uniqueId = -1
    var knownFrameContexts = Set<NSObject>()
    fileprivate static var containerWebViewForCallbacks = { return ContainerWebView() }()
    // From http://stackoverflow.com/questions/14268230/has-anybody-found-a-way-to-load-https-pages-with-an-invalid-server-certificate-u
    var loadingUnvalidatedHTTPSPage: Bool = false



    var blankTargetLinkDetectionOn = true
    var lastTappedTime: Date?
    var removeBvcObserversOnDeinit: ((UIWebView) -> Void)?
    var removeProgressObserversOnDeinit: ((UIWebView) -> Void)?

    var safeBrowsingBlockTriggered:Bool = false
    
    var estimatedProgress: Double = 0
    var title: String = "" {
        didSet {
            if let item = backForwardList.currentItem {
                item.title = title
            }
        }
    }

    fileprivate var _url: (url: Foundation.URL?, prevUrl: Foundation.URL?) = (nil, nil)

    fileprivate var lastBroadcastedKvoUrl: String = ""
    // return true if set, false if unchanged
    @discardableResult func setUrl( _ newUrl: Foundation.URL?) -> Bool {
        guard var newUrl = newUrl, !newUrl.absoluteString.isEmpty else { return false }
        let urlString = newUrl.absoluteString
        
        if urlString.endsWith("?") {
            if let noEndingQ = URL?.absoluteString.components(separatedBy: "?")[0] {
                newUrl = Foundation.URL(string: noEndingQ) ?? newUrl
            }
        }

        if urlString == _url.url?.absoluteString {
            return false
        }

        _url.prevUrl = _url.url
        _url.url = newUrl

        if urlString != lastBroadcastedKvoUrl {
            delegatesForPageState.forEach { $0.value?.webView(self, urlChanged: urlString) }
            lastBroadcastedKvoUrl = urlString
        }

        return true
    }

    var previousUrl: Foundation.URL? { get { return _url.prevUrl } }

    var URL: Foundation.URL? {
        get {
            return _url.url
        }
    }
<commit_msg>Make scrollview indicator on ipx horizontal left close to screen edge. (#1380)<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import Foundation
import WebKit
import Shared
import JavaScriptCore

let kNotificationPageUnload = "kNotificationPageUnload"
let kNotificationAllWebViewsDeallocated = "kNotificationAllWebViewsDeallocated"

func convertNavActionToWKType(_ type:UIWebViewNavigationType) -> WKNavigationType {
    return WKNavigationType(rawValue: type.rawValue)!
}

class ContainerWebView : WKWebView {
    weak var legacyWebView: BraveWebView?
}

var globalContainerWebView = ContainerWebView()

protocol WebPageStateDelegate : class {
    func webView(_ webView: UIWebView, progressChanged: Float)
    func webView(_ webView: UIWebView, isLoading: Bool)
    func webView(_ webView: UIWebView, urlChanged: String)
    func webView(_ webView: UIWebView, canGoBack: Bool)
    func webView(_ webView: UIWebView, canGoForward: Bool)
}


@objc class HandleJsWindowOpen : NSObject {
    static func open(_ url: String) {
        postAsyncToMain(0) { // we now know JS callbacks can be off main
            guard let wv = BraveApp.getCurrentWebView() else { return }
            let current = wv.URL
            print("window.open")
            if BraveApp.getPrefs()?.boolForKey("blockPopups") ?? true {
                guard let lastTappedTime = wv.lastTappedTime else { return }
                if fabs(lastTappedTime.timeIntervalSinceNow) > 0.75 { // outside of the 3/4 sec time window and we ignore it
                    print(lastTappedTime.timeIntervalSinceNow)
                    return
                }
            }
            wv.lastTappedTime = nil
            if let _url = URL(string: url, relativeTo: current) {
                getApp().browserViewController.openURLInNewTab(_url)
            }
        }
    }
}

class BrowserTabToUAMapper {
    static fileprivate let idToBrowserTab = NSMapTable<NSString, AnyObject>(keyOptions: NSPointerFunctions.Options.strongMemory, valueOptions: NSPointerFunctions.Options.weakMemory)

    static func setId(_ uniqueId: Int, tab: Browser) {
        objc_sync_enter(self)
        defer { objc_sync_exit(self) }
        idToBrowserTab.setObject(tab, forKey: "\(uniqueId)" as NSString)
    }

    static func userAgentToBrowserTab(_ ua: String?) -> Browser? {
        // synchronize code from this point on.
        objc_sync_enter(self)
        defer { objc_sync_exit(self) }

        guard let ua = ua else { return nil }
        guard let loc = ua.range(of: "_id/") else {
            // the first created webview doesn't have this id set (see webviewBuiltinUserAgent to explain)
            return idToBrowserTab.object(forKey: "1") as? Browser
        }

        let to = ua.index(loc.upperBound, offsetBy: 6)
        let keyString = ua.substring(with: loc.upperBound..<to)
        guard let key = Int(keyString) else { return nil }
        // Cast to an int and back again
        return idToBrowserTab.object(forKey: "\(key)" as NSString) as? Browser
    }
}

struct BraveWebViewConstants {
    static let kNotificationWebViewLoadCompleteOrFailed = "kNotificationWebViewLoadCompleteOrFailed"
    static let kNotificationPageInteractive = "kNotificationPageInteractive"
    static let kContextMenuBlockNavigation = 8675309
}

class BraveWebView: UIWebView {
    class Weak_WebPageStateDelegate {     // We can't use a WeakList here because this is a protocol.
        weak var value : WebPageStateDelegate?
        init (value: WebPageStateDelegate) { self.value = value }
    }
    var delegatesForPageState = [Weak_WebPageStateDelegate]()

    let usingDesktopUserAgent: Bool
    let specialStopLoadUrl = "http://localhost.stop.load"
    weak var navigationDelegate: WKCompatNavigationDelegate?

    lazy var configuration: BraveWebViewConfiguration = { return BraveWebViewConfiguration(webView: self) }()
    lazy var backForwardList: WebViewBackForwardList = { return WebViewBackForwardList(webView: self) } ()
    var progress: WebViewProgress?
    var certificateInvalidConnection:NSURLConnection?

    var uniqueId = -1
    var knownFrameContexts = Set<NSObject>()
    fileprivate static var containerWebViewForCallbacks = { return ContainerWebView() }()
    // From http://stackoverflow.com/questions/14268230/has-anybody-found-a-way-to-load-https-pages-with-an-invalid-server-certificate-u
    var loadingUnvalidatedHTTPSPage: Bool = false



    var blankTargetLinkDetectionOn = true
    var lastTappedTime: Date?
    var removeBvcObserversOnDeinit: ((UIWebView) -> Void)?
    var removeProgressObserversOnDeinit: ((UIWebView) -> Void)?

    var safeBrowsingBlockTriggered:Bool = false
    
    var estimatedProgress: Double = 0
    var title: String = "" {
        didSet {
            if let item = backForwardList.currentItem {
                item.title = title
            }
        }
    }

    fileprivate var _url: (url: Foundation.URL?, prevUrl: Foundation.URL?) = (nil, nil)

    fileprivate var lastBroadcastedKvoUrl: String = ""
    // return true if set, false if unchanged
    @discardableResult func setUrl( _ newUrl: Foundation.URL?) -> Bool {
        guard var newUrl = newUrl, !newUrl.absoluteString.isEmpty else { return false }
        let urlString = newUrl.absoluteString
        
        if urlString.endsWith("?") {
            if let noEndingQ = URL?.absoluteString.components(separatedBy: "?")[0] {
                newUrl = Foundation.URL(string: noEndingQ) ?? newUrl
            }
        }

        if urlString == _url.url?.absoluteString {
            return false
        }

        _url.prevUrl = _url.url
        _url.url = newUrl

        if urlString != lastBroadcastedKvoUrl {
            delegatesForPageState.forEach { $0.value?.webView(self, urlChanged: urlString) }
            lastBroadcastedKvoUrl = urlString
        }

        return true
    }

    var previousUrl: Foundation.URL? { get { return _url.prevUrl } }

    var URL: Foundation.URL? {
        get {
            return _url.url
        }
    }

    override func safeAreaInsetsDidChange() {
        // On Safari, scroll view indicator is next to the edge when ipX is in landscape and notch is on the left
        // We need to adjust inset for this only screen configuration.
        if #available(iOS 11, *), DeviceDetector.iPhoneX {
            let isLandscapeLeft = UIDevice.current.orientation == UIDeviceOrientation.landscapeLeft
            // No easy way to get right inset, using hardcoded value
            scrollView.scrollIndicatorInsets.right = isLandscapeLeft ? -44 : 0
        }
    }

{'fraction_non_alphanumeric': 0.08316493082543137, 'fraction_numerical': 0.005518420643556661, 'mean_word_length': 2.8489380795692494, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '348843', 'n_tokens_mistral': 3773, 'n_tokens_neox': 3615, 'n_words': 997}