<commit_before>/*****************************************************************************
 * Copyright (C) 2011-2014 Michael Ira Krufky
 *
 * Author: Michael Ira Krufky <mkrufky@linuxtv.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <stdlib.h>
#include "channels.h"

static int atsc_vsb_base_offset(const unsigned int channel)
{
	int base_offset;

	if (channel < 5)
		base_offset = 45000000;
	else if (channel < 7)
		base_offset = 49000000;
	else if (channel < 14)
		base_offset = 135000000;
	else
		base_offset = 389000000;

	return base_offset;
}

static int atsc_qam_base_offset(const unsigned int channel)
{
	int base_offset;

	if (channel < 5)
		base_offset = 45000000;
	else if (channel < 7)
		base_offset = 49000000;
	else if (channel < 14)
		base_offset = 135000000;
	else if (channel < 17)
		base_offset = 39012500;
	else if (channel < 23)
		base_offset = 39000000;
	else if (channel < 25)
		base_offset = 81000000;
	else if (channel < 54)
		base_offset = 81012500;
	else if (channel < 95)
		base_offset = 81000000;
	else if (channel < 98)
		base_offset = -477000000;
	else if (channel < 100)
		base_offset = -476987500;
	else
		base_offset = 51000000;

	return base_offset;
}

static int dvbt_base_offset(const unsigned int channel)
{
	int base_offset;

	if (channel < 13)
		base_offset = 142500000;
	else if (channel < 70)
		base_offset = 306000000;
	else
		base_offset = 0; /* FIXME */

	return base_offset;
}

unsigned int atsc_vsb_chan_to_freq(const unsigned int channel)
{
	return (unsigned int)((int)channel*6000000 + atsc_vsb_base_offset(channel));
}

unsigned int atsc_qam_chan_to_freq(const unsigned int channel)
{
	return (unsigned int)((int)channel*6000000 + atsc_qam_base_offset(channel));
}

unsigned int atsc_vsb_freq_to_chan(const unsigned int frequency)
{
	for (int channel=2; channel <= 69; channel++) {
		if (abs(atsc_vsb_chan_to_freq(channel) - frequency) < 1000000)
			return channel;
	}
	return 0;
}

unsigned int atsc_qam_freq_to_chan(const unsigned int frequency)
{
	for (int channel=2; channel <= 133; channel++) {
		if (abs(atsc_qam_chan_to_freq(channel) == frequency) < 1000000)
			return channel;
	}
	return 0;
}

#if 0
#define VHF_LOWER_FREQUENCY 177500 /* channel 5 */
#define VHF_UPPER_FREQUENCY 226500 /* channel 12 */
#define UHF_LOWER_FREQUENCY 474000 /* channel 21 */
#define UHF_UPPER_FREQUENCY 858000 /* channel 69 */
#endif
unsigned int dvbt_chan_to_freq(const unsigned int channel)
{
	return (unsigned int)((int)channel* ((channel <= 12) ? 7000000 : 8000000) + dvbt_base_offset(channel));
}

unsigned int dvbt_freq_to_chan(const unsigned int frequency)
{
	for (int channel=5; channel <= 69; channel++) {
		if (abs(dvbt_chan_to_freq(channel) - frequency) < 1000000)
			return channel;
	}
	return 0;
}
<commit_msg>channels: fix typo: should be '-' rather than '=='<commit_after>/*****************************************************************************
 * Copyright (C) 2011-2014 Michael Ira Krufky
 *
 * Author: Michael Ira Krufky <mkrufky@linuxtv.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <stdlib.h>
#include "channels.h"

static int atsc_vsb_base_offset(const unsigned int channel)
{
	int base_offset;

	if (channel < 5)
		base_offset = 45000000;
	else if (channel < 7)
		base_offset = 49000000;
	else if (channel < 14)
		base_offset = 135000000;
	else
		base_offset = 389000000;

	return base_offset;
}

static int atsc_qam_base_offset(const unsigned int channel)
{
	int base_offset;

	if (channel < 5)
		base_offset = 45000000;
	else if (channel < 7)
		base_offset = 49000000;
	else if (channel < 14)
		base_offset = 135000000;
	else if (channel < 17)
		base_offset = 39012500;
	else if (channel < 23)
		base_offset = 39000000;
	else if (channel < 25)
		base_offset = 81000000;
	else if (channel < 54)
		base_offset = 81012500;
	else if (channel < 95)
		base_offset = 81000000;
	else if (channel < 98)
		base_offset = -477000000;
	else if (channel < 100)
		base_offset = -476987500;
	else
		base_offset = 51000000;

	return base_offset;
}

static int dvbt_base_offset(const unsigned int channel)
{
	int base_offset;

	if (channel < 13)
		base_offset = 142500000;
	else if (channel < 70)
		base_offset = 306000000;
	else
		base_offset = 0; /* FIXME */

	return base_offset;
}

unsigned int atsc_vsb_chan_to_freq(const unsigned int channel)
{
	return (unsigned int)((int)channel*6000000 + atsc_vsb_base_offset(channel));
}

unsigned int atsc_qam_chan_to_freq(const unsigned int channel)
{
	return (unsigned int)((int)channel*6000000 + atsc_qam_base_offset(channel));
}

unsigned int atsc_vsb_freq_to_chan(const unsigned int frequency)
{
	for (int channel=2; channel <= 69; channel++) {
		if (abs(atsc_vsb_chan_to_freq(channel) - frequency) < 1000000)
			return channel;
	}
	return 0;
}

unsigned int atsc_qam_freq_to_chan(const unsigned int frequency)
{
	for (int channel=2; channel <= 133; channel++) {
		if (abs(atsc_qam_chan_to_freq(channel) - frequency) < 1000000)
			return channel;
	}
	return 0;
}

#if 0
#define VHF_LOWER_FREQUENCY 177500 /* channel 5 */
#define VHF_UPPER_FREQUENCY 226500 /* channel 12 */
#define UHF_LOWER_FREQUENCY 474000 /* channel 21 */
#define UHF_UPPER_FREQUENCY 858000 /* channel 69 */
#endif
unsigned int dvbt_chan_to_freq(const unsigned int channel)
{
	return (unsigned int)((int)channel* ((channel <= 12) ? 7000000 : 8000000) + dvbt_base_offset(channel));
}

