<commit_before>/*
 * Copyright 2009, Google 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:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
 * OWNER OR 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.
 */



#include <GL/glew.h>
#include "plugin_mac.h"
#include "Breakpad.h"
#include <Cocoa/Cocoa.h>
#include <QuickTime/QuickTime.h>
#include "plugin/cross/o3d_glue.h"
#include "plugin/cross/main.h"
#include "core/mac/display_window_mac.h"
#include "plugin/mac/graphics_utils_mac.h"

#if !defined(O3D_INTERNAL_PLUGIN)
BreakpadRef gBreakpadRef =  NULL;
#endif

using glue::_o3d::PluginObject;
using o3d::DisplayWindowMac;

@interface NSWindowController (plugin_hack)
- (id)selectedTab;
@end

namespace o3d {

bool gIsChrome = false;

// Returns the version number of the running Mac browser, as parsed from
// the short version string in the plist of the app's bundle.
bool GetBrowserVersionInfo(int *returned_major,
                           int *returned_minor,
                           int *returned_bugfix) {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  int major = 0;
  int minor = 0;
  int bugfix = 0;
  NSBundle *app_bundle = [NSBundle mainBundle];
  NSString *versionString =
      [app_bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];

  if ([versionString length]) {
    NSScanner *versionScanner = [NSScanner scannerWithString:versionString];
    NSCharacterSet *dotSet =
        [NSCharacterSet characterSetWithCharactersInString:@"."];
    NSCharacterSet *numSet =
        [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
    NSCharacterSet *notNumSet = [numSet invertedSet];

    // Skip anything at start that is not a number.
    [versionScanner scanCharactersFromSet:notNumSet intoString:NULL];

    // Keep reading values until we get all 3 numbers, or something isn't found.
    if ([versionScanner scanInt:&major])
      if ([versionScanner scanCharactersFromSet:dotSet intoString:NULL])
        if ([versionScanner scanInt:&minor])
          if ([versionScanner scanCharactersFromSet:dotSet intoString:NULL])
            [versionScanner scanInt:&bugfix];
  }

  *returned_major = major;
  *returned_minor = minor;
  *returned_bugfix = bugfix;

  [pool release];

  // If we read any version numbers, then we succeeded.
  return (major || minor || bugfix);
}


// Code for peeking at the selected tab object for a WindowRef in Safari.  This
// is purely so we can detect changes in active tab in Safari, since it does not
// notify us when our tab is hidden or revealed.
//
// If the browser is not Safari these functions should harmlessly be NULL since
// the walk from windowref to cocoa window (of type "BrowserWindow") to cocoa
// windowcontroller to selectedTab should harmlessly break down somewhere along
// the way.
//
// This is useful merely for peeking at Safari's internal state for a tab change
// event, as Safari does not notify us when this happens.  It coerces the value
// to a void*, as the plain .cc files don't like the type id, and we actually
// only care whether the value changes or not.


void ReleaseSafariBrowserWindow(void* browserWindow) {
  if (browserWindow) {
    NSWindow* cocoaWindow = (NSWindow*) browserWindow;
    // Retain the WindowRef so it doesn't go away when we release the
    // NSWindow copy we made.
    WindowRef theWindow = (WindowRef)[cocoaWindow windowRef];
    if (theWindow)
      CFRetain(theWindow);
    [cocoaWindow release];
  }
}

void* SafariBrowserWindowForWindowRef(WindowRef theWindow) {
  if (theWindow != NULL) {
    NSWindow* cocoaWindow = [[NSWindow alloc] initWithWindowRef:theWindow];
    if (cocoaWindow) {
      if (strcmp(object_getClassName(cocoaWindow), "BrowserWindow") == 0) {
        return cocoaWindow;
      } else {
        // Retain the WindowRef so it doesn't go away when we release the
        // NSWindow copy we made.
        CFRetain(theWindow);
        [cocoaWindow release];
      }
    }
  }
  return NULL;
}

void* SelectedTabForSafariBrowserWindow(void* browserWindow) {
  id selectedTab = nil;
  NSWindow* cocoaWindow = (NSWindow*) browserWindow;
  if (cocoaWindow) {
    @try {
      selectedTab = [[cocoaWindow windowController] selectedTab];
    } @catch(NSException* exc) {
    }
  }
  return (void*) selectedTab;
}

// Detects when Safari has hidden or revealed our tab.
// If a hide event is detected, it sets the mac_surface_hidden_ flag and hides
// the surface.
// Later, if the mac_surface_hidden_ flag is set but we are no longer hidden,
// ie DetectTabHiding is now returning false, it restores the surface to the
// previous state.
void ManageSafariTabSwitching(PluginObject* obj) {
  // This is only needed when we are using an AGL context and need to hide
  // and show it.
  if (!obj->mac_agl_context_)
    return;

  if (obj->DetectTabHiding()) {
    if (!obj->mac_surface_hidden_) {
      obj->mac_surface_hidden_ = true;
      GLint rect[4] = {0,0,0,0};
      aglSetInteger(obj->mac_agl_context_, AGL_BUFFER_RECT, rect);
      aglEnable(obj->mac_agl_context_, AGL_BUFFER_RECT);
    }
  } else if (obj->mac_surface_hidden_) {
    obj->mac_surface_hidden_ = false;
    aglSetInteger(obj->mac_agl_context_, AGL_BUFFER_RECT,
                  obj->last_buffer_rect_);
    aglEnable(obj->mac_agl_context_, AGL_BUFFER_RECT);
  }
}


#pragma mark ____RenderTimer

RenderTimer gRenderTimer;
std::vector<NPP> RenderTimer::instances_;

void RenderTimer::Start() {
  CFRunLoopTimerContext timerContext;
  memset(&timerContext, 0, sizeof(timerContext));
  timerContext.info = (void*)NULL;

  if (!timerRef_) {
    timerRef_ = CFRunLoopTimerCreate(NULL,
                                     1.0,
                                     1.0 / 60.0,
                                     0,
                                     0,
                                     TimerCallback,
                                     &timerContext);

    CFRunLoopAddTimer(CFRunLoopGetCurrent(), timerRef_, kCFRunLoopCommonModes);
  }
}

void RenderTimer::Stop() {
  if (timerRef_) {
    CFRunLoopTimerInvalidate(timerRef_);
    timerRef_ = NULL;
  }
  instances_.clear();   // this should already be empty, but make sure
}

void RenderTimer::AddInstance(NPP instance) {
  // avoid adding the same instance twice!
  InstanceIterator i = find(instances_.begin(), instances_.end(), instance);
  if (i == instances_.end()) {
    instances_.push_back(instance);
  }
}

void RenderTimer::RemoveInstance(NPP instance) {
  InstanceIterator i = find(instances_.begin(), instances_.end(), instance);
  if (i != instances_.end()) {
    instances_.erase(i);
  }
}

void RenderTimer::TimerCallback(CFRunLoopTimerRef timer, void* info) {
  HANDLE_CRASHES;
  int instance_count = instances_.size();
  for (int i = 0; i < instance_count; ++i) {
    NPP instance = instances_[i];
    PluginObject* obj = static_cast<PluginObject*>(instance->pdata);

    ManageSafariTabSwitching(obj);
    obj->client()->Tick();

    bool in_fullscreen = obj->GetFullscreenMacWindow();

#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG
    if (in_fullscreen) {
      obj->FullscreenIdle();
    }
#endif

    // We're visible if (a) we are in fullscreen mode, (b) our cliprect
    // height and width are both a sensible size, ie > 1 pixel, or (c) if
    // we are rendering to render surfaces (CoreGraphics drawing model,
    // essentially offscreen rendering).
    //
    // We don't check for 0 as we have to size to 1 x 1 on occasion rather than
    // 0 x 0 to avoid crashing the Apple software renderer, but do not want to
    // actually draw to a 1 x 1 pixel area.
    bool plugin_visible = in_fullscreen ||
        (obj->last_buffer_rect_[2] > 1 && obj->last_buffer_rect_[3] > 1) ||
        obj->IsOffscreenRenderingEnabled();

    if (plugin_visible && obj->renderer()) {
      if (obj->client()->render_mode() == o3d::Client::RENDERMODE_CONTINUOUS ||
          obj->renderer()->need_to_render()) {
        // Force a sync to the VBL (once per timer callback)
        // to avoid tearing
        GLint sync = (i == 0);
        if (obj->mac_cgl_context_) {
          CGLSetParameter(obj->mac_cgl_context_, kCGLCPSwapInterval, &sync);
        } else if (obj->mac_agl_context_) {
          aglSetInteger(obj->mac_agl_context_, AGL_SWAP_INTERVAL, &sync);
        }

        if (obj->IsOffscreenRenderingEnabled()) {
          NPRect rect = { 0 };
          rect.bottom = obj->width();
          rect.right = obj->height();
          NPN_InvalidateRect(instance, &rect);
        } else {
          obj->client()->RenderClient(true);
        }
      }<commit_msg>Fixed bug in size of invalid rect. This slipped through in http://code.google.com/p/o3d/issues/detail?id=215 / http://codereview.chromium.org/669220 because of a last minute change to the NPN_InvalidateRect call.<commit_after>/*
 * Copyright 2009, Google 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:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
 * OWNER OR 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.
 */



#include <GL/glew.h>
#include "plugin_mac.h"
#include "Breakpad.h"
#include <Cocoa/Cocoa.h>
#include <QuickTime/QuickTime.h>
#include "plugin/cross/o3d_glue.h"
#include "plugin/cross/main.h"
#include "core/mac/display_window_mac.h"
#include "plugin/mac/graphics_utils_mac.h"

#if !defined(O3D_INTERNAL_PLUGIN)
BreakpadRef gBreakpadRef =  NULL;
#endif

using glue::_o3d::PluginObject;
using o3d::DisplayWindowMac;

@interface NSWindowController (plugin_hack)
- (id)selectedTab;
@end

namespace o3d {

bool gIsChrome = false;

// Returns the version number of the running Mac browser, as parsed from
// the short version string in the plist of the app's bundle.
bool GetBrowserVersionInfo(int *returned_major,
                           int *returned_minor,
                           int *returned_bugfix) {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  int major = 0;
  int minor = 0;
  int bugfix = 0;
  NSBundle *app_bundle = [NSBundle mainBundle];
  NSString *versionString =
      [app_bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];

  if ([versionString length]) {
    NSScanner *versionScanner = [NSScanner scannerWithString:versionString];
    NSCharacterSet *dotSet =
        [NSCharacterSet characterSetWithCharactersInString:@"."];
    NSCharacterSet *numSet =
        [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
    NSCharacterSet *notNumSet = [numSet invertedSet];

    // Skip anything at start that is not a number.
    [versionScanner scanCharactersFromSet:notNumSet intoString:NULL];

    // Keep reading values until we get all 3 numbers, or something isn't found.
    if ([versionScanner scanInt:&major])
      if ([versionScanner scanCharactersFromSet:dotSet intoString:NULL])
        if ([versionScanner scanInt:&minor])
          if ([versionScanner scanCharactersFromSet:dotSet intoString:NULL])
            [versionScanner scanInt:&bugfix];
  }

  *returned_major = major;
  *returned_minor = minor;
  *returned_bugfix = bugfix;

  [pool release];

  // If we read any version numbers, then we succeeded.
  return (major || minor || bugfix);
}


// Code for peeking at the selected tab object for a WindowRef in Safari.  This
// is purely so we can detect changes in active tab in Safari, since it does not
// notify us when our tab is hidden or revealed.
//
// If the browser is not Safari these functions should harmlessly be NULL since
// the walk from windowref to cocoa window (of type "BrowserWindow") to cocoa
// windowcontroller to selectedTab should harmlessly break down somewhere along
// the way.
//
// This is useful merely for peeking at Safari's internal state for a tab change
// event, as Safari does not notify us when this happens.  It coerces the value
// to a void*, as the plain .cc files don't like the type id, and we actually
// only care whether the value changes or not.


void ReleaseSafariBrowserWindow(void* browserWindow) {
  if (browserWindow) {
    NSWindow* cocoaWindow = (NSWindow*) browserWindow;
    // Retain the WindowRef so it doesn't go away when we release the
    // NSWindow copy we made.
    WindowRef theWindow = (WindowRef)[cocoaWindow windowRef];
    if (theWindow)
      CFRetain(theWindow);
    [cocoaWindow release];
  }
}

void* SafariBrowserWindowForWindowRef(WindowRef theWindow) {
  if (theWindow != NULL) {
    NSWindow* cocoaWindow = [[NSWindow alloc] initWithWindowRef:theWindow];
    if (cocoaWindow) {
      if (strcmp(object_getClassName(cocoaWindow), "BrowserWindow") == 0) {
        return cocoaWindow;
      } else {
        // Retain the WindowRef so it doesn't go away when we release the
        // NSWindow copy we made.
        CFRetain(theWindow);
        [cocoaWindow release];
      }
    }
  }
  return NULL;
}

void* SelectedTabForSafariBrowserWindow(void* browserWindow) {
  id selectedTab = nil;
  NSWindow* cocoaWindow = (NSWindow*) browserWindow;
  if (cocoaWindow) {
    @try {
      selectedTab = [[cocoaWindow windowController] selectedTab];
    } @catch(NSException* exc) {
    }
  }
  return (void*) selectedTab;
}

// Detects when Safari has hidden or revealed our tab.
// If a hide event is detected, it sets the mac_surface_hidden_ flag and hides
// the surface.
// Later, if the mac_surface_hidden_ flag is set but we are no longer hidden,
// ie DetectTabHiding is now returning false, it restores the surface to the
// previous state.
void ManageSafariTabSwitching(PluginObject* obj) {
  // This is only needed when we are using an AGL context and need to hide
  // and show it.
  if (!obj->mac_agl_context_)
    return;

  if (obj->DetectTabHiding()) {
    if (!obj->mac_surface_hidden_) {
      obj->mac_surface_hidden_ = true;
      GLint rect[4] = {0,0,0,0};
      aglSetInteger(obj->mac_agl_context_, AGL_BUFFER_RECT, rect);
      aglEnable(obj->mac_agl_context_, AGL_BUFFER_RECT);
    }
  } else if (obj->mac_surface_hidden_) {
    obj->mac_surface_hidden_ = false;
    aglSetInteger(obj->mac_agl_context_, AGL_BUFFER_RECT,
                  obj->last_buffer_rect_);
    aglEnable(obj->mac_agl_context_, AGL_BUFFER_RECT);
  }
}


#pragma mark ____RenderTimer

RenderTimer gRenderTimer;
std::vector<NPP> RenderTimer::instances_;

void RenderTimer::Start() {
  CFRunLoopTimerContext timerContext;
  memset(&timerContext, 0, sizeof(timerContext));
  timerContext.info = (void*)NULL;

  if (!timerRef_) {
    timerRef_ = CFRunLoopTimerCreate(NULL,
                                     1.0,
                                     1.0 / 60.0,
                                     0,
                                     0,
                                     TimerCallback,
                                     &timerContext);

    CFRunLoopAddTimer(CFRunLoopGetCurrent(), timerRef_, kCFRunLoopCommonModes);
  }
}

void RenderTimer::Stop() {
  if (timerRef_) {
    CFRunLoopTimerInvalidate(timerRef_);
    timerRef_ = NULL;
  }
  instances_.clear();   // this should already be empty, but make sure
}

void RenderTimer::AddInstance(NPP instance) {
  // avoid adding the same instance twice!
  InstanceIterator i = find(instances_.begin(), instances_.end(), instance);
  if (i == instances_.end()) {
    instances_.push_back(instance);
  }
}

void RenderTimer::RemoveInstance(NPP instance) {
  InstanceIterator i = find(instances_.begin(), instances_.end(), instance);
  if (i != instances_.end()) {
    instances_.erase(i);
  }
}

void RenderTimer::TimerCallback(CFRunLoopTimerRef timer, void* info) {
  HANDLE_CRASHES;
  int instance_count = instances_.size();
  for (int i = 0; i < instance_count; ++i) {
    NPP instance = instances_[i];
    PluginObject* obj = static_cast<PluginObject*>(instance->pdata);

    ManageSafariTabSwitching(obj);
    obj->client()->Tick();

    bool in_fullscreen = obj->GetFullscreenMacWindow();

#ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG
    if (in_fullscreen) {
      obj->FullscreenIdle();
    }
#endif

    // We're visible if (a) we are in fullscreen mode, (b) our cliprect
    // height and width are both a sensible size, ie > 1 pixel, or (c) if
    // we are rendering to render surfaces (CoreGraphics drawing model,
    // essentially offscreen rendering).
    //
    // We don't check for 0 as we have to size to 1 x 1 on occasion rather than
    // 0 x 0 to avoid crashing the Apple software renderer, but do not want to
    // actually draw to a 1 x 1 pixel area.
    bool plugin_visible = in_fullscreen ||
        (obj->last_buffer_rect_[2] > 1 && obj->last_buffer_rect_[3] > 1) ||
        obj->IsOffscreenRenderingEnabled();

    if (plugin_visible && obj->renderer()) {
      if (obj->client()->render_mode() == o3d::Client::RENDERMODE_CONTINUOUS ||
          obj->renderer()->need_to_render()) {
        // Force a sync to the VBL (once per timer callback)
        // to avoid tearing
        GLint sync = (i == 0);
        if (obj->mac_cgl_context_) {
          CGLSetParameter(obj->mac_cgl_context_, kCGLCPSwapInterval, &sync);
        } else if (obj->mac_agl_context_) {
          aglSetInteger(obj->mac_agl_context_, AGL_SWAP_INTERVAL, &sync);
        }

        if (obj->IsOffscreenRenderingEnabled()) {
          NPRect rect = { 0 };
          rect.bottom = obj->height();
          rect.right = obj->width();
          NPN_InvalidateRect(instance, &rect);
        } else {
          obj->client()->RenderClient(true);
        }
      }
{'fraction_non_alphanumeric': 0.09529967669733896, 'fraction_numerical': 0.006068142253170853, 'mean_word_length': 3.238195615514334, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 85, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1526792', 'n_tokens_mistral': 6109, 'n_tokens_neox': 5812, 'n_words': 1940}