unsigned int dvbt_freq_to_chan(const unsigned int frequency)
{
	for (int channel=5; channel <= 69; channel++) {
		if (abs(dvbt_chan_to_freq(channel) - frequency) < 1000000)
			return channel;
	}
	return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: aqua_clipboard.cxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dtrans.hxx"
#include "aqua_clipboard.hxx"

#include "DataFlavorMapping.hxx"
#include "OSXTransferable.hxx"

#ifndef COMPHELPER_MAKESEQUENCE_HXX_INCLUDED
#include "comphelper/makesequence.hxx"
#endif

#include <boost/assert.hpp>

using namespace com::sun::star::datatransfer;
using namespace com::sun::star::datatransfer::clipboard;
using namespace com::sun::star::lang;
using namespace com::sun::star::uno;
using namespace cppu;
using namespace osl;
using namespace rtl;
using namespace std;
using namespace comphelper;

@implementation EventListener;

-(EventListener*)initWithAquaClipboard: (AquaClipboard*) pcb
{
  self = [super init];

  if (self)
    {
      pAquaClipboard = pcb;
    }

  return self;
}

-(void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString*)type
{
  pAquaClipboard->provideDataForType(sender, type);
}

-(void)applicationDidBecomeActive:(NSNotification*)aNotification
{
  pAquaClipboard->applicationDidBecomeActive(aNotification);
}

@end

OUString clipboard_getImplementationName()
{
  return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.clipboard.AquaClipboard"));
}

Sequence<OUString> clipboard_getSupportedServiceNames()
{
  return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.clipboard.SystemClipboard")));
}

AquaClipboard::AquaClipboard(const Reference< XComponentContext >& context, NSPasteboard* pasteboard, bool bUseSystemPasteboard) :
  WeakComponentImplHelper4<XClipboardEx, XClipboardNotifier, XFlushableClipboard, XServiceInfo>(m_aMutex),
  mXComponentContext(context),
  mIsSystemPasteboard(bUseSystemPasteboard)
{
  Reference<XMultiComponentFactory> mrServiceMgr = mXComponentContext->getServiceManager();

  mrXMimeCntFactory = Reference<XMimeContentTypeFactory>(mrServiceMgr->createInstanceWithContext(
     OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.MimeContentTypeFactory")), mXComponentContext), UNO_QUERY);

  if (!mrXMimeCntFactory.is())
    {
      throw RuntimeException(OUString(
            RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create com.sun.star.datatransfer.MimeContentTypeFactory")),
            static_cast<XClipboardEx*>(this));
    }

  mpDataFlavorMapper = DataFlavorMapperPtr_t(new DataFlavorMapper(mXComponentContext));

  if (pasteboard != NULL)
    {
      mPasteboard = pasteboard;
      mIsSystemPasteboard = false;
    }
  else
    {
      mPasteboard = bUseSystemPasteboard ? [NSPasteboard generalPasteboard] :
        [NSPasteboard pasteboardWithName: NSDragPboard];

      if (mPasteboard == nil)
        {
          throw RuntimeException(OUString(
                RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create Cocoa pasteboard")),
                static_cast<XClipboardEx*>(this));
        }
    }

  [mPasteboard retain];

  mEventListener = [[EventListener alloc] initWithAquaClipboard: this];

  if (mEventListener == nil)
    {
      [mPasteboard release];

      throw RuntimeException(
            OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create pasteboard change listener")),
            static_cast<XClipboardEx*>(this));
    }

  if (mIsSystemPasteboard)
    {
      NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];

      [notificationCenter addObserver: mEventListener
       selector: @selector(applicationDidBecomeActive:)
       name: @"NSApplicationDidBecomeActiveNotification"
       object: [NSApplication sharedApplication]];
    }

  mPasteboardChangeCount = [mPasteboard changeCount];
}

AquaClipboard::~AquaClipboard()
{
  if (mIsSystemPasteboard)
    {
      [[NSNotificationCenter defaultCenter] removeObserver: mEventListener];
    }

  [mEventListener release];
  [mPasteboard release];
}

Reference<XTransferable> SAL_CALL AquaClipboard::getContents() throw(RuntimeException)
{
  MutexGuard aGuard(m_aMutex);

  // Shortcut: If we are clipboard owner already we don't need
  // to drag the data through the system clipboard
  if (mXClipboardContent.is())
    {
      return mXClipboardContent;
    }

  return Reference<XTransferable>(new OSXTransferable(mXComponentContext,
                                                      mrXMimeCntFactory,
                                                      mpDataFlavorMapper,
                                                      mPasteboard));
}

void SAL_CALL AquaClipboard::setContents(const Reference<XTransferable>& xTransferable,
                                         const Reference<XClipboardOwner>& xClipboardOwner)
  throw( RuntimeException )
{
  ClearableMutexGuard aGuard(m_aMutex);

  Reference<XClipboardOwner> oldOwner(mXClipboardOwner);
  mXClipboardOwner = xClipboardOwner;

  Reference<XTransferable> oldContent(mXClipboardContent);
  mXClipboardContent = xTransferable;

  NSArray* types = mpDataFlavorMapper->flavorSequenceToTypesArray(mXClipboardContent->getTransferDataFlavors());
  mPasteboardChangeCount = [mPasteboard declareTypes: types owner: mEventListener];

  // if we are already the owner of the clipboard
  // then fire lost ownership event
  if (oldOwner.is())
    {
      fireLostClipboardOwnershipEvent(oldOwner, oldContent);
    }

  fireClipboardChangedEvent();
}

OUString SAL_CALL AquaClipboard::getName() throw( RuntimeException )
{
  return OUString();
}

sal_Int8 SAL_CALL AquaClipboard::getRenderingCapabilities() throw( RuntimeException )
{
    return 0;
}

void SAL_CALL AquaClipboard::addClipboardListener(const Reference< XClipboardListener >& listener)
  throw( RuntimeException )
{
  MutexGuard aGuard(m_aMutex);

  if (!listener.is())
     throw IllegalArgumentException(OUString(RTL_CONSTASCII_USTRINGPARAM("empty reference")),
                                   static_cast<XClipboardEx*>(this), 1);

  mClipboardListeners.push_back(listener);
}

void SAL_CALL AquaClipboard::removeClipboardListener(const Reference< XClipboardListener >& listener)
  throw( RuntimeException )
{
  MutexGuard aGuard(m_aMutex);

  if (!listener.is())
     throw IllegalArgumentException(OUString(RTL_CONSTASCII_USTRINGPARAM("empty reference")),
                                   static_cast<XClipboardEx*>(this), 1);

  mClipboardListeners.remove(listener);
}

void AquaClipboard::applicationDidBecomeActive(NSNotification* aNotification)
{
  MutexGuard aGuard(m_aMutex);

  int currentPboardChgCount = [mPasteboard changeCount];

  if (currentPboardChgCount != mPasteboardChangeCount)
    {
      mPasteboardChangeCount = currentPboardChgCount;

      // Clear clipboard content and owner and send lostOwnership
      // notification to the old clipboard owner as well as
      // ClipboardChanged notification to any clipboard listener
      Reference<XClipboardOwner> oldOwner(mXClipboardOwner);
      mXClipboardOwner = Reference<XClipboardOwner>();

      Reference<XTransferable> oldContent(mXClipboardContent);
      mXClipboardContent = Reference<XTransferable>();

      if (oldOwner.is())
        {
          fireLostClipboardOwnershipEvent(oldOwner, oldContent);
        }

      fireClipboardChangedEvent();
    }
}

void AquaClipboard::fireClipboardChangedEvent()
{
    ClearableMutexGuard aGuard(m_aMutex);

    list<Reference< XClipboardListener > > listeners(mClipboardListeners);
    ClipboardEvent aEvent;

    if (listeners.begin() != listeners.end())
      {
        aEvent = ClipboardEvent(static_cast<OWeakObject*>(this), getContents());
      }

    aGuard.clear();

    while (listeners.begin() != listeners.end())
    {
        if (listeners.front().is())
          {
            try { listeners.front()->changedContents(aEvent); }
            catch (RuntimeException&) { }
          }
        listeners.pop_front();
    }
}

void AquaClipboard::fireLostClipboardOwnershipEvent(Reference<XClipboardOwner> oldOwner, Reference<XTransferable> oldContent)
{
  BOOST_ASSERT(oldOwner.is());

  try { oldOwner->lostOwnership(static_cast<XClipboardEx*>(this), oldContent); }
  catch(RuntimeException&) { }
}

void AquaClipboard::provideDataForType(NSPasteboard* sender, NSString* type)
{
  DataProviderPtr_t dp = mpDataFlavorMapper->getDataProvider(type, mXClipboardContent);
  NSData* pBoardData = (NSData*)dp->getSystemData();
  [sender setData: pBoardData forType: type];
}

//------------------------------------------------
// XFlushableClipboard
//------------------------------------------------

void SAL_CALL AquaClipboard::flushClipboard()
  throw(RuntimeException)
{
  if (mXClipboardContent.is())
    {
          Sequence<DataFlavor> flavorList = mXClipboardContent->getTransferDataFlavors();
        sal_uInt32 nFlavors = flavorList.getLength();

        for (sal_uInt32 i = 0; i < nFlavors; i++)
          {
            NSString* sysType = mpDataFlavorMapper->openOfficeToSystemFlavor(flavorList[i]);

            if (sysType != NULL)
              {
                provideDataForType(mPasteboard, sysType);
              }
          }
    }
}

NSPasteboard* AquaClipboard::getPasteboard() const
{
  return mPasteboard;
}

//-------------------------------------------------
// XServiceInfo
//-------------------------------------------------

OUString SAL_CALL AquaClipboard::getImplementationName() throw( RuntimeException )
{
  return clipboard_getImplementationName();
}

sal_Bool SAL_CALL AquaClipboard::supportsService( const OUString& ServiceName ) throw( RuntimeException )
{
    return sal_False;
}

Sequence< OUString > SAL_CALL AquaClipboard::getSupportedServiceNames() throw( RuntimeException )
{
  return clipboard_getSupportedServiceNames();
}

<commit_msg>INTEGRATION: CWS aquavcl07 (1.6.8); FILE MERGED 2008/04/17 05:39:39 pl 1.6.8.2: RESYNC: (1.6-1.7); FILE MERGED 2008/04/16 12:07:10 pl 1.6.8.1: #i87595# don not call on destroyed objects<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: aqua_clipboard.cxx,v $
 * $Revision: 1.8 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dtrans.hxx"
#include "aqua_clipboard.hxx"

#include "DataFlavorMapping.hxx"
#include "OSXTransferable.hxx"

#ifndef COMPHELPER_MAKESEQUENCE_HXX_INCLUDED
#include "comphelper/makesequence.hxx"
#endif

#include <boost/assert.hpp>

using namespace com::sun::star::datatransfer;
using namespace com::sun::star::datatransfer::clipboard;
using namespace com::sun::star::lang;
using namespace com::sun::star::uno;
using namespace cppu;
using namespace osl;
using namespace rtl;
using namespace std;
using namespace comphelper;

@implementation EventListener;

-(EventListener*)initWithAquaClipboard: (AquaClipboard*) pcb
{
    self = [super init];

    if (self)
        pAquaClipboard = pcb;

    return self;
}

-(void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString*)type
{
    if( pAquaClipboard )
        pAquaClipboard->provideDataForType(sender, type);
}

-(void)applicationDidBecomeActive:(NSNotification*)aNotification
{
    if( pAquaClipboard )
        pAquaClipboard->applicationDidBecomeActive(aNotification);
}

-(void)disposing
{
    pAquaClipboard = NULL;
}

@end

OUString clipboard_getImplementationName()
{
  return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.clipboard.AquaClipboard"));
}

Sequence<OUString> clipboard_getSupportedServiceNames()
{
  return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.clipboard.SystemClipboard")));
}

AquaClipboard::AquaClipboard(const Reference< XComponentContext >& context, NSPasteboard* pasteboard, bool bUseSystemPasteboard) :
  WeakComponentImplHelper4<XClipboardEx, XClipboardNotifier, XFlushableClipboard, XServiceInfo>(m_aMutex),
  mXComponentContext(context),
  mIsSystemPasteboard(bUseSystemPasteboard)
{
  Reference<XMultiComponentFactory> mrServiceMgr = mXComponentContext->getServiceManager();

  mrXMimeCntFactory = Reference<XMimeContentTypeFactory>(mrServiceMgr->createInstanceWithContext(
     OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.MimeContentTypeFactory")), mXComponentContext), UNO_QUERY);

  if (!mrXMimeCntFactory.is())
    {
      throw RuntimeException(OUString(
            RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create com.sun.star.datatransfer.MimeContentTypeFactory")),
            static_cast<XClipboardEx*>(this));
    }

  mpDataFlavorMapper = DataFlavorMapperPtr_t(new DataFlavorMapper(mXComponentContext));

  if (pasteboard != NULL)
    {
      mPasteboard = pasteboard;
      mIsSystemPasteboard = false;
    }
  else
    {
      mPasteboard = bUseSystemPasteboard ? [NSPasteboard generalPasteboard] :
        [NSPasteboard pasteboardWithName: NSDragPboard];

      if (mPasteboard == nil)
        {
          throw RuntimeException(OUString(
                RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create Cocoa pasteboard")),
                static_cast<XClipboardEx*>(this));
        }
    }

  [mPasteboard retain];

  mEventListener = [[EventListener alloc] initWithAquaClipboard: this];

  if (mEventListener == nil)
    {
      [mPasteboard release];

      throw RuntimeException(
            OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create pasteboard change listener")),
            static_cast<XClipboardEx*>(this));
    }

  if (mIsSystemPasteboard)
    {
      NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];

      [notificationCenter addObserver: mEventListener
       selector: @selector(applicationDidBecomeActive:)
       name: @"NSApplicationDidBecomeActiveNotification"
       object: [NSApplication sharedApplication]];
    }

  mPasteboardChangeCount = [mPasteboard changeCount];
}

AquaClipboard::~AquaClipboard()
{
  if (mIsSystemPasteboard)
    {
      [[NSNotificationCenter defaultCenter] removeObserver: mEventListener];
    }

  [mEventListener disposing];
  [mEventListener release];
  [mPasteboard release];
}

Reference<XTransferable> SAL_CALL AquaClipboard::getContents() throw(RuntimeException)
{
  MutexGuard aGuard(m_aMutex);

  // Shortcut: If we are clipboard owner already we don't need
  // to drag the data through the system clipboard
  if (mXClipboardContent.is())
    {
      return mXClipboardContent;
    }

  return Reference<XTransferable>(new OSXTransferable(mXComponentContext,
                                                      mrXMimeCntFactory,
                                                      mpDataFlavorMapper,
                                                      mPasteboard));
}

void SAL_CALL AquaClipboard::setContents(const Reference<XTransferable>& xTransferable,
                                         const Reference<XClipboardOwner>& xClipboardOwner)
  throw( RuntimeException )
{
  ClearableMutexGuard aGuard(m_aMutex);

  Reference<XClipboardOwner> oldOwner(mXClipboardOwner);
  mXClipboardOwner = xClipboardOwner;

  Reference<XTransferable> oldContent(mXClipboardContent);
  mXClipboardContent = xTransferable;

  NSArray* types = mpDataFlavorMapper->flavorSequenceToTypesArray(mXClipboardContent->getTransferDataFlavors());
  mPasteboardChangeCount = [mPasteboard declareTypes: types owner: mEventListener];

  // if we are already the owner of the clipboard
  // then fire lost ownership event
  if (oldOwner.is())
    {
      fireLostClipboardOwnershipEvent(oldOwner, oldContent);
    }

  fireClipboardChangedEvent();
}

OUString SAL_CALL AquaClipboard::getName() throw( RuntimeException )
{
  return OUString();
}

sal_Int8 SAL_CALL AquaClipboard::getRenderingCapabilities() throw( RuntimeException )
{
    return 0;
}

void SAL_CALL AquaClipboard::addClipboardListener(const Reference< XClipboardListener >& listener)
  throw( RuntimeException )
{
  MutexGuard aGuard(m_aMutex);

  if (!listener.is())
     throw IllegalArgumentException(OUString(RTL_CONSTASCII_USTRINGPARAM("empty reference")),
                                   static_cast<XClipboardEx*>(this), 1);

  mClipboardListeners.push_back(listener);
}

void SAL_CALL AquaClipboard::removeClipboardListener(const Reference< XClipboardListener >& listener)
  throw( RuntimeException )
{
  MutexGuard aGuard(m_aMutex);

  if (!listener.is())
     throw IllegalArgumentException(OUString(RTL_CONSTASCII_USTRINGPARAM("empty reference")),
                                   static_cast<XClipboardEx*>(this), 1);

  mClipboardListeners.remove(listener);
}

void AquaClipboard::applicationDidBecomeActive(NSNotification* aNotification)
{
  MutexGuard aGuard(m_aMutex);

  int currentPboardChgCount = [mPasteboard changeCount];

  if (currentPboardChgCount != mPasteboardChangeCount)
    {
      mPasteboardChangeCount = currentPboardChgCount;

      // Clear clipboard content and owner and send lostOwnership
      // notification to the old clipboard owner as well as
      // ClipboardChanged notification to any clipboard listener
      Reference<XClipboardOwner> oldOwner(mXClipboardOwner);
      mXClipboardOwner = Reference<XClipboardOwner>();

      Reference<XTransferable> oldContent(mXClipboardContent);
      mXClipboardContent = Reference<XTransferable>();

      if (oldOwner.is())
        {
          fireLostClipboardOwnershipEvent(oldOwner, oldContent);
        }

      fireClipboardChangedEvent();
    }
}

void AquaClipboard::fireClipboardChangedEvent()
{
    ClearableMutexGuard aGuard(m_aMutex);

    list<Reference< XClipboardListener > > listeners(mClipboardListeners);
    ClipboardEvent aEvent;

    if (listeners.begin() != listeners.end())
      {
        aEvent = ClipboardEvent(static_cast<OWeakObject*>(this), getContents());
      }

    aGuard.clear();

    while (listeners.begin() != listeners.end())
    {
        if (listeners.front().is())
          {
            try { listeners.front()->changedContents(aEvent); }
            catch (RuntimeException&) { }
          }
        listeners.pop_front();
    }
}

void AquaClipboard::fireLostClipboardOwnershipEvent(Reference<XClipboardOwner> oldOwner, Reference<XTransferable> oldContent)
{
  BOOST_ASSERT(oldOwner.is());

  try { oldOwner->lostOwnership(static_cast<XClipboardEx*>(this), oldContent); }
  catch(RuntimeException&) { }
}

void AquaClipboard::provideDataForType(NSPasteboard* sender, NSString* type)
{
  DataProviderPtr_t dp = mpDataFlavorMapper->getDataProvider(type, mXClipboardContent);
  NSData* pBoardData = (NSData*)dp->getSystemData();
  [sender setData: pBoardData forType: type];
}

//------------------------------------------------
// XFlushableClipboard
//------------------------------------------------

void SAL_CALL AquaClipboard::flushClipboard()
  throw(RuntimeException)
{
  if (mXClipboardContent.is())
    {
          Sequence<DataFlavor> flavorList = mXClipboardContent->getTransferDataFlavors();
        sal_uInt32 nFlavors = flavorList.getLength();

        for (sal_uInt32 i = 0; i < nFlavors; i++)
          {
            NSString* sysType = mpDataFlavorMapper->openOfficeToSystemFlavor(flavorList[i]);

            if (sysType != NULL)
              {
                provideDataForType(mPasteboard, sysType);
              }
          }
    }
}

NSPasteboard* AquaClipboard::getPasteboard() const
{
  return mPasteboard;
}

//-------------------------------------------------
// XServiceInfo
//-------------------------------------------------

OUString SAL_CALL AquaClipboard::getImplementationName() throw( RuntimeException )
{
  return clipboard_getImplementationName();
}

sal_Bool SAL_CALL AquaClipboard::supportsService( const OUString& ServiceName ) throw( RuntimeException )
{
    return sal_False;
}

Sequence< OUString > SAL_CALL AquaClipboard::getSupportedServiceNames() throw( RuntimeException )
{
  return clipboard_getSupportedServiceNames();
}

<|endoftext|>


<commit_before>/*
    Copyright (C) 1998,2000 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include "cssysdef.h"
#include "csutil/parser.h"

// A string containing white spaces (' ', '\t', '\n', '\r')
static const char *kWhiteSpace = " \t\n\r";
static char last_offender[255];
static int parser_line;

char* csGetLastOffender () { return last_offender; }
int   csGetParserLine   () { return parser_line;   }
void  csResetParserLine () { parser_line = 1;      }

long csGetObject (char **buf, csTokenVector * tokens, char **name, char **data)
{
  csSkipCharacters (buf, kWhiteSpace);

  // skip comment lines.
  while (**buf == ';')
  {
    *buf = strchr (*buf, '\n');
    parser_line++;
    csSkipCharacters (buf, kWhiteSpace);
  }

  if (!**buf)                   // at end of file
    return CS_PARSERR_EOF;

  // find the token.
  // for now just use brute force.  Improve later.
  int i=0;
  for (i=0; i < tokens->Length ()-1; i++)
  {
    if (!strncasecmp (tokens->Get (i)->token, *buf, strlen (tokens->Get (i)->token)))
    {
      break;
    }
  }

  if (i+1 == tokens->Length ())
  {
    char *p = strchr (*buf, '\n');
    if (p) *p = 0;
    strcpy (last_offender, *buf);
    return CS_PARSERR_TOKENNOTFOUND;
  }
  // skip the token
  *buf += strlen (tokens->Get (i)->token);
  csSkipCharacters (buf, kWhiteSpace);

  // get optional name
  *name = csGetSubText (buf, '\'', '\''); // single quotes
  csSkipCharacters (buf, kWhiteSpace);

  // get optional data
  if (**buf == '=') // An assignment rather than a command/object.
    *data = csGetAssignmentText (buf);
  else
    *data = csGetSubText (buf, '(', ')');

  return tokens->Get (i)->id;
}

long csGetCommand (char **buf, csTokenVector * tokens, char **params)
{
  char *name;
  return csGetObject (buf, tokens, &name, params);
}

void csSkipCharacters (char **buf, const char *toSkip)
{
  char ch;
  while ((ch = **buf) != 0)
  {
    if (ch == '\n') parser_line++;
    if (strchr (toSkip, ch) == NULL)
      return;
    ++*buf;                     // skip this character
  }
  // we must be at the end of the buffer if we get here
}

char *csGetSubText (char **buf, char open, char close)
{
  if (**buf == 0 || **buf != open)
    return 0;
  ++*buf;                       // skip opening delimiter
  char *result = *buf;

  // now find the closing delimiter
  char theChar;
  long skip = 1;

  if (open == close)            // we cant nest identical delimiters
    open = 0;
  while ((theChar = **buf) != 0)
  {
    if (theChar == open)
      ++skip;
    if (theChar == close)
    {
      if (--skip == 0)
      {
        **buf = 0;              // null terminate the result string
        ++*buf;                 // move past the closing delimiter
        break;
      }
    }
    ++*buf;                     // try next character
  }
  return result;
}

char *csGetAssignmentText (char **buf)
{
  ++*buf;                       // skip the '='
  csSkipCharacters (buf, kWhiteSpace);
  char *result = *buf;

  // now, we need to find the next whitespace to end the data
  char theChar;

  while ((theChar = **buf) != 0)
  {
    if (theChar <= 0x20)        // space and control chars
      break;
    ++*buf;
  }
  **buf = 0;                    // null terminate it
  if (theChar)                  // skip the terminator
    ++*buf;
  return result;
}
<commit_msg>let the parser return -1 for now... this is still better than bogus values<commit_after>/*
    Copyright (C) 1998,2000 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include "cssysdef.h"
#include "csutil/parser.h"

// A string containing white spaces (' ', '\t', '\n', '\r')
static const char *kWhiteSpace = " \t\n\r";
static char last_offender[255];
static int parser_line;

char* csGetLastOffender () { return last_offender; }

// XXX: Here we have a problem: the parser_line variable is static and
// therefor not shared across plugins, because the real fix (moving everything
// into a class) takes time, we'll just always return -1 now...
//int   csGetParserLine   () { return parser_line;   }
int csGetParserLine() { return -1; }

void  csResetParserLine () { parser_line = 1;      }

long csGetObject (char **buf, csTokenVector * tokens, char **name, char **data)
{
  csSkipCharacters (buf, kWhiteSpace);

  // skip comment lines.
  while (**buf == ';')
  {
    *buf = strchr (*buf, '\n');
    parser_line++;
    csSkipCharacters (buf, kWhiteSpace);
  }

  if (!**buf)                   // at end of file
    return CS_PARSERR_EOF;

  // find the token.
  // for now just use brute force.  Improve later.
  int i=0;
  for (i=0; i < tokens->Length ()-1; i++)
  {
    if (!strncasecmp (tokens->Get (i)->token, *buf, strlen (tokens->Get (i)->token)))
    {
      break;
    }
  }

  if (i+1 == tokens->Length ())
  {
    char *p = strchr (*buf, '\n');
    if (p) *p = 0;
    strcpy (last_offender, *buf);
    return CS_PARSERR_TOKENNOTFOUND;
  }
  // skip the token
  *buf += strlen (tokens->Get (i)->token);
  csSkipCharacters (buf, kWhiteSpace);

  // get optional name
  *name = csGetSubText (buf, '\'', '\''); // single quotes
  csSkipCharacters (buf, kWhiteSpace);

  // get optional data
  if (**buf == '=') // An assignment rather than a command/object.
    *data = csGetAssignmentText (buf);
  else
    *data = csGetSubText (buf, '(', ')');

  return tokens->Get (i)->id;
}

long csGetCommand (char **buf, csTokenVector * tokens, char **params)
{
  char *name;
  return csGetObject (buf, tokens, &name, params);
}

void csSkipCharacters (char **buf, const char *toSkip)
{
  char ch;
  while ((ch = **buf) != 0)
  {
    if (ch == '\n') parser_line++;
    if (strchr (toSkip, ch) == NULL)
      return;
    ++*buf;                     // skip this character
  }
  // we must be at the end of the buffer if we get here
}

char *csGetSubText (char **buf, char open, char close)
{
  if (**buf == 0 || **buf != open)
    return 0;
  ++*buf;                       // skip opening delimiter
  char *result = *buf;

  // now find the closing delimiter
  char theChar;
  long skip = 1;

  if (open == close)            // we cant nest identical delimiters
    open = 0;
  while ((theChar = **buf) != 0)
  {
    if (theChar == open)
      ++skip;
    if (theChar == close)
    {
      if (--skip == 0)
      {
        **buf = 0;              // null terminate the result string
        ++*buf;                 // move past the closing delimiter
        break;
      }
    }
    ++*buf;                     // try next character
  }
  return result;
}

char *csGetAssignmentText (char **buf)
{
  ++*buf;                       // skip the '='
  csSkipCharacters (buf, kWhiteSpace);
  char *result = *buf;

  // now, we need to find the next whitespace to end the data
  char theChar;

  while ((theChar = **buf) != 0)
  {
    if (theChar <= 0x20)        // space and control chars
      break;
    ++*buf;
  }
  **buf = 0;                    // null terminate it
  if (theChar)                  // skip the terminator
    ++*buf;
  return result;
}
<|endoftext|>


<commit_before>/* Copyright (c) 2017-2020 Hans-Kristian Arntzen
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "transforms.hpp"
#include "aabb.hpp"
#include "simd.hpp"
#include "muglm/matrix_helper.hpp"
#include <assert.h>

namespace Granite
{
bool compute_plane_reflection(mat4 &projection, mat4 &view, vec3 camera_pos, vec3 center, vec3 normal, vec3 look_up,
                              float radius_up, float radius_other, float &z_near, float z_far)
{
	normal = normalize(normal);

	// Reflect the camera position from the plane.
	float over_plane = dot(normal, camera_pos - center);
	if (over_plane <= 0.0f)
		return false;

	camera_pos -= 2.0f * over_plane * normal;

	// The look direction is up through the plane direction.
	// This way we avoid skewed near and far planes (i.e. oblique).
	// Make sure look_up is perpendicular to normal.
	vec3 look_pos_x = normalize(cross(normal, look_up));
	look_up = normalize(cross(look_pos_x, normal));

	view = mat4_cast(look_at(normal, look_up)) * translate(-camera_pos);

	float dist_x = dot(look_pos_x, center - camera_pos);
	float left = dist_x - radius_other;
	float right = dist_x + radius_other;

	float dist_y = dot(look_up, center - camera_pos);
	float bottom = dist_y - radius_up;
	float top = dist_y + radius_up;

	z_near = over_plane;
	projection = frustum(left, right, bottom, top, over_plane, z_far);
	if (z_near >= z_far)
		return false;
	return true;
}

bool compute_plane_refraction(mat4 &projection, mat4 &view, vec3 camera_pos, vec3 center, vec3 normal, vec3 look_up,
                              float radius_up, float radius_other, float &z_near, float z_far)
{
	normal = normalize(normal);

	// Reflect the camera position from the plane.
	float over_plane = dot(normal, camera_pos - center);
	if (over_plane <= 0.0f)
		return false;

	normal = -normal;

	// The look direction is up through the plane direction.
	// This way we avoid skewed near and far planes (i.e. oblique).
	// Make sure look_up is perpendicular to normal.
	vec3 look_pos_x = normalize(cross(normal, look_up));
	look_up = normalize(cross(look_pos_x, normal));

	view = mat4_cast(look_at(normal, look_up)) * translate(-camera_pos);

	float dist_x = dot(look_pos_x, center - camera_pos);
	float left = dist_x - radius_other;
	float right = dist_x + radius_other;

	float dist_y = dot(look_up, center - camera_pos);
	float bottom = dist_y - radius_up;
	float top = dist_y + radius_up;

	z_near = over_plane;
	projection = frustum(left, right, bottom, top, over_plane, z_far);
	if (z_near >= z_far)
		return false;
	return true;
}

void compute_model_transform(mat4 &world, vec3 s, quat rot, vec3 trans, const mat4 &parent)
{
	mat4 model;
	model[3] = vec4(trans, 1.0f);
	SIMD::convert_quaternion_with_scale(&model[0], rot, s);
	SIMD::mul(world, parent, model);
}

void compute_normal_transform(mat4 &normal, const mat4 &world)
{
	normal = mat4(transpose(inverse(mat3(world))));
}

quat rotate_vector(vec3 from, vec3 to)
{
	from = normalize(from);
	to = normalize(to);

	float cos_angle = dot(from, to);
	if (abs(cos_angle) > 0.9999f)
	{
		if (cos_angle > 0.9999f)
			return quat(1.0f, 0.0f, 0.0f, 0.0f);
		else
		{
			vec3 rotation = cross(vec3(1.0f, 0.0f, 0.0f), from);
			if (dot(rotation, rotation) > 0.001f)
				rotation = normalize(rotation);
			else
				rotation = normalize(cross(vec3(0.0f, 1.0f, 0.0f), from));
			return quat(0.0f, rotation);
		}
	}

	vec3 rotation = normalize(cross(from, to));
	vec3 half_vector = normalize(from + to);
	float cos_half_range = clamp(dot(half_vector, from), 0.0f, 1.0f);
	float sin_half_angle = sqrtf(1.0f - cos_half_range * cos_half_range);
	return quat(cos_half_range, rotation * sin_half_angle);
}

quat rotate_vector_axis(vec3 from, vec3 to, vec3 axis)
{
	axis = normalize(axis);
	from = normalize(cross(axis, from));
	to = normalize(cross(axis, to));

	if (dot(to, from) < -0.9999f)
		return quat(0.0f, axis);

	// Rotate CCW or CW, we only find the angle of rotation below.
	float quat_sign = sign(dot(axis, cross(from, to)));

	vec3 half_vector = normalize(from + to);
	float cos_half_range = clamp(dot(half_vector, from), 0.0f, 1.0f);
	float sin_half_angle = quat_sign * sqrtf(1.0f - cos_half_range * cos_half_range);
	return quat(cos_half_range, axis * sin_half_angle);
}

quat look_at(vec3 direction, vec3 up)
{
	static const vec3 z(0.0f, 0.0f, -1.0f);
	static const vec3 y(0.0f, 1.0f, 0.0f);
	direction = normalize(direction);
	vec3 right = cross(direction, up);
	vec3 actual_up = cross(right, direction);
	quat look_transform = rotate_vector(direction, z);
	quat up_transform = rotate_vector_axis(look_transform * actual_up, y, z);
	return up_transform * look_transform;
}

quat look_at_arbitrary_up(vec3 direction)
{
	return rotate_vector(normalize(direction), vec3(0.0f, 0.0f, -1.0f));
}

mat4 projection(float fovy, float aspect, float znear, float zfar)
{
	return perspective(fovy, aspect, znear, zfar);
}

mat4 ortho(const AABB &aabb)
{
	vec3 min = aabb.get_minimum();
	vec3 max = aabb.get_maximum();

	// Flip Z for RH, ortho zNear/zFar is LH style.
	std::swap(max.z, min.z);
	max.z = -max.z;
	min.z = -min.z;

	return muglm::ortho(min.x, max.x, min.y, max.y, min.z, max.z);
}

void compute_cube_render_transform(vec3 center, unsigned face, mat4 &proj, mat4 &view, float znear, float zfar)
{
	static const vec3 dirs[6] = {
		vec3(1.0f, 0.0f, 0.0f),
		vec3(-1.0f, 0.0f, 0.0f),
		vec3(0.0f, 1.0f, 0.0f),
		vec3(0.0f, -1.0f, 0.0f),
		vec3(0.0f, 0.0f, 1.0f),
		vec3(0.0f, 0.0f, -1.0f),
	};

	static const vec3 ups[6] = {
		vec3(0.0f, 1.0f, 0.0f),
		vec3(0.0f, 1.0f, 0.0f),
		vec3(0.0f, 0.0f, -1.0f),
		vec3(0.0f, 0.0f, +1.0f),
		vec3(0.0f, 1.0f, 0.0f),
		vec3(0.0f, 1.0f, 0.0f),
	};

	view = mat4_cast(look_at(dirs[face], ups[face])) * translate(-center);
	proj = scale(vec3(-1.0f, 1.0f, 1.0f)) * projection(0.5f * pi<float>(), 1.0f, znear, zfar);
}

vec3 PositionalSampler::sample(unsigned index, float l) const
{
	if (l == 0.0f)
		return values[index];
	assert(index + 1 < values.size());
	return mix(values[index], values[index + 1], l);
}

template <typename T>
static T compute_cubic_spline(const std::vector<T> &values, unsigned index, float t, float dt)
{
	assert(3 * index + 4 < values.size());
	T p0 = values[3 * index + 1];

	// For t == 0.0f, the result must be exactly on the point as specified by glTF.
	if (t == 0.0f)
		return p0;

	T m0 = dt * values[3 * index + 2];
	T m1 = dt * values[3 * index + 3];
	T p1 = values[3 * index + 4];

	float t2 = t * t;
	float t3 = t2 * t;

	return (2.0f * t3 - 3.0f * t2 + 1.0f) * p0 +
	       (t3 - 2.0f * t2 + t) * m0 +
	       (-2.0f * t3 + 3.0f * t2) * p1 +
	       (t3 - t2) * m1;
}

vec3 PositionalSampler::sample_spline(unsigned index, float t, float dt) const
{
	return compute_cubic_spline(values, index, t, dt);
}

quat SphericalSampler::sample(unsigned index, float l) const
{
	if (l == 0.0f)
		return quat(values[index]);
	assert(index + 1 < values.size());
	return slerp(quat(values[index]), quat(values[index + 1]), l);
}

quat SphericalSampler::sample_spline(unsigned index, float t, float dt) const
{
	// CUBICSPLINE for quaternion is defined as simple vec4 interpolation with normalization.
	return normalize(quat(compute_cubic_spline(values, index, t, dt)));
}

quat SphericalSampler::sample_squad(unsigned index, float l) const
{
	if (l == 0.0f)
		return quat(values[index]);

	assert(3 * index + 4 < values.size());

	quat q0 = quat(values[3 * index + 1]);
	quat cp0 = quat(values[3 * index + 2]);
	quat cp1 = quat(values[3 * index + 3]);
	quat q1 = quat(values[3 * index + 4]);

	return slerp_no_invert(slerp_no_invert(q0, q1, l), slerp_no_invert(cp0, cp1, l), 2.0f * l * (1.0f - l));
}

quat compute_inner_control_point(const quat &q0, const quat &q1, const quat &q2)
{
	// This is almost gibberish, as this is just copy-pastaed from various implementations
	// found on the interwebs.
	// From studying it in greater detail,
	// the basic gist is that quaternion log and exp are used to
	// decompose what should be a series of multiplications (quat rotations) into additions, since
	// ln(a * b) = ln(a) + ln(b), and exp(ln(a)) = a.

	// ln(q) means encoding a vec3 where the length encodes theta, and direction encodes direction.
	// Summing ln(a) + ln(b) will therefore "add" the addition together, similar to how one
	// would add torque vectors in physics. The exp must then re-encode the vector-magnitude encoding
	// back to normal quaternion form.

	// In this domain we can average rotations, and go back again to a normal quaternion with exp.
	// inv_q1 * q2 and inv_q1 * q0 both do some form of "differential" of the rotations.
	// q12 and q10 estimate first derivative at the control points.
	// q12 and q10 have opposing signs,
	// so the sum of the logs is therefore seen as instantaneous acceleration at the q1.

	// quat_log() breaks down if q.w goes negative it seems, so that explains some shenanigans
	// where some docs say that this only works for "normal" interpolation scenarios.
	// Probably more than good enough for us though.

	quat inv_q1 = conjugate(q1);
	quat q12 = inv_q1 * q2;
	quat q10 = inv_q1 * q0;
	vec3 q12_log = quat_log(q12);
	vec3 q10_log = quat_log(q10);
	quat exp_value = quat_exp(-0.25f * (q12_log + q10_log));
	return q1 * exp_value;
}
}<commit_msg>Handle l == 1.0f in lerp functions.<commit_after>/* Copyright (c) 2017-2020 Hans-Kristian Arntzen
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "transforms.hpp"
#include "aabb.hpp"
#include "simd.hpp"
#include "muglm/matrix_helper.hpp"
#include <assert.h>

namespace Granite
{
bool compute_plane_reflection(mat4 &projection, mat4 &view, vec3 camera_pos, vec3 center, vec3 normal, vec3 look_up,
                              float radius_up, float radius_other, float &z_near, float z_far)
{
	normal = normalize(normal);

	// Reflect the camera position from the plane.
	float over_plane = dot(normal, camera_pos - center);
	if (over_plane <= 0.0f)
		return false;

	camera_pos -= 2.0f * over_plane * normal;

	// The look direction is up through the plane direction.
	// This way we avoid skewed near and far planes (i.e. oblique).
	// Make sure look_up is perpendicular to normal.
	vec3 look_pos_x = normalize(cross(normal, look_up));
	look_up = normalize(cross(look_pos_x, normal));

	view = mat4_cast(look_at(normal, look_up)) * translate(-camera_pos);

	float dist_x = dot(look_pos_x, center - camera_pos);
	float left = dist_x - radius_other;
	float right = dist_x + radius_other;

	float dist_y = dot(look_up, center - camera_pos);
	float bottom = dist_y - radius_up;
	float top = dist_y + radius_up;

	z_near = over_plane;
	projection = frustum(left, right, bottom, top, over_plane, z_far);
	if (z_near >= z_far)
		return false;
	return true;
}

bool compute_plane_refraction(mat4 &projection, mat4 &view, vec3 camera_pos, vec3 center, vec3 normal, vec3 look_up,
                              float radius_up, float radius_other, float &z_near, float z_far)
{
	normal = normalize(normal);

	// Reflect the camera position from the plane.
	float over_plane = dot(normal, camera_pos - center);
	if (over_plane <= 0.0f)
		return false;

	normal = -normal;

	// The look direction is up through the plane direction.
	// This way we avoid skewed near and far planes (i.e. oblique).
	// Make sure look_up is perpendicular to normal.
	vec3 look_pos_x = normalize(cross(normal, look_up));
	look_up = normalize(cross(look_pos_x, normal));

	view = mat4_cast(look_at(normal, look_up)) * translate(-camera_pos);

	float dist_x = dot(look_pos_x, center - camera_pos);
	float left = dist_x - radius_other;
	float right = dist_x + radius_other;

	float dist_y = dot(look_up, center - camera_pos);
	float bottom = dist_y - radius_up;
	float top = dist_y + radius_up;

	z_near = over_plane;
	projection = frustum(left, right, bottom, top, over_plane, z_far);
	if (z_near >= z_far)
		return false;
	return true;
}

void compute_model_transform(mat4 &world, vec3 s, quat rot, vec3 trans, const mat4 &parent)
{
	mat4 model;
	model[3] = vec4(trans, 1.0f);
	SIMD::convert_quaternion_with_scale(&model[0], rot, s);
	SIMD::mul(world, parent, model);
}

void compute_normal_transform(mat4 &normal, const mat4 &world)
{
	normal = mat4(transpose(inverse(mat3(world))));
}

quat rotate_vector(vec3 from, vec3 to)
{
	from = normalize(from);
	to = normalize(to);

	float cos_angle = dot(from, to);
	if (abs(cos_angle) > 0.9999f)
	{
		if (cos_angle > 0.9999f)
			return quat(1.0f, 0.0f, 0.0f, 0.0f);
		else
		{
			vec3 rotation = cross(vec3(1.0f, 0.0f, 0.0f), from);
			if (dot(rotation, rotation) > 0.001f)
				rotation = normalize(rotation);
			else
				rotation = normalize(cross(vec3(0.0f, 1.0f, 0.0f), from));
			return quat(0.0f, rotation);
		}
	}

	vec3 rotation = normalize(cross(from, to));
	vec3 half_vector = normalize(from + to);
	float cos_half_range = clamp(dot(half_vector, from), 0.0f, 1.0f);
	float sin_half_angle = sqrtf(1.0f - cos_half_range * cos_half_range);
	return quat(cos_half_range, rotation * sin_half_angle);
}

quat rotate_vector_axis(vec3 from, vec3 to, vec3 axis)
{
	axis = normalize(axis);
	from = normalize(cross(axis, from));
	to = normalize(cross(axis, to));

	if (dot(to, from) < -0.9999f)
		return quat(0.0f, axis);

	// Rotate CCW or CW, we only find the angle of rotation below.
	float quat_sign = sign(dot(axis, cross(from, to)));

	vec3 half_vector = normalize(from + to);
	float cos_half_range = clamp(dot(half_vector, from), 0.0f, 1.0f);
	float sin_half_angle = quat_sign * sqrtf(1.0f - cos_half_range * cos_half_range);
	return quat(cos_half_range, axis * sin_half_angle);
}

quat look_at(vec3 direction, vec3 up)
{
	static const vec3 z(0.0f, 0.0f, -1.0f);
	static const vec3 y(0.0f, 1.0f, 0.0f);
	direction = normalize(direction);
	vec3 right = cross(direction, up);
	vec3 actual_up = cross(right, direction);
	quat look_transform = rotate_vector(direction, z);
	quat up_transform = rotate_vector_axis(look_transform * actual_up, y, z);
	return up_transform * look_transform;
}

quat look_at_arbitrary_up(vec3 direction)
{
	return rotate_vector(normalize(direction), vec3(0.0f, 0.0f, -1.0f));
}

mat4 projection(float fovy, float aspect, float znear, float zfar)
{
	return perspective(fovy, aspect, znear, zfar);
}

mat4 ortho(const AABB &aabb)
{
	vec3 min = aabb.get_minimum();
	vec3 max = aabb.get_maximum();

	// Flip Z for RH, ortho zNear/zFar is LH style.
	std::swap(max.z, min.z);
	max.z = -max.z;
	min.z = -min.z;

	return muglm::ortho(min.x, max.x, min.y, max.y, min.z, max.z);
}

void compute_cube_render_transform(vec3 center, unsigned face, mat4 &proj, mat4 &view, float znear, float zfar)
{
	static const vec3 dirs[6] = {
		vec3(1.0f, 0.0f, 0.0f),
		vec3(-1.0f, 0.0f, 0.0f),
		vec3(0.0f, 1.0f, 0.0f),
		vec3(0.0f, -1.0f, 0.0f),
		vec3(0.0f, 0.0f, 1.0f),
		vec3(0.0f, 0.0f, -1.0f),
	};

	static const vec3 ups[6] = {
		vec3(0.0f, 1.0f, 0.0f),
		vec3(0.0f, 1.0f, 0.0f),
		vec3(0.0f, 0.0f, -1.0f),
		vec3(0.0f, 0.0f, +1.0f),
		vec3(0.0f, 1.0f, 0.0f),
		vec3(0.0f, 1.0f, 0.0f),
	};

	view = mat4_cast(look_at(dirs[face], ups[face])) * translate(-center);
	proj = scale(vec3(-1.0f, 1.0f, 1.0f)) * projection(0.5f * pi<float>(), 1.0f, znear, zfar);
}

vec3 PositionalSampler::sample(unsigned index, float l) const
{
	if (l == 0.0f)
		return values[index];
	else if (l == 1.0f)
		return values[index + 1];

	assert(index + 1 < values.size());
	return mix(values[index], values[index + 1], l);
}

template <typename T>
static T compute_cubic_spline(const std::vector<T> &values, unsigned index, float t, float dt)
{
	assert(3 * index + 4 < values.size());
	T p0 = values[3 * index + 1];
	T p1 = values[3 * index + 4];

	// For t == 0.0f, the result must be exactly on the point as specified by glTF.
	if (t == 0.0f)
		return p0;
	else if (t == 1.0f)
		return p1;

	T m0 = dt * values[3 * index + 2];
	T m1 = dt * values[3 * index + 3];

	float t2 = t * t;
	float t3 = t2 * t;

	return (2.0f * t3 - 3.0f * t2 + 1.0f) * p0 +
	       (t3 - 2.0f * t2 + t) * m0 +
	       (-2.0f * t3 + 3.0f * t2) * p1 +
	       (t3 - t2) * m1;
}

vec3 PositionalSampler::sample_spline(unsigned index, float t, float dt) const
{
	return compute_cubic_spline(values, index, t, dt);
}

quat SphericalSampler::sample(unsigned index, float l) const
{
	if (l == 0.0f)
		return quat(values[index]);
	else if (l == 1.0f)
		return quat(values[index + 1]);

	assert(index + 1 < values.size());
	return slerp(quat(values[index]), quat(values[index + 1]), l);
}

quat SphericalSampler::sample_spline(unsigned index, float t, float dt) const
{
	// CUBICSPLINE for quaternion is defined as simple vec4 interpolation with normalization.
	return normalize(quat(compute_cubic_spline(values, index, t, dt)));
}

quat SphericalSampler::sample_squad(unsigned index, float l) const
{
	assert(3 * index + 4 < values.size());

	if (l == 0.0f)
		return quat(values[3 * index + 1]);
	else if (l == 1.0f)
		return quat(values[3 * index + 4]);

	quat q0 = quat(values[3 * index + 1]);
	quat cp0 = quat(values[3 * index + 2]);
	quat cp1 = quat(values[3 * index + 3]);
	quat q1 = quat(values[3 * index + 4]);

	return slerp_no_invert(slerp_no_invert(q0, q1, l), slerp_no_invert(cp0, cp1, l), 2.0f * l * (1.0f - l));
}

quat compute_inner_control_point(const quat &q0, const quat &q1, const quat &q2)
{
	// This is almost gibberish, as this is just copy-pastaed from various implementations
	// found on the interwebs.
	// From studying it in greater detail,
	// the basic gist is that quaternion log and exp are used to
	// decompose what should be a series of multiplications (quat rotations) into additions, since
	// ln(a * b) = ln(a) + ln(b), and exp(ln(a)) = a.

	// ln(q) means encoding a vec3 where the length encodes theta, and direction encodes direction.
	// Summing ln(a) + ln(b) will therefore "add" the addition together, similar to how one
	// would add torque vectors in physics. The exp must then re-encode the vector-magnitude encoding
	// back to normal quaternion form.

	// In this domain we can average rotations, and go back again to a normal quaternion with exp.
	// inv_q1 * q2 and inv_q1 * q0 both do some form of "differential" of the rotations.
	// q12 and q10 estimate first derivative at the control points.
	// q12 and q10 have opposing signs,
	// so the sum of the logs is therefore seen as instantaneous acceleration at the q1.

	// quat_log() breaks down if q.w goes negative it seems, so that explains some shenanigans
	// where some docs say that this only works for "normal" interpolation scenarios.
	// Probably more than good enough for us though.

	quat inv_q1 = conjugate(q1);
	quat q12 = inv_q1 * q2;
	quat q10 = inv_q1 * q0;
	vec3 q12_log = quat_log(q12);
	vec3 q10_log = quat_log(q10);
	quat exp_value = quat_exp(-0.25f * (q12_log + q10_log));
	return q1 * exp_value;
}
}<|endoftext|>


<commit_before>/*
 * libjingle
 * Copyright 2004 Google Inc.
 *
 * 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. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "talk/media/base/codec.h"

#include <algorithm>
#include <sstream>

#include "talk/base/common.h"
#include "talk/base/logging.h"
#include "talk/base/stringencode.h"
#include "talk/base/stringutils.h"

namespace cricket {

static const int kMaxStaticPayloadId = 95;

bool FeedbackParam::operator==(const FeedbackParam& other) const {
  return _stricmp(other.id().c_str(), id().c_str()) == 0 &&
      _stricmp(other.param().c_str(), param().c_str()) == 0;
}

bool FeedbackParams::operator==(const FeedbackParams& other) const {
  return params_ == other.params_;
}

bool FeedbackParams::Has(const FeedbackParam& param) const {
  return std::find(params_.begin(), params_.end(), param) != params_.end();
}

void FeedbackParams::Add(const FeedbackParam& param) {
  if (param.id().empty()) {
    return;
  }
  if (Has(param)) {
    // Param already in |this|.
    return;
  }
  params_.push_back(param);
  ASSERT(!HasDuplicateEntries());
}

void FeedbackParams::Intersect(const FeedbackParams& from) {
  std::vector<FeedbackParam>::iterator iter_to = params_.begin();
  while (iter_to != params_.end()) {
    if (!from.Has(*iter_to)) {
      iter_to = params_.erase(iter_to);
    } else {
      ++iter_to;
    }
  }
}

bool FeedbackParams::HasDuplicateEntries() const {
  for (std::vector<FeedbackParam>::const_iterator iter = params_.begin();
       iter != params_.end(); ++iter) {
    for (std::vector<FeedbackParam>::const_iterator found = iter + 1;
         found != params_.end(); ++found) {
      if (*found == *iter) {
        return true;
      }
    }
  }
  return false;
}

bool Codec::Matches(const Codec& codec) const {
  // Match the codec id/name based on the typical static/dynamic name rules.
  // Matching is case-insensitive.
  return (codec.id <= kMaxStaticPayloadId) ?
      (id == codec.id) : (_stricmp(name.c_str(), codec.name.c_str()) == 0);
}

bool Codec::GetParam(const std::string& name, std::string* out) const {
  CodecParameterMap::const_iterator iter = params.find(name);
  if (iter == params.end())
    return false;
  *out = iter->second;
  return true;
}

bool Codec::GetParam(const std::string& name, int* out) const {
  CodecParameterMap::const_iterator iter = params.find(name);
  if (iter == params.end())
    return false;
  return talk_base::FromString(iter->second, out);
}

void Codec::SetParam(const std::string& name, const std::string& value) {
  params[name] = value;
}

void Codec::SetParam(const std::string& name, int value)  {
  params[name] = talk_base::ToString(value);
}

void Codec::AddFeedbackParam(const FeedbackParam& param) {
  feedback_params.Add(param);
}

bool Codec::HasFeedbackParam(const FeedbackParam& param) const {
  return feedback_params.Has(param);
}

void Codec::IntersectFeedbackParams(const Codec& other) {
  feedback_params.Intersect(other.feedback_params);
}

bool AudioCodec::Matches(const AudioCodec& codec) const {
  // If a nonzero clockrate is specified, it must match the actual clockrate.
  // If a nonzero bitrate is specified, it must match the actual bitrate,
  // unless the codec is VBR (0), where we just force the supplied value.
  // The number of channels must match exactly, with the exception
  // that channels=0 is treated synonymously as channels=1, per RFC
  // 4566 section 6: " [The channels] parameter is OPTIONAL and may be
  // omitted if the number of channels is one."
  // Preference is ignored.
  // TODO(juberti): Treat a zero clockrate as 8000Hz, the RTP default clockrate.
  return Codec::Matches(codec) &&
      ((codec.clockrate == 0 /*&& clockrate == 8000*/) ||
          clockrate == codec.clockrate) &&
      (codec.bitrate == 0 || bitrate <= 0 || bitrate == codec.bitrate) &&
      ((codec.channels < 2 && channels < 2) || channels == codec.channels);
}

std::string AudioCodec::ToString() const {
  std::ostringstream os;
  os << "AudioCodec[" << id << ":" << name << ":" << clockrate << ":" << bitrate
     << ":" << channels << ":" << preference << "]";
  return os.str();
}

std::string VideoCodec::ToString() const {
  std::ostringstream os;
  os << "VideoCodec[" << id << ":" << name << ":" << width << ":" << height
     << ":" << framerate << ":" << preference << "]";
  return os.str();
}

VideoCodec VideoCodec::CreateRtxCodec(int rtx_payload_type,
                                      int associated_payload_type) {
  VideoCodec rtx_codec(rtx_payload_type, kRtxCodecName, 0, 0, 0, 0);
  rtx_codec.SetParam(kCodecParamAssociatedPayloadType, associated_payload_type);
  return rtx_codec;
}

VideoCodec::CodecType VideoCodec::GetCodecType() const {
  const char* payload_name = name.c_str();
  if (_stricmp(payload_name, kRedCodecName) == 0) {
    return CODEC_RED;
  }
  if (_stricmp(payload_name, kUlpfecCodecName) == 0) {
    return CODEC_ULPFEC;
  }
  if (_stricmp(payload_name, kRtxCodecName) == 0) {
    return CODEC_RTX;
  }

  return CODEC_VIDEO;
}

bool VideoCodec::ValidateCodecFormat() const {
  if (id < 0 || id > 127) {
    LOG(LS_ERROR) << "Codec with invalid payload type: " << ToString();
    return false;
  }
  if (GetCodecType() != CODEC_VIDEO) {
    return true;
  }

  // Video validation from here on.

  if (width <= 0 || height <= 0) {
    LOG(LS_ERROR) << "Codec with invalid dimensions: " << ToString();
    return false;
  }
  int min_bitrate = -1;
  int max_bitrate = -1;
  if (GetParam(kCodecParamMinBitrate, &min_bitrate) &&
      GetParam(kCodecParamMaxBitrate, &max_bitrate)) {
    if (max_bitrate < min_bitrate) {
      LOG(LS_ERROR) << "Codec with max < min bitrate: " << ToString();
      return false;
    }
  }
  return true;
}

std::string DataCodec::ToString() const {
  std::ostringstream os;
  os << "DataCodec[" << id << ":" << name << "]";
  return os.str();
}

}  // namespace cricket
<commit_msg>Rollback of r6108<commit_after>/*
 * libjingle
 * Copyright 2004 Google Inc.
 *
 * 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. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "talk/media/base/codec.h"

#include <algorithm>
#include <sstream>

#include "talk/base/common.h"
#include "talk/base/logging.h"
#include "talk/base/stringencode.h"
#include "talk/base/stringutils.h"

namespace cricket {

static const int kMaxStaticPayloadId = 95;

bool FeedbackParam::operator==(const FeedbackParam& other) const {
  return _stricmp(other.id().c_str(), id().c_str()) == 0 &&
      _stricmp(other.param().c_str(), param().c_str()) == 0;
}

bool FeedbackParams::operator==(const FeedbackParams& other) const {
  return params_ == other.params_;
}

bool FeedbackParams::Has(const FeedbackParam& param) const {
  return std::find(params_.begin(), params_.end(), param) != params_.end();
}

void FeedbackParams::Add(const FeedbackParam& param) {
  if (param.id().empty()) {
    return;
  }
  if (Has(param)) {
    // Param already in |this|.
    return;
  }
  params_.push_back(param);
  ASSERT(!HasDuplicateEntries());
}

void FeedbackParams::Intersect(const FeedbackParams& from) {
  std::vector<FeedbackParam>::iterator iter_to = params_.begin();
  while (iter_to != params_.end()) {
    if (!from.Has(*iter_to)) {
      iter_to = params_.erase(iter_to);
    } else {
      ++iter_to;
    }
  }
}

bool FeedbackParams::HasDuplicateEntries() const {
  for (std::vector<FeedbackParam>::const_iterator iter = params_.begin();
       iter != params_.end(); ++iter) {
    for (std::vector<FeedbackParam>::const_iterator found = iter + 1;
         found != params_.end(); ++found) {
      if (*found == *iter) {
        return true;
      }
    }
  }
  return false;
}

bool Codec::Matches(const Codec& codec) const {
  // Match the codec id/name based on the typical static/dynamic name rules.
  // Matching is case-insensitive.
  return (codec.id <= kMaxStaticPayloadId) ?
      (id == codec.id) : (_stricmp(name.c_str(), codec.name.c_str()) == 0);
}

bool Codec::GetParam(const std::string& name, std::string* out) const {
  CodecParameterMap::const_iterator iter = params.find(name);
  if (iter == params.end())
    return false;
  *out = iter->second;
  return true;
}

bool Codec::GetParam(const std::string& name, int* out) const {
  CodecParameterMap::const_iterator iter = params.find(name);
  if (iter == params.end())
    return false;
  return talk_base::FromString(iter->second, out);
}

void Codec::SetParam(const std::string& name, const std::string& value) {
  params[name] = value;
}

void Codec::SetParam(const std::string& name, int value)  {
  params[name] = talk_base::ToString(value);
}

void Codec::AddFeedbackParam(const FeedbackParam& param) {
  feedback_params.Add(param);
}

bool Codec::HasFeedbackParam(const FeedbackParam& param) const {
  return feedback_params.Has(param);
}

void Codec::IntersectFeedbackParams(const Codec& other) {
  feedback_params.Intersect(other.feedback_params);
}

bool AudioCodec::Matches(const AudioCodec& codec) const {
  // If a nonzero clockrate is specified, it must match the actual clockrate.
  // If a nonzero bitrate is specified, it must match the actual bitrate,
  // unless the codec is VBR (0), where we just force the supplied value.
  // The number of channels must match exactly, with the exception
  // that channels=0 is treated synonymously as channels=1, per RFC
  // 4566 section 6: " [The channels] parameter is OPTIONAL and may be
  // omitted if the number of channels is one."
  // Preference is ignored.
  // TODO(juberti): Treat a zero clockrate as 8000Hz, the RTP default clockrate.
  return Codec::Matches(codec) &&
      ((codec.clockrate == 0 /*&& clockrate == 8000*/) ||
          clockrate == codec.clockrate) &&
      (codec.bitrate == 0 || bitrate <= 0 || bitrate == codec.bitrate) &&
      ((codec.channels < 2 && channels < 2) || channels == codec.channels);
}

std::string AudioCodec::ToString() const {
  std::ostringstream os;
  os << "AudioCodec[" << id << ":" << name << ":" << clockrate << ":" << bitrate
     << ":" << channels << ":" << preference << "]";
  return os.str();
}

std::string VideoCodec::ToString() const {
  std::ostringstream os;
  os << "VideoCodec[" << id << ":" << name << ":" << width << ":" << height
     << ":" << framerate << ":" << preference << "]";
  return os.str();
}

VideoCodec VideoCodec::CreateRtxCodec(int rtx_payload_type,
                                      int associated_payload_type) {
  VideoCodec rtx_codec(rtx_payload_type, kRtxCodecName, 0, 0, 0, 0);
  rtx_codec.SetParam(kCodecParamAssociatedPayloadType, associated_payload_type);
  return rtx_codec;
}

VideoCodec::CodecType VideoCodec::GetCodecType() const {
  const char* payload_name = name.c_str();
  if (_stricmp(payload_name, kRedCodecName) == 0) {
    return CODEC_RED;
  }
  if (_stricmp(payload_name, kUlpfecCodecName) == 0) {
    return CODEC_ULPFEC;
  }
  if (_stricmp(payload_name, kRtxCodecName) == 0) {
    return CODEC_RTX;
  }

  return CODEC_VIDEO;
}

bool VideoCodec::ValidateCodecFormat() const {
  if (id < 0 || id > 127) {
    LOG(LS_ERROR) << "Codec with invalid payload type: " << ToString();
    return false;
  }
  if (GetCodecType() != CODEC_VIDEO) {
    return true;
  }

  // Video validation from here on.

  if (width <= 0 || height <= 0) {
    LOG(LS_ERROR) << "Codec with invalid dimensions: " << ToString();
    return false;
  }
  int min_bitrate;
  int max_bitrate;
  if (GetParam(kCodecParamMinBitrate, &min_bitrate) &&
      GetParam(kCodecParamMaxBitrate, &max_bitrate)) {
    if (max_bitrate < min_bitrate) {
      LOG(LS_ERROR) << "Codec with max < min bitrate: " << ToString();
      return false;
    }
  }
  return true;
}

std::string DataCodec::ToString() const {
  std::ostringstream os;
  os << "DataCodec[" << id << ":" << name << "]";
  return os.str();
}

}  // namespace cricket
<|endoftext|>


<commit_before>/*
 * C++ Design Patterns: Memento
 * Author: Jakub Vojvoda [github.com/JakubVojvoda]
 * 2016
 *
 * Source code is licensed under MIT License
 * (for more details see LICENSE)
 *
 */

#include <iostream>
#include <vector>

/*
 * Memento
 * stores internal state of the Originator object and protects
 * against access by objects other than the originator
 */
class Memento {
private:
  // accessible only to Originator
  friend class Originator;

  Memento(int s)
    : state(s) {}

  void setState(int s) {
    state = s;
  }

  int getState() {
    return state;
  }
  // ...

private:
  int state;
  // ...
};

/*
 * Originator
 * creates a memento containing a snapshot of its current internal
 * state and uses the memento to restore its internal state
 */
class Originator {
public:
  // implemented only for printing purpose
  void setState(int s) {
    state = s;
  }

  // implemented only for printing purpose
  int getState() {
    return state;
  }

  void setMemento(Memento *m) {
    state = m->getState();
  }

  Memento *createMemento() {
    return new Memento(state);
  }

private:
  int state;
  // ...
};

/*
 * CareTaker
 * is responsible for the memento's safe keeping
 */
class CareTaker {
public:
  CareTaker(Originator *o)
    : originator(o) {}

  ~CareTaker() {
    for (unsigned int i = 0; i < history.size(); i++) {
      delete history.at(i);
    }
    history.clear();
  }

  void save() {
    history.push_back(originator->createMemento());
  }

  void undo() {
    originator->setMemento(history.front());
    history.pop_back();
  }
  // ...

private:
  Originator *originator;
  std::vector<Memento *> history;
  // ...
};

int main()
{
  Originator *originator = new Originator;
  CareTaker *caretaker = new CareTaker(originator);

  originator->setState(1);
  caretaker->save();
  std::cout << "Set state: " << originator->getState() << std::endl;

  originator->setState(2);
  caretaker->save();
  std::cout << "Set state: " << originator->getState() << std::endl;

  caretaker->undo();
  std::cout << "Undo state: " << originator->getState() << std::endl;

  delete originator;
  delete caretaker;

  return 0;
}
<commit_msg>fix Memento pattern<commit_after>/*
 * C++ Design Patterns: Memento
 * Author: Jakub Vojvoda [github.com/JakubVojvoda]
 * 2016
 *
 * Source code is licensed under MIT License
 * (for more details see LICENSE)
 *
 */

#include <iostream>
#include <vector>

/*
 * Memento
 * stores internal state of the Originator object and protects
 * against access by objects other than the originator
 */
class Memento {
private:
  // accessible only to Originator
  friend class Originator;

  Memento(int s)
    : state(s) {}

  void setState(int s) {
    state = s;
  }

  int getState() {
    return state;
  }
  // ...

private:
  int state;
  // ...
};

/*
 * Originator
 * creates a memento containing a snapshot of its current internal
 * state and uses the memento to restore its internal state
 */
class Originator {
public:
  // implemented only for printing purpose
  void setState(int s) {
    std::cout << "Set state to " << s << "." << std::endl;
    state = s;
  }

  // implemented only for printing purpose
  int getState() {
    return state;
  }

  void setMemento(Memento *m) {
    state = m->getState();
  }

  Memento *createMemento() {
    return new Memento(state);
  }

private:
  int state;
  // ...
};

/*
 * CareTaker
 * is responsible for the memento's safe keeping
 */
class CareTaker {
public:
  CareTaker(Originator *o)
    : originator(o) {}

  ~CareTaker() {
    for (unsigned int i = 0; i < history.size(); i++) {
      delete history.at(i);
    }
    history.clear();
  }

  void save() {
    std::cout << "Save state." << std::endl;;
    history.push_back(originator->createMemento());
  }

  void undo() {
    std::cout << "Undo state." << std::endl;;
    originator->setMemento(history.back());
    history.pop_back();
  }
  // ...

private:
  Originator *originator;
  std::vector<Memento *> history;
  // ...
};

int main()
{
  Originator *originator = new Originator;
  CareTaker *caretaker = new CareTaker(originator);

  originator->setState(1);
  caretaker->save();

  originator->setState(2);
  caretaker->save();

  originator->setState(3);
  caretaker->undo();

  std::cout << "Actual state is " << originator->getState() << "." << std::endl;

  delete originator;
  delete caretaker;

  return 0;
}
<|endoftext|>