<commit_before>#include <boost/format.hpp>

#include <Common.h>
#include <Network/CommonNetwork.h>
#include <Network/GamePacketNew.h>
#include <Logging/Logger.h>
#include <Exd/ExdDataGenerated.h>
#include <Network/PacketContainer.h>

#include "Zone/Zone.h"
#include "Zone/ZonePosition.h"

#include "Network/GameConnection.h"
#include "Network/PacketWrappers/InitUIPacket.h"
#include "Network/PacketWrappers/PingPacket.h"
#include "Network/PacketWrappers/MoveActorPacket.h"
#include "Network/PacketWrappers/ChatPacket.h"
#include "Network/PacketWrappers/ServerNoticePacket.h"
#include "Network/PacketWrappers/ActorControlPacket142.h"
#include "Network/PacketWrappers/ActorControlPacket143.h"
#include "Network/PacketWrappers/ActorControlPacket144.h"
#include "Network/PacketWrappers/EventStartPacket.h"
#include "Network/PacketWrappers/EventFinishPacket.h"
#include "Network/PacketWrappers/PlayerStateFlagsPacket.h"

#include "DebugCommand/DebugCommandHandler.h"

#include "Actor/Player.h"

#include "Inventory/Inventory.h"

#include "Event/EventHelper.h"

#include "Action/Action.h"
#include "Action/ActionTeleport.h"

#include "Session.h"
#include "ServerZone.h"
#include "Forwards.h"
#include "Framework.h"

extern Core::Framework g_fw;

using namespace Core::Common;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;

enum ClientTrigger
{
   ToggleSeathe = 0x01,
   ToggleAutoAttack = 0x02,
   ChangeTarget = 0x03,

   Dismount = 0x65,

   RemoveStatusEffect = 0x68,
   CastCancel = 0x69,

   Return = 0xC8, // return dead / accept raise
   FinishZoning = 0xC9,
   Teleport = 0xCA,

   MarkPlayer = 0x12D, // Mark player, visible to party only
   SetTitle = 0x12E,
   TitleList = 0x12F,

   UpdatedSeenHowTos = 0x133,
   AllotAttribute = 0x135,

   ClearWaymarks = 0x13A,

   HuntingLogDetails = 0x194,

   Timers = 0x1AB,

   DyeItem = 0x1B5,

   RequestChocoboInventory = 0x1C4,

   Emote = 0x1F4,
   PersistantEmoteCancel = 0x1F7,
   PoseChange = 0x1F9,
   PoseReapply = 0x1FA,
   PoseCancel = 0x1FB,

   AchievementCrit = 0x202,
   AchievementComp = 0x203,
   AchievementCatChat = 0x206,

   DirectorInitFinish = 0x321,

   SomeDirectorEvent = 0x328, // unsure what exactly triggers it, starts director when returning to instance though

   EnterTerritoryEventFinished = 0x330,

   AchievementCritReq = 0x3E8,
   AchievementList = 0x3E9,

   CompanionAction = 0x6A4,
   CompanionSetBarding = 0x6A5,
   CompanionActionUnlock = 0x6A6,

   OpenPerformInstrumentUI = 0x71C,
};

void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& inPacket,
                                                   Entity::Player& player )
{
    auto pLog = g_fw.get< Logger >();
    uint16_t commandId = inPacket.getValAt< uint16_t >( 0x20 );
    uint64_t param1 = inPacket.getValAt< uint64_t >( 0x24 );
    uint32_t param11 = inPacket.getValAt< uint32_t >( 0x24 );
    uint32_t param12 = inPacket.getValAt< uint32_t >( 0x28 );
    uint32_t param2 = inPacket.getValAt< uint32_t >( 0x2C );
    uint64_t param3 = inPacket.getValAt< uint64_t >( 0x38 );

    pLog->debug( "[" + std::to_string( m_pSession->getId() ) + "] Incoming action: " +
                 boost::str( boost::format( "%|04X|" ) % ( uint32_t ) ( commandId & 0xFFFF ) ) +
                 "\nparam1: " + boost::str( boost::format( "%|016X|" ) % ( uint64_t ) ( param1 & 0xFFFFFFFFFFFFFFF ) ) +
                 "\nparam2: " + boost::str( boost::format( "%|08X|" ) % ( uint32_t ) ( param2 & 0xFFFFFFFF ) ) +
                 "\nparam3: " + boost::str( boost::format( "%|016X|" ) % ( uint64_t ) ( param3 & 0xFFFFFFFFFFFFFFF ) )
    );

    //g_log.Log(LoggingSeverity::debug, "[" + std::to_string(m_pSession->getId()) + "] " + pInPacket->toString());

    switch( commandId )
    {
        case ClientTrigger::ToggleSeathe:  // Toggle sheathe
        {
            if ( param11 == 1 )
                player.setStance( Entity::Chara::Stance::Active );
            else
            {
                player.setStance( Entity::Chara::Stance::Passive );
                player.setAutoattack( false );
            }

            player.sendToInRangeSet( ActorControlPacket142( player.getId(), 0, param11, 1 ) );

            break;
        }
        case ClientTrigger::ToggleAutoAttack:  // Toggle auto-attack
        {
            if ( param11 == 1 )
            {
                player.setAutoattack( true );
                player.setStance( Entity::Chara::Stance::Active );
            }
            else
                player.setAutoattack( false );

            player.sendToInRangeSet( ActorControlPacket142( player.getId(), 1, param11, 1 ) );

            break;
        }
        case ClientTrigger::ChangeTarget: // Change target
        {

            uint64_t targetId = inPacket.getValAt< uint64_t >( 0x24 );
            player.changeTarget( targetId );
            break;
        }
        case ClientTrigger::Dismount:
        {
           player.dismount();
           break;
        }
        case ClientTrigger::RemoveStatusEffect: // Remove status (clicking it off)
        {
           // todo: check if status can be removed by client from exd
           player.removeSingleStatusEffectById( static_cast< uint32_t >( param1 ) );
           break;
        }
        case ClientTrigger::CastCancel: // Cancel cast
        {
           if( player.getCurrentAction() )
               player.getCurrentAction()->setInterrupted();
           break;
        }
        case ClientTrigger::MarkPlayer: // Mark player
        {
           break;
        }
        case ClientTrigger::SetTitle: // Set player title
        {
           player.setTitle( static_cast< uint16_t >( param1 ) );
           break;
        }
        case ClientTrigger::TitleList: // Get title list
        {
           player.sendTitleList();
           break;
        }
        case ClientTrigger::UpdatedSeenHowTos: // Update howtos seen
        {
            uint32_t howToId = param11;
            player.updateHowtosSeen( howToId );
            break;
        }
        case ClientTrigger::Emote: // emote
        {
            uint64_t targetId = player.getTargetId();
            uint32_t emoteId = inPacket.getValAt< uint32_t >( 0x24 );

            player.emote( emoteId, targetId );
            break;
        }
        case ClientTrigger::PersistantEmoteCancel: // cancel persistant emote
        {
            break;
        }
        case ClientTrigger::PoseChange: // change pose
        {
            break;
        }
        case ClientTrigger::PoseReapply: // reapply pose
        {
            break;
        }
        case ClientTrigger::PoseCancel: // cancel pose
        {
            break;
        }
        case ClientTrigger::Return: // return dead / accept raise
        {
           switch ( static_cast < ResurrectType >( param1 ) )
           {
              case ResurrectType::RaiseSpell:
                 // todo: handle raise case (set position to raiser, apply weakness status, set hp/mp/tp as well as packet)
                 player.returnToHomepoint();
                 break;
              case ResurrectType::Return:
                 player.returnToHomepoint();
                 break;
              default:
                 break;
           }

        }
        case ClientTrigger::FinishZoning: // Finish zoning
        {
            player.finishZoning();
            break;
        }

        case ClientTrigger::Teleport: // Teleport
        {

            player.teleportQuery( param11 );
            break;
        }
        case ClientTrigger::DyeItem: // Dye item
        {
           break;
        }
        case ClientTrigger::DirectorInitFinish: // Director init finish
        {
           player.getCurrentZone()->onInitDirector( player );
           break;
        }
       case ClientTrigger::SomeDirectorEvent: // Director init finish
       {
          player.getCurrentZone()->onSomeDirectorEvent( player );
          break;
       }
        case ClientTrigger::EnterTerritoryEventFinished:// this may still be something else. I think i have seen it elsewhere
        {
           player.setOnEnterEventDone( true );
           break;
        }
        default:
        {
           pLog->debug( "[" + std::to_string( m_pSession->getId() ) + "] Unhandled action: " +
              boost::str( boost::format( "%|04X|" ) % (uint32_t) ( commandId & 0xFFFF ) ) );
           break;
        }
    }
}
<commit_msg>fix indent and leave button opcode def<commit_after>#include <boost/format.hpp>

#include <Common.h>
#include <Network/CommonNetwork.h>
#include <Network/GamePacketNew.h>
#include <Logging/Logger.h>
#include <Exd/ExdDataGenerated.h>
#include <Network/PacketContainer.h>

#include "Zone/Zone.h"
#include "Zone/ZonePosition.h"

#include "Network/GameConnection.h"
#include "Network/PacketWrappers/InitUIPacket.h"
#include "Network/PacketWrappers/PingPacket.h"
#include "Network/PacketWrappers/MoveActorPacket.h"
#include "Network/PacketWrappers/ChatPacket.h"
#include "Network/PacketWrappers/ServerNoticePacket.h"
#include "Network/PacketWrappers/ActorControlPacket142.h"
#include "Network/PacketWrappers/ActorControlPacket143.h"
#include "Network/PacketWrappers/ActorControlPacket144.h"
#include "Network/PacketWrappers/EventStartPacket.h"
#include "Network/PacketWrappers/EventFinishPacket.h"
#include "Network/PacketWrappers/PlayerStateFlagsPacket.h"

#include "DebugCommand/DebugCommandHandler.h"

#include "Actor/Player.h"

#include "Inventory/Inventory.h"

#include "Event/EventHelper.h"

#include "Action/Action.h"
#include "Action/ActionTeleport.h"

#include "Session.h"
#include "ServerZone.h"
#include "Forwards.h"
#include "Framework.h"

extern Core::Framework g_fw;

using namespace Core::Common;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;

enum ClientTrigger
{
   ToggleSeathe = 0x01,
   ToggleAutoAttack = 0x02,
   ChangeTarget = 0x03,

   Dismount = 0x65,

   RemoveStatusEffect = 0x68,
   CastCancel = 0x69,

   Return = 0xC8, // return dead / accept raise
   FinishZoning = 0xC9,
   Teleport = 0xCA,

   MarkPlayer = 0x12D, // Mark player, visible to party only
   SetTitle = 0x12E,
   TitleList = 0x12F,

   UpdatedSeenHowTos = 0x133,
   AllotAttribute = 0x135,

   ClearWaymarks = 0x13A,

   HuntingLogDetails = 0x194,

   Timers = 0x1AB,

   DyeItem = 0x1B5,

   RequestChocoboInventory = 0x1C4,

   Emote = 0x1F4,
   PersistantEmoteCancel = 0x1F7,
   PoseChange = 0x1F9,
   PoseReapply = 0x1FA,
   PoseCancel = 0x1FB,

   AchievementCrit = 0x202,
   AchievementComp = 0x203,
   AchievementCatChat = 0x206,

   DirectorInitFinish = 0x321,

   SomeDirectorEvent = 0x328, // unsure what exactly triggers it, starts director when returning to instance though

   EnterTerritoryEventFinished = 0x330,
   RequestInstanceLeave = 0x330, // df menu button

   AchievementCritReq = 0x3E8,
   AchievementList = 0x3E9,

   CompanionAction = 0x6A4,
   CompanionSetBarding = 0x6A5,
   CompanionActionUnlock = 0x6A6,

   OpenPerformInstrumentUI = 0x71C,
};

void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& inPacket,
                                                   Entity::Player& player )
{
   auto pLog = g_fw.get< Logger >();
   uint16_t commandId = inPacket.getValAt< uint16_t >( 0x20 );
   uint64_t param1 = inPacket.getValAt< uint64_t >( 0x24 );
   uint32_t param11 = inPacket.getValAt< uint32_t >( 0x24 );
   uint32_t param12 = inPacket.getValAt< uint32_t >( 0x28 );
   uint32_t param2 = inPacket.getValAt< uint32_t >( 0x2C );
   uint64_t param3 = inPacket.getValAt< uint64_t >( 0x38 );

   pLog->debug( "[" + std::to_string( m_pSession->getId() ) + "] Incoming action: " +
              boost::str( boost::format( "%|04X|" ) % ( uint32_t ) ( commandId & 0xFFFF ) ) +
              "\nparam1: " + boost::str( boost::format( "%|016X|" ) % ( uint64_t ) ( param1 & 0xFFFFFFFFFFFFFFF ) ) +
              "\nparam2: " + boost::str( boost::format( "%|08X|" ) % ( uint32_t ) ( param2 & 0xFFFFFFFF ) ) +
              "\nparam3: " + boost::str( boost::format( "%|016X|" ) % ( uint64_t ) ( param3 & 0xFFFFFFFFFFFFFFF ) )
   );

   //g_log.Log(LoggingSeverity::debug, "[" + std::to_string(m_pSession->getId()) + "] " + pInPacket->toString());

   switch( commandId )
   {
      case ClientTrigger::ToggleSeathe:  // Toggle sheathe
      {
          if ( param11 == 1 )
              player.setStance( Entity::Chara::Stance::Active );
          else
          {
              player.setStance( Entity::Chara::Stance::Passive );
              player.setAutoattack( false );
          }

          player.sendToInRangeSet( ActorControlPacket142( player.getId(), 0, param11, 1 ) );

          break;
      }
      case ClientTrigger::ToggleAutoAttack:  // Toggle auto-attack
      {
          if ( param11 == 1 )
          {
              player.setAutoattack( true );
              player.setStance( Entity::Chara::Stance::Active );
          }
          else
              player.setAutoattack( false );

          player.sendToInRangeSet( ActorControlPacket142( player.getId(), 1, param11, 1 ) );

          break;
      }
      case ClientTrigger::ChangeTarget: // Change target
      {

          uint64_t targetId = inPacket.getValAt< uint64_t >( 0x24 );
          player.changeTarget( targetId );
          break;
      }
      case ClientTrigger::Dismount:
      {
         player.dismount();
         break;
      }
      case ClientTrigger::RemoveStatusEffect: // Remove status (clicking it off)
      {
         // todo: check if status can be removed by client from exd
         player.removeSingleStatusEffectById( static_cast< uint32_t >( param1 ) );
         break;
      }
      case ClientTrigger::CastCancel: // Cancel cast
      {
         if( player.getCurrentAction() )
             player.getCurrentAction()->setInterrupted();
         break;
      }
      case ClientTrigger::MarkPlayer: // Mark player
      {
         break;
      }
      case ClientTrigger::SetTitle: // Set player title
      {
         player.setTitle( static_cast< uint16_t >( param1 ) );
         break;
      }
      case ClientTrigger::TitleList: // Get title list
      {
         player.sendTitleList();
         break;
      }
      case ClientTrigger::UpdatedSeenHowTos: // Update howtos seen
      {
          uint32_t howToId = param11;
          player.updateHowtosSeen( howToId );
          break;
      }
      case ClientTrigger::Emote: // emote
      {
          uint64_t targetId = player.getTargetId();
          uint32_t emoteId = inPacket.getValAt< uint32_t >( 0x24 );

          player.emote( emoteId, targetId );
          break;
      }
      case ClientTrigger::PersistantEmoteCancel: // cancel persistant emote
      {
          break;
      }
      case ClientTrigger::PoseChange: // change pose
      {
          break;
      }
      case ClientTrigger::PoseReapply: // reapply pose
      {
          break;
      }
      case ClientTrigger::PoseCancel: // cancel pose
      {
          break;
      }
      case ClientTrigger::Return: // return dead / accept raise
      {
         switch ( static_cast < ResurrectType >( param1 ) )
         {
            case ResurrectType::RaiseSpell:
               // todo: handle raise case (set position to raiser, apply weakness status, set hp/mp/tp as well as packet)
               player.returnToHomepoint();
               break;
            case ResurrectType::Return:
               player.returnToHomepoint();
               break;
            default:
               break;
         }

      }
      case ClientTrigger::FinishZoning: // Finish zoning
      {
          player.finishZoning();
          break;
      }

      case ClientTrigger::Teleport: // Teleport
      {

          player.teleportQuery( param11 );
          break;
      }
      case ClientTrigger::DyeItem: // Dye item
      {
         break;
      }
      case ClientTrigger::DirectorInitFinish: // Director init finish
      {
         player.getCurrentZone()->onInitDirector( player );
         break;
      }
      case ClientTrigger::SomeDirectorEvent: // Director init finish
      {
         player.getCurrentZone()->onSomeDirectorEvent( player );
         break;
      }
      case ClientTrigger::EnterTerritoryEventFinished:// this may still be something else. I think i have seen it elsewhere
      {
         player.setOnEnterEventDone( true );
         break;
      }
      default:
      {
         pLog->debug( "[" + std::to_string( m_pSession->getId() ) + "] Unhandled action: " +
            boost::str( boost::format( "%|04X|" ) % (uint32_t) ( commandId & 0xFFFF ) ) );
         break;
      }
   }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2008-2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "esnpapi.h"
#include "proxyImpl.h"

#include <any.h>
#include <reflect.h>
#include <org/w3c/dom.h>

using namespace org::w3c::dom;

void initializeHtmlMetaData()
{
    registerMetaData(html::ApplicationCache::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::ApplicationCache_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::BarProp::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::BarProp_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::BeforeUnloadEvent::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::BeforeUnloadEvent_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::CanvasGradient::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::CanvasGradient_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::CanvasPattern::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::CanvasPattern_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::CanvasPixelArray::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::CanvasPixelArray_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::CanvasRenderingContext2D::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::CanvasRenderingContext2D_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::DataTransfer::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::DataTransfer_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::DOMSettableTokenList::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::DOMSettableTokenList_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::DOMStringMap::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::DOMStringMap_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::DOMTokenList::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::DOMTokenList_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::DragEvent::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::DragEvent_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::Function::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::Function_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::History::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::History_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::ImageData::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::ImageData_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::Location::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::Location_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::MediaError::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::MediaError_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::MessageChannel::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::MessageChannel_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::MessageEvent::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::MessageEvent_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::MessagePort::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::MessagePort_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::Navigator::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::Navigator_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::PopStateEvent::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::PopStateEvent_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::PropertyNodeList::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::PropertyNodeList_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::RadioNodeList::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::RadioNodeList_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::Screen::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::Screen_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::Selection::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::Selection_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::StyleMedia::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::StyleMedia_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::TextMetrics::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::TextMetrics_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::TimeRanges::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::TimeRanges_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::UndoManagerEvent::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::UndoManagerEvent_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::UndoManager::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::UndoManager_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::ValidityState::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::ValidityState_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::Window::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::Window_Bridge<Any, invoke> >::createInstance));

    initializeHtmlMetaDataA_G();
    initializeHtmlMetaDataH_N();
    initializeHtmlMetaDataO_U();
    initializeHtmlMetaDataV_Z();

    // In HTML5, HTMLDocument is a mixin of Document, but historically it was a separate interface extended from Document.
    // Existing browsers uses HTMLDocument as a class name, and we need to register 'HTMLDocument' as a valid interface name for Document.
    registerMetaData(Document::getMetaData(),
                     reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, Document_Bridge<Any, invoke> >::createInstance),
                     "HTMLDocument");
}
<commit_msg>(initializeHtmlMetaData) : Regiseter DOMWindow for WebKit.<commit_after>/*
 * Copyright 2008-2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "esnpapi.h"
#include "proxyImpl.h"

#include <any.h>
#include <reflect.h>
#include <org/w3c/dom.h>

using namespace org::w3c::dom;

void initializeHtmlMetaData()
{
    registerMetaData(html::ApplicationCache::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::ApplicationCache_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::BarProp::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::BarProp_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::BeforeUnloadEvent::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::BeforeUnloadEvent_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::CanvasGradient::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::CanvasGradient_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::CanvasPattern::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::CanvasPattern_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::CanvasPixelArray::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::CanvasPixelArray_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::CanvasRenderingContext2D::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::CanvasRenderingContext2D_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::DataTransfer::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::DataTransfer_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::DOMSettableTokenList::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::DOMSettableTokenList_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::DOMStringMap::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::DOMStringMap_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::DOMTokenList::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::DOMTokenList_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::DragEvent::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::DragEvent_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::Function::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::Function_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::History::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::History_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::ImageData::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::ImageData_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::Location::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::Location_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::MediaError::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::MediaError_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::MessageChannel::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::MessageChannel_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::MessageEvent::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::MessageEvent_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::MessagePort::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::MessagePort_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::Navigator::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::Navigator_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::PopStateEvent::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::PopStateEvent_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::PropertyNodeList::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::PropertyNodeList_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::RadioNodeList::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::RadioNodeList_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::Screen::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::Screen_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::Selection::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::Selection_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::StyleMedia::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::StyleMedia_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::TextMetrics::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::TextMetrics_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::TimeRanges::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::TimeRanges_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::UndoManagerEvent::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::UndoManagerEvent_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::UndoManager::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::UndoManager_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::ValidityState::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::ValidityState_Bridge<Any, invoke> >::createInstance));
    registerMetaData(html::Window::getMetaData(), reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::Window_Bridge<Any, invoke> >::createInstance));

    initializeHtmlMetaDataA_G();
    initializeHtmlMetaDataH_N();
    initializeHtmlMetaDataO_U();
    initializeHtmlMetaDataV_Z();

    // In HTML5, HTMLDocument is a mixin of Document, but historically it was a separate interface extended from Document.
    // Existing browsers uses HTMLDocument as a class name, and we need to register 'HTMLDocument' as a valid interface name for Document.
    registerMetaData(Document::getMetaData(),
                     reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, Document_Bridge<Any, invoke> >::createInstance),
                     "HTMLDocument");

    // WebKit uses "DOMWindow" instead of "Window"
    registerMetaData(html::Window::getMetaData(),
                     reinterpret_cast<Object* (*)(ProxyObject)>(Proxy_Impl<ProxyObject, html::Window_Bridge<Any, invoke> >::createInstance),
                     "DOMWindow");
}
<|endoftext|>


<commit_before>// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ssl/connection_security_helper.h"

#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ssl/ssl_error_info.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/cert_store.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/ssl_status.h"
#include "net/base/net_util.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "url/url_constants.h"

#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/policy/policy_cert_service.h"
#include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
#endif

namespace {

ConnectionSecurityHelper::SecurityLevel
GetSecurityLevelForNonSecureFieldTrial() {
  std::string choice =
      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
          switches::kMarkNonSecureAs);
  if (choice == switches::kMarkNonSecureAsNeutral)
    return ConnectionSecurityHelper::NONE;
  if (choice == switches::kMarkNonSecureAsDubious)
    return ConnectionSecurityHelper::SECURITY_WARNING;
  if (choice == switches::kMarkNonSecureAsNonSecure)
    return ConnectionSecurityHelper::SECURITY_ERROR;

  std::string group = base::FieldTrialList::FindFullName("MarkNonSecureAs");
  if (group == switches::kMarkNonSecureAsNeutral)
    return ConnectionSecurityHelper::NONE;
  if (group == switches::kMarkNonSecureAsDubious)
    return ConnectionSecurityHelper::SECURITY_WARNING;
  if (group == switches::kMarkNonSecureAsNonSecure)
    return ConnectionSecurityHelper::SECURITY_ERROR;

  return ConnectionSecurityHelper::NONE;
}

}  // namespace

ConnectionSecurityHelper::SecurityLevel
ConnectionSecurityHelper::GetSecurityLevelForWebContents(
    content::WebContents* web_contents) {
  if (!web_contents)
    return NONE;

  content::NavigationEntry* entry =
      web_contents->GetController().GetVisibleEntry();
  if (!entry)
    return NONE;

  const content::SSLStatus& ssl = entry->GetSSL();
  switch (ssl.security_style) {
    case content::SECURITY_STYLE_UNKNOWN:
      return NONE;

    case content::SECURITY_STYLE_UNAUTHENTICATED: {
      const GURL& url = entry->GetURL();
      if (url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kFtpScheme))
        return GetSecurityLevelForNonSecureFieldTrial();
      return NONE;
    }

    case content::SECURITY_STYLE_AUTHENTICATION_BROKEN:
      return SECURITY_ERROR;

    case content::SECURITY_STYLE_AUTHENTICATED: {
#if defined(OS_CHROMEOS)
      policy::PolicyCertService* service =
          policy::PolicyCertServiceFactory::GetForProfile(
              Profile::FromBrowserContext(web_contents->GetBrowserContext()));
      if (service && service->UsedPolicyCertificates())
        return SECURITY_POLICY_WARNING;
#endif
      if (ssl.content_status & content::SSLStatus::DISPLAYED_INSECURE_CONTENT)
        return SECURITY_WARNING;
      scoped_refptr<net::X509Certificate> cert;
      if (content::CertStore::GetInstance()->RetrieveCert(ssl.cert_id, &cert) &&
          (ssl.cert_status & net::CERT_STATUS_SHA1_SIGNATURE_PRESENT)) {
        // The internal representation of the dates for UI treatment of SHA-1.
        // See http://crbug.com/401365 for details.
        static const int64_t kJanuary2017 = INT64_C(13127702400000000);
        // kJanuary2016 needs to be kept in sync with
        // ToolbarModelAndroid::IsDeprecatedSHA1Present().
        static const int64_t kJanuary2016 = INT64_C(13096080000000000);
        if (cert->valid_expiry() >=
            base::Time::FromInternalValue(kJanuary2017)) {
          return SECURITY_ERROR;
        }
        if (cert->valid_expiry() >=
            base::Time::FromInternalValue(kJanuary2016)) {
          return SECURITY_WARNING;
        }
      }
      if (net::IsCertStatusError(ssl.cert_status)) {
        DCHECK(net::IsCertStatusMinorError(ssl.cert_status));
        return SECURITY_WARNING;
      }
      if (net::SSLConnectionStatusToVersion(ssl.connection_status) ==
          net::SSL_CONNECTION_VERSION_SSL3) {
        // SSLv3 will be removed in the future.
        return SECURITY_WARNING;
      }
      if ((ssl.cert_status & net::CERT_STATUS_IS_EV) && cert)
        return EV_SECURE;
      return SECURE;
    }

    default:
      NOTREACHED();
      return NONE;
  }
}
<commit_msg>Use |IsOriginSecure| for mark-HTTP-nonsecure field trial<commit_after>// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ssl/connection_security_helper.h"

#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ssl/ssl_error_info.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/cert_store.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/origin_util.h"
#include "content/public/common/ssl_status.h"
#include "net/base/net_util.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_connection_status_flags.h"

#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/policy/policy_cert_service.h"
#include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
#endif

namespace {

ConnectionSecurityHelper::SecurityLevel
GetSecurityLevelForNonSecureFieldTrial() {
  std::string choice =
      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
          switches::kMarkNonSecureAs);
  if (choice == switches::kMarkNonSecureAsNeutral)
    return ConnectionSecurityHelper::NONE;
  if (choice == switches::kMarkNonSecureAsDubious)
    return ConnectionSecurityHelper::SECURITY_WARNING;
  if (choice == switches::kMarkNonSecureAsNonSecure)
    return ConnectionSecurityHelper::SECURITY_ERROR;

  std::string group = base::FieldTrialList::FindFullName("MarkNonSecureAs");
  if (group == switches::kMarkNonSecureAsNeutral)
    return ConnectionSecurityHelper::NONE;
  if (group == switches::kMarkNonSecureAsDubious)
    return ConnectionSecurityHelper::SECURITY_WARNING;
  if (group == switches::kMarkNonSecureAsNonSecure)
    return ConnectionSecurityHelper::SECURITY_ERROR;

  return ConnectionSecurityHelper::NONE;
}

}  // namespace

ConnectionSecurityHelper::SecurityLevel
ConnectionSecurityHelper::GetSecurityLevelForWebContents(
    content::WebContents* web_contents) {
  if (!web_contents)
    return NONE;

  content::NavigationEntry* entry =
      web_contents->GetController().GetVisibleEntry();
  if (!entry)
    return NONE;

  const content::SSLStatus& ssl = entry->GetSSL();
  switch (ssl.security_style) {
    case content::SECURITY_STYLE_UNKNOWN:
      return NONE;

    case content::SECURITY_STYLE_UNAUTHENTICATED: {
      const GURL& url = entry->GetURL();
      if (!content::IsOriginSecure(url))
        return GetSecurityLevelForNonSecureFieldTrial();
      return NONE;
    }

    case content::SECURITY_STYLE_AUTHENTICATION_BROKEN:
      return SECURITY_ERROR;

    case content::SECURITY_STYLE_AUTHENTICATED: {
#if defined(OS_CHROMEOS)
      policy::PolicyCertService* service =
          policy::PolicyCertServiceFactory::GetForProfile(
              Profile::FromBrowserContext(web_contents->GetBrowserContext()));
      if (service && service->UsedPolicyCertificates())
        return SECURITY_POLICY_WARNING;
#endif
      if (ssl.content_status & content::SSLStatus::DISPLAYED_INSECURE_CONTENT)
        return SECURITY_WARNING;
      scoped_refptr<net::X509Certificate> cert;
      if (content::CertStore::GetInstance()->RetrieveCert(ssl.cert_id, &cert) &&
          (ssl.cert_status & net::CERT_STATUS_SHA1_SIGNATURE_PRESENT)) {
        // The internal representation of the dates for UI treatment of SHA-1.
        // See http://crbug.com/401365 for details.
        static const int64_t kJanuary2017 = INT64_C(13127702400000000);
        // kJanuary2016 needs to be kept in sync with
        // ToolbarModelAndroid::IsDeprecatedSHA1Present().
        static const int64_t kJanuary2016 = INT64_C(13096080000000000);
        if (cert->valid_expiry() >=
            base::Time::FromInternalValue(kJanuary2017)) {
          return SECURITY_ERROR;
        }
        if (cert->valid_expiry() >=
            base::Time::FromInternalValue(kJanuary2016)) {
          return SECURITY_WARNING;
        }
      }
      if (net::IsCertStatusError(ssl.cert_status)) {
        DCHECK(net::IsCertStatusMinorError(ssl.cert_status));
        return SECURITY_WARNING;
      }
      if (net::SSLConnectionStatusToVersion(ssl.connection_status) ==
          net::SSL_CONNECTION_VERSION_SSL3) {
        // SSLv3 will be removed in the future.
        return SECURITY_WARNING;
      }
      if ((ssl.cert_status & net::CERT_STATUS_IS_EV) && cert)
        return EV_SECURE;
      return SECURE;
    }

    default:
      NOTREACHED();
      return NONE;
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/test_profile_sync_service.h"

#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/sync/abstract_profile_sync_service_test.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/profile_sync_components_factory.h"
#include "chrome/browser/sync/test/test_http_bridge_factory.h"
#include "chrome/common/chrome_notification_types.h"
#include "sync/internal_api/public/sessions/sync_session_snapshot.h"
#include "sync/internal_api/public/test/test_internal_components_factory.h"
#include "sync/internal_api/public/user_share.h"
#include "sync/js/js_reply_handler.h"
#include "sync/protocol/encryption.pb.h"
#include "sync/syncable/directory.h"

using syncer::ModelSafeRoutingInfo;
using syncer::TestInternalComponentsFactory;
using syncer::sessions::ModelNeutralState;
using syncer::sessions::SyncSessionSnapshot;
using syncer::sessions::SyncSourceInfo;
using syncer::UserShare;
using syncer::syncable::Directory;

namespace browser_sync {

SyncBackendHostForProfileSyncTest::SyncBackendHostForProfileSyncTest(
    Profile* profile,
    const base::WeakPtr<SyncPrefs>& sync_prefs,
    const base::WeakPtr<InvalidatorStorage>& invalidator_storage,
    syncer::TestIdFactory& id_factory,
    base::Closure& callback,
    bool set_initial_sync_ended_on_init,
    bool synchronous_init,
    bool fail_initial_download,
    bool use_real_database)
    : browser_sync::SyncBackendHost(
        profile->GetDebugName(), profile, sync_prefs, invalidator_storage),
      id_factory_(id_factory),
      callback_(callback),
      set_initial_sync_ended_on_init_(set_initial_sync_ended_on_init),
      synchronous_init_(synchronous_init),
      fail_initial_download_(fail_initial_download),
      use_real_database_(use_real_database) {}

SyncBackendHostForProfileSyncTest::~SyncBackendHostForProfileSyncTest() {}

namespace {

scoped_ptr<syncer::HttpPostProviderFactory> MakeTestHttpBridgeFactory() {
  return scoped_ptr<syncer::HttpPostProviderFactory>(
      new browser_sync::TestHttpBridgeFactory());
}

}  // namespace

void SyncBackendHostForProfileSyncTest::InitCore(
    const DoInitializeOptions& options) {
  DoInitializeOptions test_options = options;
  test_options.make_http_bridge_factory_fn =
      base::Bind(&MakeTestHttpBridgeFactory);
  test_options.credentials.email = "testuser@gmail.com";
  test_options.credentials.sync_token = "token";
  test_options.restored_key_for_bootstrapping = "";
  TestInternalComponentsFactory::StorageOption storage =
      use_real_database_ ? TestInternalComponentsFactory::ON_DISK
                         : TestInternalComponentsFactory::IN_MEMORY;

  // It'd be nice if we avoided creating the InternalComponentsFactory in the
  // first place, but SyncBackendHost will have created one by now so we must
  // free it.
  delete test_options.internal_components_factory;
  test_options.internal_components_factory =
      new TestInternalComponentsFactory(storage);
  SyncBackendHost::InitCore(test_options);
  // TODO(akalin): Figure out a better way to do this.
  if (synchronous_init_) {
    // The SyncBackend posts a task to the current loop when
    // initialization completes.
    MessageLoop::current()->Run();
  }
}

void SyncBackendHostForProfileSyncTest::RequestConfigureSyncer(
    syncer::ConfigureReason reason,
    syncer::ModelTypeSet types_to_config,
    const syncer::ModelSafeRoutingInfo& routing_info,
    const base::Callback<void(syncer::ModelTypeSet)>& ready_task,
    const base::Closure& retry_callback) {
  syncer::ModelTypeSet failed_configuration_types;
  if (fail_initial_download_)
    failed_configuration_types = types_to_config;

  FinishConfigureDataTypesOnFrontendLoop(failed_configuration_types,
                                         ready_task);
}

void SyncBackendHostForProfileSyncTest
        ::HandleSyncManagerInitializationOnFrontendLoop(
    const syncer::WeakHandle<syncer::JsBackend>& js_backend, bool success,
    syncer::ModelTypeSet restored_types) {
  // Here's our opportunity to pretend to do things that the SyncManager would
  // normally do during initialization, but can't because this is a test.
  bool send_passphrase_required = false;
  if (success) {
    // Set up any nodes the test wants around before model association.
    if (!callback_.is_null()) {
      callback_.Run();
    }

    // Pretend we downloaded initial updates and set initial sync ended bits
    // if we were asked to.
    if (set_initial_sync_ended_on_init_) {
      UserShare* user_share = GetUserShare();
      Directory* directory = user_share->directory.get();

      if (!directory->initial_sync_ended_for_type(syncer::NIGORI)) {
        ProfileSyncServiceTestHelper::CreateRoot(
            syncer::NIGORI, user_share, &id_factory_);

        // A side effect of adding the NIGORI mode (normally done by the
        // syncer) is a decryption attempt, which will fail the first time.
        send_passphrase_required = true;
      }

      SetInitialSyncEndedForAllTypes();
      restored_types = syncer::ModelTypeSet::All();
    }
  }

  SyncBackendHost::HandleSyncManagerInitializationOnFrontendLoop(
      js_backend, success, restored_types);
}

void SyncBackendHostForProfileSyncTest::SetInitialSyncEndedForAllTypes() {
  UserShare* user_share = GetUserShare();
  Directory* directory = user_share->directory.get();

  for (int i = syncer::FIRST_REAL_MODEL_TYPE;
       i < syncer::MODEL_TYPE_COUNT; ++i) {
    directory->set_initial_sync_ended_for_type(
        syncer::ModelTypeFromInt(i), true);
  }
}

}  // namespace browser_sync

syncer::TestIdFactory* TestProfileSyncService::id_factory() {
  return &id_factory_;
}

browser_sync::SyncBackendHostForProfileSyncTest*
    TestProfileSyncService::GetBackendForTest() {
  return static_cast<browser_sync::SyncBackendHostForProfileSyncTest*>(
      ProfileSyncService::GetBackendForTest());
}

TestProfileSyncService::TestProfileSyncService(
    ProfileSyncComponentsFactory* factory,
    Profile* profile,
    SigninManager* signin,
    ProfileSyncService::StartBehavior behavior,
    bool synchronous_backend_initialization,
    const base::Closure& callback)
    : ProfileSyncService(factory,
                         profile,
                         signin,
                         behavior),
      synchronous_backend_initialization_(
          synchronous_backend_initialization),
      synchronous_sync_configuration_(false),
      callback_(callback),
      set_initial_sync_ended_on_init_(true),
      fail_initial_download_(false),
      use_real_database_(false) {
  SetSyncSetupCompleted();
}

TestProfileSyncService::~TestProfileSyncService() {
}

void TestProfileSyncService::OnBackendInitialized(
    const syncer::WeakHandle<syncer::JsBackend>& backend,
    bool success) {
  ProfileSyncService::OnBackendInitialized(backend, success);

  // TODO(akalin): Figure out a better way to do this.
  if (synchronous_backend_initialization_) {
    MessageLoop::current()->Quit();
  }
}

void TestProfileSyncService::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  ProfileSyncService::Observe(type, source, details);
  if (type == chrome::NOTIFICATION_SYNC_CONFIGURE_DONE &&
      !synchronous_sync_configuration_) {
    MessageLoop::current()->Quit();
  }
}

UserShare* TestProfileSyncService::GetUserShare() const {
  return backend_->GetUserShare();
}

void TestProfileSyncService::dont_set_initial_sync_ended_on_init() {
  set_initial_sync_ended_on_init_ = false;
}
void TestProfileSyncService::set_synchronous_sync_configuration() {
  synchronous_sync_configuration_ = true;
}
void TestProfileSyncService::fail_initial_download() {
  fail_initial_download_ = true;
}
void TestProfileSyncService::set_use_real_database() {
  use_real_database_ = true;
}

void TestProfileSyncService::CreateBackend() {
  backend_.reset(new browser_sync::SyncBackendHostForProfileSyncTest(
      profile(),
      sync_prefs_.AsWeakPtr(),
      invalidator_storage_.AsWeakPtr(),
      id_factory_,
      callback_,
      set_initial_sync_ended_on_init_,
      synchronous_backend_initialization_,
      fail_initial_download_,
      use_real_database_));
}
<commit_msg>Fix Precise build.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/test_profile_sync_service.h"

#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/sync/abstract_profile_sync_service_test.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/profile_sync_components_factory.h"
#include "chrome/browser/sync/test/test_http_bridge_factory.h"
#include "chrome/common/chrome_notification_types.h"
#include "sync/internal_api/public/sessions/sync_session_snapshot.h"
#include "sync/internal_api/public/test/test_internal_components_factory.h"
#include "sync/internal_api/public/user_share.h"
#include "sync/js/js_reply_handler.h"
#include "sync/protocol/encryption.pb.h"
#include "sync/syncable/directory.h"

using syncer::ModelSafeRoutingInfo;
using syncer::TestInternalComponentsFactory;
using syncer::sessions::ModelNeutralState;
using syncer::sessions::SyncSessionSnapshot;
using syncer::sessions::SyncSourceInfo;
using syncer::UserShare;
using syncer::syncable::Directory;

namespace browser_sync {

SyncBackendHostForProfileSyncTest::SyncBackendHostForProfileSyncTest(
    Profile* profile,
    const base::WeakPtr<SyncPrefs>& sync_prefs,
    const base::WeakPtr<InvalidatorStorage>& invalidator_storage,
    syncer::TestIdFactory& id_factory,
    base::Closure& callback,
    bool set_initial_sync_ended_on_init,
    bool synchronous_init,
    bool fail_initial_download,
    bool use_real_database)
    : browser_sync::SyncBackendHost(
        profile->GetDebugName(), profile, sync_prefs, invalidator_storage),
      id_factory_(id_factory),
      callback_(callback),
      set_initial_sync_ended_on_init_(set_initial_sync_ended_on_init),
      synchronous_init_(synchronous_init),
      fail_initial_download_(fail_initial_download),
      use_real_database_(use_real_database) {}

SyncBackendHostForProfileSyncTest::~SyncBackendHostForProfileSyncTest() {}

namespace {

scoped_ptr<syncer::HttpPostProviderFactory> MakeTestHttpBridgeFactory() {
  return scoped_ptr<syncer::HttpPostProviderFactory>(
      new browser_sync::TestHttpBridgeFactory());
}

}  // namespace

void SyncBackendHostForProfileSyncTest::InitCore(
    const DoInitializeOptions& options) {
  DoInitializeOptions test_options = options;
  test_options.make_http_bridge_factory_fn =
      base::Bind(&MakeTestHttpBridgeFactory);
  test_options.credentials.email = "testuser@gmail.com";
  test_options.credentials.sync_token = "token";
  test_options.restored_key_for_bootstrapping = "";
  TestInternalComponentsFactory::StorageOption storage =
      use_real_database_ ? TestInternalComponentsFactory::ON_DISK
                         : TestInternalComponentsFactory::IN_MEMORY;

  // It'd be nice if we avoided creating the InternalComponentsFactory in the
  // first place, but SyncBackendHost will have created one by now so we must
  // free it.
  delete test_options.internal_components_factory;
  test_options.internal_components_factory =
      new TestInternalComponentsFactory(storage);
  SyncBackendHost::InitCore(test_options);
  // TODO(akalin): Figure out a better way to do this.
  if (synchronous_init_) {
    // The SyncBackend posts a task to the current loop when
    // initialization completes.
    MessageLoop::current()->Run();
  }
}

void SyncBackendHostForProfileSyncTest::RequestConfigureSyncer(
    syncer::ConfigureReason reason,
    syncer::ModelTypeSet types_to_config,
    const syncer::ModelSafeRoutingInfo& routing_info,
    const base::Callback<void(syncer::ModelTypeSet)>& ready_task,
    const base::Closure& retry_callback) {
  syncer::ModelTypeSet failed_configuration_types;
  if (fail_initial_download_)
    failed_configuration_types = types_to_config;

  FinishConfigureDataTypesOnFrontendLoop(failed_configuration_types,
                                         ready_task);
}

void SyncBackendHostForProfileSyncTest
        ::HandleSyncManagerInitializationOnFrontendLoop(
    const syncer::WeakHandle<syncer::JsBackend>& js_backend, bool success,
    syncer::ModelTypeSet restored_types) {
  // Here's our opportunity to pretend to do things that the SyncManager would
  // normally do during initialization, but can't because this is a test.
  if (success) {
    // Set up any nodes the test wants around before model association.
    if (!callback_.is_null()) {
      callback_.Run();
    }

    // Pretend we downloaded initial updates and set initial sync ended bits
    // if we were asked to.
    if (set_initial_sync_ended_on_init_) {
      UserShare* user_share = GetUserShare();
      Directory* directory = user_share->directory.get();

      if (!directory->initial_sync_ended_for_type(syncer::NIGORI)) {
        ProfileSyncServiceTestHelper::CreateRoot(
            syncer::NIGORI, user_share, &id_factory_);

        // A side effect of adding the NIGORI mode (normally done by the
        // syncer) is a decryption attempt, which will fail the first time.
      }

      SetInitialSyncEndedForAllTypes();
      restored_types = syncer::ModelTypeSet::All();
    }
  }

  SyncBackendHost::HandleSyncManagerInitializationOnFrontendLoop(
      js_backend, success, restored_types);
}

void SyncBackendHostForProfileSyncTest::SetInitialSyncEndedForAllTypes() {
  UserShare* user_share = GetUserShare();
  Directory* directory = user_share->directory.get();

  for (int i = syncer::FIRST_REAL_MODEL_TYPE;
       i < syncer::MODEL_TYPE_COUNT; ++i) {
    directory->set_initial_sync_ended_for_type(
        syncer::ModelTypeFromInt(i), true);
  }
}

}  // namespace browser_sync

syncer::TestIdFactory* TestProfileSyncService::id_factory() {
  return &id_factory_;
}

browser_sync::SyncBackendHostForProfileSyncTest*
    TestProfileSyncService::GetBackendForTest() {
  return static_cast<browser_sync::SyncBackendHostForProfileSyncTest*>(
      ProfileSyncService::GetBackendForTest());
}

TestProfileSyncService::TestProfileSyncService(
    ProfileSyncComponentsFactory* factory,
    Profile* profile,
    SigninManager* signin,
    ProfileSyncService::StartBehavior behavior,
    bool synchronous_backend_initialization,
    const base::Closure& callback)
    : ProfileSyncService(factory,
                         profile,
                         signin,
                         behavior),
      synchronous_backend_initialization_(
          synchronous_backend_initialization),
      synchronous_sync_configuration_(false),
      callback_(callback),
      set_initial_sync_ended_on_init_(true),
      fail_initial_download_(false),
      use_real_database_(false) {
  SetSyncSetupCompleted();
}

TestProfileSyncService::~TestProfileSyncService() {
}

void TestProfileSyncService::OnBackendInitialized(
    const syncer::WeakHandle<syncer::JsBackend>& backend,
    bool success) {
  ProfileSyncService::OnBackendInitialized(backend, success);

  // TODO(akalin): Figure out a better way to do this.
  if (synchronous_backend_initialization_) {
    MessageLoop::current()->Quit();
  }
}

void TestProfileSyncService::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  ProfileSyncService::Observe(type, source, details);
  if (type == chrome::NOTIFICATION_SYNC_CONFIGURE_DONE &&
      !synchronous_sync_configuration_) {
    MessageLoop::current()->Quit();
  }
}

UserShare* TestProfileSyncService::GetUserShare() const {
  return backend_->GetUserShare();
}

void TestProfileSyncService::dont_set_initial_sync_ended_on_init() {
  set_initial_sync_ended_on_init_ = false;
}
void TestProfileSyncService::set_synchronous_sync_configuration() {
  synchronous_sync_configuration_ = true;
}
void TestProfileSyncService::fail_initial_download() {
  fail_initial_download_ = true;
}
void TestProfileSyncService::set_use_real_database() {
  use_real_database_ = true;
}

void TestProfileSyncService::CreateBackend() {
  backend_.reset(new browser_sync::SyncBackendHostForProfileSyncTest(
      profile(),
      sync_prefs_.AsWeakPtr(),
      invalidator_storage_.AsWeakPtr(),
      id_factory_,
      callback_,
      set_initial_sync_ended_on_init_,
      synchronous_backend_initialization_,
      fail_initial_download_,
      use_real_database_));
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/tab_contents/web_drag_dest_gtk.h"

#include "app/gtk_dnd_util.h"
#include "base/string_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/gtk_util.h"

using WebKit::WebDragOperation;
using WebKit::WebDragOperationCopy;
using WebKit::WebDragOperationNone;

WebDragDestGtk::WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget)
    : tab_contents_(tab_contents),
      widget_(widget),
      context_(NULL),
      method_factory_(this) {
  gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0),
                    NULL, 0, GDK_ACTION_COPY);
  g_signal_connect(widget, "drag-motion",
                   G_CALLBACK(OnDragMotionThunk), this);
  g_signal_connect(widget, "drag-leave",
                   G_CALLBACK(OnDragLeaveThunk), this);
  g_signal_connect(widget, "drag-drop",
                   G_CALLBACK(OnDragDropThunk), this);
  g_signal_connect(widget, "drag-data-received",
                   G_CALLBACK(OnDragDataReceivedThunk), this);

  destroy_handler_ = g_signal_connect(
      widget, "destroy", G_CALLBACK(gtk_widget_destroyed), &widget_);
}

WebDragDestGtk::~WebDragDestGtk() {
  if (widget_) {
    gtk_drag_dest_unset(widget_);
    g_signal_handler_disconnect(widget_, destroy_handler_);
  }
}

void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) {
  if (context_) {
    // TODO(estade): we might want to support other actions besides copy,
    // but that would increase the cost of getting our drag success guess
    // wrong.
    is_drop_target_ = operation != WebDragOperationNone;
    // TODO(snej): Pass appropriate GDK action instead of hardcoding COPY
    gdk_drag_status(context_, is_drop_target_ ? GDK_ACTION_COPY :
                    static_cast<GdkDragAction>(0),
                    drag_over_time_);
  }
}

void WebDragDestGtk::DragLeave() {
  tab_contents_->render_view_host()->DragTargetDragLeave();
}

gboolean WebDragDestGtk::OnDragMotion(GdkDragContext* context, gint x, gint y,
                                      guint time) {
  if (context_ != context) {
    context_ = context;
    drop_data_.reset(new WebDropData);
    is_drop_target_ = false;

    static int supported_targets[] = {
      GtkDndUtil::TEXT_PLAIN,
      GtkDndUtil::TEXT_URI_LIST,
      GtkDndUtil::TEXT_HTML,
      // TODO(estade): support image drags?
    };

    data_requests_ = arraysize(supported_targets);
    for (size_t i = 0; i < arraysize(supported_targets); ++i) {
      gtk_drag_get_data(widget_, context,
                        GtkDndUtil::GetAtomForTarget(supported_targets[i]),
                        time);
    }
  } else if (data_requests_ == 0) {
    tab_contents_->render_view_host()->
        DragTargetDragOver(gtk_util::ClientPoint(widget_),
                           gtk_util::ScreenPoint(widget_),
                           WebDragOperationCopy);
    // TODO(snej): Pass appropriate DragOperation instead of hardcoding
    drag_over_time_ = time;
  }

  // Pretend we are a drag destination because we don't want to wait for
  // the renderer to tell us if we really are or not.
  return TRUE;
}

void WebDragDestGtk::OnDragDataReceived(
    GdkDragContext* context, gint x, gint y, GtkSelectionData* data,
    guint info, guint time) {
  // We might get the data from an old get_data() request that we no longer
  // care about.
  if (context != context_)
    return;

  data_requests_--;

  // Decode the data.
  if (data->data) {
    // If the source can't provide us with valid data for a requested target,
    // data->data will be NULL.
    if (data->target ==
        GtkDndUtil::GetAtomForTarget(GtkDndUtil::TEXT_PLAIN)) {
      guchar* text = gtk_selection_data_get_text(data);
      if (text) {
        drop_data_->plain_text =
            UTF8ToUTF16(std::string(reinterpret_cast<char*>(text),
                                    data->length));
        g_free(text);
      }
    } else if (data->target ==
               GtkDndUtil::GetAtomForTarget(GtkDndUtil::TEXT_URI_LIST)) {
      gchar** uris = gtk_selection_data_get_uris(data);
      if (uris) {
        for (gchar** uri_iter = uris; *uri_iter; uri_iter++) {
          // TODO(estade): Can the filenames have a non-UTF8 encoding?
          drop_data_->filenames.push_back(UTF8ToUTF16(*uri_iter));
        }
        // Also, write the first URI as the URL.
        if (uris[0])
          drop_data_->url = GURL(uris[0]);
        g_strfreev(uris);
      }
    } else if (data->target ==
               GtkDndUtil::GetAtomForTarget(GtkDndUtil::TEXT_HTML)) {
      // TODO(estade): Can the html have a non-UTF8 encoding?
      drop_data_->text_html =
          UTF8ToUTF16(std::string(reinterpret_cast<char*>(data->data),
                                  data->length));
      // We leave the base URL empty.
    }
  }

  if (data_requests_ == 0) {
    // Tell the renderer about the drag.
    // |x| and |y| are seemingly arbitrary at this point.
    tab_contents_->render_view_host()->
        DragTargetDragEnter(*drop_data_.get(),
                            gtk_util::ClientPoint(widget_),
                            gtk_util::ScreenPoint(widget_),
                            WebDragOperationCopy);
    // TODO(snej): Pass appropriate DragOperation instead of hardcoding
    drag_over_time_ = time;
  }
}

// The drag has left our widget; forward this information to the renderer.
void WebDragDestGtk::OnDragLeave(GdkDragContext* context, guint time) {
  // Set |context_| to NULL to make sure we will recognize the next DragMotion
  // as an enter.
  context_ = NULL;
  drop_data_.reset();
  // When GTK sends us a drag-drop signal, it is shortly (and synchronously)
  // preceded by a drag-leave. The renderer doesn't like getting the signals
  // in this order so delay telling it about the drag-leave till we are sure
  // we are not getting a drop as well.
  MessageLoop::current()->PostTask(FROM_HERE,
      method_factory_.NewRunnableMethod(&WebDragDestGtk::DragLeave));
}

// Called by GTK when the user releases the mouse, executing a drop.
gboolean WebDragDestGtk::OnDragDrop(GdkDragContext* context, gint x, gint y,
                                    guint time) {
  // Cancel that drag leave!
  method_factory_.RevokeAll();

  tab_contents_->render_view_host()->
      DragTargetDrop(gtk_util::ClientPoint(widget_),
                     gtk_util::ScreenPoint(widget_));

  // The second parameter is just an educated guess, but at least we will
  // get the drag-end animation right sometimes.
  gtk_drag_finish(context, is_drop_target_, FALSE, time);
  return TRUE;
}
<commit_msg>Fix the problem that file URL is not converted to file path in drag-and-drop on Linux.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/tab_contents/web_drag_dest_gtk.h"

#include "app/gtk_dnd_util.h"
#include "base/file_path.h"
#include "base/string_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/gtk_util.h"
#include "net/base/net_util.h"

using WebKit::WebDragOperation;
using WebKit::WebDragOperationCopy;
using WebKit::WebDragOperationNone;

WebDragDestGtk::WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget)
    : tab_contents_(tab_contents),
      widget_(widget),
      context_(NULL),
      method_factory_(this) {
  gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0),
                    NULL, 0, GDK_ACTION_COPY);
  g_signal_connect(widget, "drag-motion",
                   G_CALLBACK(OnDragMotionThunk), this);
  g_signal_connect(widget, "drag-leave",
                   G_CALLBACK(OnDragLeaveThunk), this);
  g_signal_connect(widget, "drag-drop",
                   G_CALLBACK(OnDragDropThunk), this);
  g_signal_connect(widget, "drag-data-received",
                   G_CALLBACK(OnDragDataReceivedThunk), this);

  destroy_handler_ = g_signal_connect(
      widget, "destroy", G_CALLBACK(gtk_widget_destroyed), &widget_);
}

WebDragDestGtk::~WebDragDestGtk() {
  if (widget_) {
    gtk_drag_dest_unset(widget_);
    g_signal_handler_disconnect(widget_, destroy_handler_);
  }
}

void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) {
  if (context_) {
    // TODO(estade): we might want to support other actions besides copy,
    // but that would increase the cost of getting our drag success guess
    // wrong.
    is_drop_target_ = operation != WebDragOperationNone;
    // TODO(snej): Pass appropriate GDK action instead of hardcoding COPY
    gdk_drag_status(context_, is_drop_target_ ? GDK_ACTION_COPY :
                    static_cast<GdkDragAction>(0),
                    drag_over_time_);
  }
}

void WebDragDestGtk::DragLeave() {
  tab_contents_->render_view_host()->DragTargetDragLeave();
}

gboolean WebDragDestGtk::OnDragMotion(GdkDragContext* context, gint x, gint y,
                                      guint time) {
  if (context_ != context) {
    context_ = context;
    drop_data_.reset(new WebDropData);
    is_drop_target_ = false;

    static int supported_targets[] = {
      GtkDndUtil::TEXT_PLAIN,
      GtkDndUtil::TEXT_URI_LIST,
      GtkDndUtil::TEXT_HTML,
      // TODO(estade): support image drags?
    };

    data_requests_ = arraysize(supported_targets);
    for (size_t i = 0; i < arraysize(supported_targets); ++i) {
      gtk_drag_get_data(widget_, context,
                        GtkDndUtil::GetAtomForTarget(supported_targets[i]),
                        time);
    }
  } else if (data_requests_ == 0) {
    tab_contents_->render_view_host()->
        DragTargetDragOver(gtk_util::ClientPoint(widget_),
                           gtk_util::ScreenPoint(widget_),
                           WebDragOperationCopy);
    // TODO(snej): Pass appropriate DragOperation instead of hardcoding
    drag_over_time_ = time;
  }

  // Pretend we are a drag destination because we don't want to wait for
  // the renderer to tell us if we really are or not.
  return TRUE;
}

void WebDragDestGtk::OnDragDataReceived(
    GdkDragContext* context, gint x, gint y, GtkSelectionData* data,
    guint info, guint time) {
  // We might get the data from an old get_data() request that we no longer
  // care about.
  if (context != context_)
    return;

  data_requests_--;

  // Decode the data.
  if (data->data) {
    // If the source can't provide us with valid data for a requested target,
    // data->data will be NULL.
    if (data->target ==
        GtkDndUtil::GetAtomForTarget(GtkDndUtil::TEXT_PLAIN)) {
      guchar* text = gtk_selection_data_get_text(data);
      if (text) {
        drop_data_->plain_text =
            UTF8ToUTF16(std::string(reinterpret_cast<char*>(text),
                                    data->length));
        g_free(text);
      }
    } else if (data->target ==
               GtkDndUtil::GetAtomForTarget(GtkDndUtil::TEXT_URI_LIST)) {
      gchar** uris = gtk_selection_data_get_uris(data);
      if (uris) {
        for (gchar** uri_iter = uris; *uri_iter; uri_iter++) {
          // TODO(estade): Can the filenames have a non-UTF8 encoding?
          FilePath file_path;
          if (net::FileURLToFilePath(GURL(*uri_iter), &file_path))
            drop_data_->filenames.push_back(UTF8ToUTF16(file_path.value()));
        }
        // Also, write the first URI as the URL.
        if (uris[0])
          drop_data_->url = GURL(uris[0]);
        g_strfreev(uris);
      }
    } else if (data->target ==
               GtkDndUtil::GetAtomForTarget(GtkDndUtil::TEXT_HTML)) {
      // TODO(estade): Can the html have a non-UTF8 encoding?
      drop_data_->text_html =
          UTF8ToUTF16(std::string(reinterpret_cast<char*>(data->data),
                                  data->length));
      // We leave the base URL empty.
    }
  }

  if (data_requests_ == 0) {
    // Tell the renderer about the drag.
    // |x| and |y| are seemingly arbitrary at this point.
    tab_contents_->render_view_host()->
        DragTargetDragEnter(*drop_data_.get(),
                            gtk_util::ClientPoint(widget_),
                            gtk_util::ScreenPoint(widget_),
                            WebDragOperationCopy);
    // TODO(snej): Pass appropriate DragOperation instead of hardcoding
    drag_over_time_ = time;
  }
}

// The drag has left our widget; forward this information to the renderer.
void WebDragDestGtk::OnDragLeave(GdkDragContext* context, guint time) {
  // Set |context_| to NULL to make sure we will recognize the next DragMotion
  // as an enter.
  context_ = NULL;
  drop_data_.reset();
  // When GTK sends us a drag-drop signal, it is shortly (and synchronously)
  // preceded by a drag-leave. The renderer doesn't like getting the signals
  // in this order so delay telling it about the drag-leave till we are sure
  // we are not getting a drop as well.
  MessageLoop::current()->PostTask(FROM_HERE,
      method_factory_.NewRunnableMethod(&WebDragDestGtk::DragLeave));
}

// Called by GTK when the user releases the mouse, executing a drop.
gboolean WebDragDestGtk::OnDragDrop(GdkDragContext* context, gint x, gint y,
                                    guint time) {
  // Cancel that drag leave!
  method_factory_.RevokeAll();

  tab_contents_->render_view_host()->
      DragTargetDrop(gtk_util::ClientPoint(widget_),
                     gtk_util::ScreenPoint(widget_));

  // The second parameter is just an educated guess, but at least we will
  // get the drag-end animation right sometimes.
  gtk_drag_finish(context, is_drop_target_, FALSE, time);
  return TRUE;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/tab_contents/web_drag_dest_gtk.h"

#include <string>

#include "base/file_path.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_node_data.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/url_constants.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "net/base/net_util.h"
#include "ui/base/dragdrop/gtk_dnd_util.h"

using WebKit::WebDragOperation;
using WebKit::WebDragOperationNone;

namespace {

// Returns the bookmark target atom, based on the underlying toolkit.
//
// For GTK, bookmark drag data is encoded as pickle and associated with
// ui::CHROME_BOOKMARK_ITEM. See // bookmark_utils::WriteBookmarksToSelection()
// for details.
// For Views, bookmark drag data is encoded in the same format, and
// associated with a custom format. See BookmarkNodeData::Write() for
// details.
GdkAtom GetBookmarkTargetAtom() {
#if defined(TOOLKIT_VIEWS)
  return BookmarkNodeData::GetBookmarkCustomFormat();
#else
  return ui::GetAtomForTarget(ui::CHROME_BOOKMARK_ITEM);
#endif
}

}  // namespace

WebDragDestGtk::WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget)
    : tab_contents_(tab_contents),
      tab_(NULL),
      widget_(widget),
      context_(NULL),
      method_factory_(this) {
  gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0),
                    NULL, 0,
                    static_cast<GdkDragAction>(GDK_ACTION_COPY |
                                               GDK_ACTION_LINK |
                                               GDK_ACTION_MOVE));
  g_signal_connect(widget, "drag-motion",
                   G_CALLBACK(OnDragMotionThunk), this);
  g_signal_connect(widget, "drag-leave",
                   G_CALLBACK(OnDragLeaveThunk), this);
  g_signal_connect(widget, "drag-drop",
                   G_CALLBACK(OnDragDropThunk), this);
  g_signal_connect(widget, "drag-data-received",
                   G_CALLBACK(OnDragDataReceivedThunk), this);
  // TODO(tony): Need a drag-data-delete handler for moving content out of
  // the tab contents.  http://crbug.com/38989

  destroy_handler_ = g_signal_connect(
      widget, "destroy", G_CALLBACK(gtk_widget_destroyed), &widget_);
}

WebDragDestGtk::~WebDragDestGtk() {
  if (widget_) {
    gtk_drag_dest_unset(widget_);
    g_signal_handler_disconnect(widget_, destroy_handler_);
  }
}

void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) {
  if (context_) {
    is_drop_target_ = operation != WebDragOperationNone;
    gdk_drag_status(context_, gtk_util::WebDragOpToGdkDragAction(operation),
                    drag_over_time_);
  }
}

void WebDragDestGtk::DragLeave() {
  tab_contents_->render_view_host()->DragTargetDragLeave();

  // TODO(thestig) Turn back to DCHECKs after we figure out bug 89388.
  CHECK(tab_);
  CHECK(tab_->bookmark_tab_helper());
  if (tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()) {
    tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()->OnDragLeave(
        bookmark_drag_data_);
  }
}

gboolean WebDragDestGtk::OnDragMotion(GtkWidget* sender,
                                      GdkDragContext* context,
                                      gint x, gint y,
                                      guint time) {
  if (context_ != context) {
    context_ = context;
    drop_data_.reset(new WebDropData);
    bookmark_drag_data_.Clear();
    is_drop_target_ = false;

    // text/plain must come before text/uri-list. This is a hack that works in
    // conjunction with OnDragDataReceived. Since some file managers populate
    // text/plain with file URLs when dragging files, we want to handle
    // text/uri-list after text/plain so that the plain text can be cleared if
    // it's a file drag.
    static int supported_targets[] = {
      ui::TEXT_PLAIN,
      ui::TEXT_URI_LIST,
      ui::TEXT_HTML,
      ui::NETSCAPE_URL,
      ui::CHROME_NAMED_URL,
      // TODO(estade): support image drags?
    };

    // Add the bookmark target as well.
    data_requests_ = arraysize(supported_targets) + 1;
    for (size_t i = 0; i < arraysize(supported_targets); ++i) {
      gtk_drag_get_data(widget_, context,
                        ui::GetAtomForTarget(supported_targets[i]),
                        time);
    }

    gtk_drag_get_data(widget_, context, GetBookmarkTargetAtom(), time);
  } else if (data_requests_ == 0) {
    tab_contents_->render_view_host()->
        DragTargetDragOver(
            gtk_util::ClientPoint(widget_),
            gtk_util::ScreenPoint(widget_),
            gtk_util::GdkDragActionToWebDragOp(context->actions));
    DCHECK(tab_);
    if (tab_->bookmark_tab_helper()->GetBookmarkDragDelegate())
      tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()->OnDragOver(
          bookmark_drag_data_);
    drag_over_time_ = time;
  }

  // Pretend we are a drag destination because we don't want to wait for
  // the renderer to tell us if we really are or not.
  return TRUE;
}

void WebDragDestGtk::OnDragDataReceived(
    GtkWidget* sender, GdkDragContext* context, gint x, gint y,
    GtkSelectionData* data, guint info, guint time) {
  // We might get the data from an old get_data() request that we no longer
  // care about.
  if (context != context_)
    return;

  data_requests_--;

  // Decode the data.
  if (data->data && data->length > 0) {
    // If the source can't provide us with valid data for a requested target,
    // data->data will be NULL.
    if (data->target == ui::GetAtomForTarget(ui::TEXT_PLAIN)) {
      guchar* text = gtk_selection_data_get_text(data);
      if (text) {
        drop_data_->plain_text =
            UTF8ToUTF16(std::string(reinterpret_cast<char*>(text)));
        g_free(text);
      }
    } else if (data->target == ui::GetAtomForTarget(ui::TEXT_URI_LIST)) {
      gchar** uris = gtk_selection_data_get_uris(data);
      if (uris) {
        drop_data_->url = GURL();
        for (gchar** uri_iter = uris; *uri_iter; uri_iter++) {
          // Most file managers populate text/uri-list with file URLs when
          // dragging files. To avoid exposing file system paths to web content,
          // file URLs are never set as the URL content for the drop.
          // TODO(estade): Can the filenames have a non-UTF8 encoding?
          GURL url(*uri_iter);
          FilePath file_path;
          if (url.SchemeIs(chrome::kFileScheme) &&
              net::FileURLToFilePath(url, &file_path)) {
            drop_data_->filenames.push_back(UTF8ToUTF16(file_path.value()));
            // This is a hack. Some file managers also populate text/plain with
            // a file URL when dragging files, so we clear it to avoid exposing
            // it to the web content.
            drop_data_->plain_text.clear();
          } else if (!drop_data_->url.is_valid()) {
            // Also set the first non-file URL as the URL content for the drop.
            drop_data_->url = url;
          }
        }
        g_strfreev(uris);
      }
    } else if (data->target == ui::GetAtomForTarget(ui::TEXT_HTML)) {
      // TODO(estade): Can the html have a non-UTF8 encoding?
      drop_data_->text_html =
          UTF8ToUTF16(std::string(reinterpret_cast<char*>(data->data),
                                  data->length));
      // We leave the base URL empty.
    } else if (data->target == ui::GetAtomForTarget(ui::NETSCAPE_URL)) {
      std::string netscape_url(reinterpret_cast<char*>(data->data),
                               data->length);
      size_t split = netscape_url.find_first_of('\n');
      if (split != std::string::npos) {
        drop_data_->url = GURL(netscape_url.substr(0, split));
        if (split < netscape_url.size() - 1)
          drop_data_->url_title = UTF8ToUTF16(netscape_url.substr(split + 1));
      }
    } else if (data->target == ui::GetAtomForTarget(ui::CHROME_NAMED_URL)) {
      ui::ExtractNamedURL(data, &drop_data_->url, &drop_data_->url_title);
    }
  }

  // For CHROME_BOOKMARK_ITEM, we have to handle the case where the drag source
  // doesn't have any data available for us. In this case we try to synthesize a
  // URL bookmark.
  // Note that bookmark drag data is encoded in the same format for both
  // GTK and Views, hence we can share the same logic here.
  if (data->target == GetBookmarkTargetAtom()) {
    if (data->data && data->length > 0) {
      Profile* profile =
          Profile::FromBrowserContext(tab_contents_->browser_context());
      bookmark_drag_data_.ReadFromVector(
          bookmark_utils::GetNodesFromSelection(
              NULL, data,
              ui::CHROME_BOOKMARK_ITEM,
              profile, NULL, NULL));
      bookmark_drag_data_.SetOriginatingProfile(profile);
    } else {
      bookmark_drag_data_.ReadFromTuple(drop_data_->url,
                                        drop_data_->url_title);
    }
  }

  if (data_requests_ == 0) {
    // Tell the renderer about the drag.
    // |x| and |y| are seemingly arbitrary at this point.
    tab_contents_->render_view_host()->
        DragTargetDragEnter(*drop_data_.get(),
            gtk_util::ClientPoint(widget_),
            gtk_util::ScreenPoint(widget_),
            gtk_util::GdkDragActionToWebDragOp(context->actions));

    if (!tab_) {
      tab_ = TabContentsWrapper::GetCurrentWrapperForContents(tab_contents_);
      DCHECK(tab_);
    }
    // This is non-null if tab_contents_ is showing an ExtensionWebUI with
    // support for (at the moment experimental) drag and drop extensions.
    if (tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()) {
      tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()->OnDragEnter(
          bookmark_drag_data_);
    }
    drag_over_time_ = time;
  }
}

// The drag has left our widget; forward this information to the renderer.
void WebDragDestGtk::OnDragLeave(GtkWidget* sender, GdkDragContext* context,
                                 guint time) {
  // Set |context_| to NULL to make sure we will recognize the next DragMotion
  // as an enter.
  context_ = NULL;
  drop_data_.reset();
  // When GTK sends us a drag-drop signal, it is shortly (and synchronously)
  // preceded by a drag-leave. The renderer doesn't like getting the signals
  // in this order so delay telling it about the drag-leave till we are sure
  // we are not getting a drop as well.
  MessageLoop::current()->PostTask(FROM_HERE,
      method_factory_.NewRunnableMethod(&WebDragDestGtk::DragLeave));
}

// Called by GTK when the user releases the mouse, executing a drop.
gboolean WebDragDestGtk::OnDragDrop(GtkWidget* sender, GdkDragContext* context,
                                    gint x, gint y, guint time) {
  // Cancel that drag leave!
  method_factory_.RevokeAll();

  tab_contents_->render_view_host()->
      DragTargetDrop(gtk_util::ClientPoint(widget_),
                     gtk_util::ScreenPoint(widget_));

  DCHECK(tab_);
  // This is non-null if tab_contents_ is showing an ExtensionWebUI with
  // support for (at the moment experimental) drag and drop extensions.
  if (tab_->bookmark_tab_helper()->GetBookmarkDragDelegate())
    tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()->OnDrop(
        bookmark_drag_data_);

  // Focus the target browser.
  Browser* browser = Browser::GetBrowserForController(
      &tab_contents_->controller(), NULL);
  if (browser)
    browser->window()->Show();

  // The second parameter is just an educated guess as to whether or not the
  // drag succeeded, but at least we will get the drag-end animation right
  // sometimes.
  gtk_drag_finish(context, is_drop_target_, FALSE, time);

  return TRUE;
}
<commit_msg>Fix a crash on Linux which occurs during drag drop operations in the renderer while dereferncing a NULL TabContentsWrapper pointer.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/tab_contents/web_drag_dest_gtk.h"

#include <string>

#include "base/file_path.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_node_data.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/url_constants.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "net/base/net_util.h"
#include "ui/base/dragdrop/gtk_dnd_util.h"

using WebKit::WebDragOperation;
using WebKit::WebDragOperationNone;

namespace {

// Returns the bookmark target atom, based on the underlying toolkit.
//
// For GTK, bookmark drag data is encoded as pickle and associated with
// ui::CHROME_BOOKMARK_ITEM. See // bookmark_utils::WriteBookmarksToSelection()
// for details.
// For Views, bookmark drag data is encoded in the same format, and
// associated with a custom format. See BookmarkNodeData::Write() for
// details.
GdkAtom GetBookmarkTargetAtom() {
#if defined(TOOLKIT_VIEWS)
  return BookmarkNodeData::GetBookmarkCustomFormat();
#else
  return ui::GetAtomForTarget(ui::CHROME_BOOKMARK_ITEM);
#endif
}

}  // namespace

WebDragDestGtk::WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget)
    : tab_contents_(tab_contents),
      tab_(NULL),
      widget_(widget),
      context_(NULL),
      method_factory_(this) {
  gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0),
                    NULL, 0,
                    static_cast<GdkDragAction>(GDK_ACTION_COPY |
                                               GDK_ACTION_LINK |
                                               GDK_ACTION_MOVE));
  g_signal_connect(widget, "drag-motion",
                   G_CALLBACK(OnDragMotionThunk), this);
  g_signal_connect(widget, "drag-leave",
                   G_CALLBACK(OnDragLeaveThunk), this);
  g_signal_connect(widget, "drag-drop",
                   G_CALLBACK(OnDragDropThunk), this);
  g_signal_connect(widget, "drag-data-received",
                   G_CALLBACK(OnDragDataReceivedThunk), this);
  // TODO(tony): Need a drag-data-delete handler for moving content out of
  // the tab contents.  http://crbug.com/38989

  destroy_handler_ = g_signal_connect(
      widget, "destroy", G_CALLBACK(gtk_widget_destroyed), &widget_);
}

WebDragDestGtk::~WebDragDestGtk() {
  if (widget_) {
    gtk_drag_dest_unset(widget_);
    g_signal_handler_disconnect(widget_, destroy_handler_);
  }
}

void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) {
  if (context_) {
    is_drop_target_ = operation != WebDragOperationNone;
    gdk_drag_status(context_, gtk_util::WebDragOpToGdkDragAction(operation),
                    drag_over_time_);
  }
}

void WebDragDestGtk::DragLeave() {
  tab_contents_->render_view_host()->DragTargetDragLeave();

  DCHECK(tab_);
  if (tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()) {
    tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()->OnDragLeave(
        bookmark_drag_data_);
  }
}

gboolean WebDragDestGtk::OnDragMotion(GtkWidget* sender,
                                      GdkDragContext* context,
                                      gint x, gint y,
                                      guint time) {
  // Ideally we would want to initialize the the TabContentsWrapper member in
  // the constructor. We cannot do that as the WebDragDestGtk object is
  // created during the construction of the TabContents object.
  // The TabContentsWrapper is created much later.
  if (!tab_) {
    tab_ = TabContentsWrapper::GetCurrentWrapperForContents(tab_contents_);
    DCHECK(tab_);
  }
  if (context_ != context) {
    context_ = context;
    drop_data_.reset(new WebDropData);
    bookmark_drag_data_.Clear();
    is_drop_target_ = false;

    // text/plain must come before text/uri-list. This is a hack that works in
    // conjunction with OnDragDataReceived. Since some file managers populate
    // text/plain with file URLs when dragging files, we want to handle
    // text/uri-list after text/plain so that the plain text can be cleared if
    // it's a file drag.
    static int supported_targets[] = {
      ui::TEXT_PLAIN,
      ui::TEXT_URI_LIST,
      ui::TEXT_HTML,
      ui::NETSCAPE_URL,
      ui::CHROME_NAMED_URL,
      // TODO(estade): support image drags?
    };

    // Add the bookmark target as well.
    data_requests_ = arraysize(supported_targets) + 1;
    for (size_t i = 0; i < arraysize(supported_targets); ++i) {
      gtk_drag_get_data(widget_, context,
                        ui::GetAtomForTarget(supported_targets[i]),
                        time);
    }

    gtk_drag_get_data(widget_, context, GetBookmarkTargetAtom(), time);
  } else if (data_requests_ == 0) {
    tab_contents_->render_view_host()->
        DragTargetDragOver(
            gtk_util::ClientPoint(widget_),
            gtk_util::ScreenPoint(widget_),
            gtk_util::GdkDragActionToWebDragOp(context->actions));
    DCHECK(tab_);
    if (tab_->bookmark_tab_helper()->GetBookmarkDragDelegate())
      tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()->OnDragOver(
          bookmark_drag_data_);
    drag_over_time_ = time;
  }

  // Pretend we are a drag destination because we don't want to wait for
  // the renderer to tell us if we really are or not.
  return TRUE;
}

void WebDragDestGtk::OnDragDataReceived(
    GtkWidget* sender, GdkDragContext* context, gint x, gint y,
    GtkSelectionData* data, guint info, guint time) {
  // We might get the data from an old get_data() request that we no longer
  // care about.
  if (context != context_)
    return;

  data_requests_--;

  // Decode the data.
  if (data->data && data->length > 0) {
    // If the source can't provide us with valid data for a requested target,
    // data->data will be NULL.
    if (data->target == ui::GetAtomForTarget(ui::TEXT_PLAIN)) {
      guchar* text = gtk_selection_data_get_text(data);
      if (text) {
        drop_data_->plain_text =
            UTF8ToUTF16(std::string(reinterpret_cast<char*>(text)));
        g_free(text);
      }
    } else if (data->target == ui::GetAtomForTarget(ui::TEXT_URI_LIST)) {
      gchar** uris = gtk_selection_data_get_uris(data);
      if (uris) {
        drop_data_->url = GURL();
        for (gchar** uri_iter = uris; *uri_iter; uri_iter++) {
          // Most file managers populate text/uri-list with file URLs when
          // dragging files. To avoid exposing file system paths to web content,
          // file URLs are never set as the URL content for the drop.
          // TODO(estade): Can the filenames have a non-UTF8 encoding?
          GURL url(*uri_iter);
          FilePath file_path;
          if (url.SchemeIs(chrome::kFileScheme) &&
              net::FileURLToFilePath(url, &file_path)) {
            drop_data_->filenames.push_back(UTF8ToUTF16(file_path.value()));
            // This is a hack. Some file managers also populate text/plain with
            // a file URL when dragging files, so we clear it to avoid exposing
            // it to the web content.
            drop_data_->plain_text.clear();
          } else if (!drop_data_->url.is_valid()) {
            // Also set the first non-file URL as the URL content for the drop.
            drop_data_->url = url;
          }
        }
        g_strfreev(uris);
      }
    } else if (data->target == ui::GetAtomForTarget(ui::TEXT_HTML)) {
      // TODO(estade): Can the html have a non-UTF8 encoding?
      drop_data_->text_html =
          UTF8ToUTF16(std::string(reinterpret_cast<char*>(data->data),
                                  data->length));
      // We leave the base URL empty.
    } else if (data->target == ui::GetAtomForTarget(ui::NETSCAPE_URL)) {
      std::string netscape_url(reinterpret_cast<char*>(data->data),
                               data->length);
      size_t split = netscape_url.find_first_of('\n');
      if (split != std::string::npos) {
        drop_data_->url = GURL(netscape_url.substr(0, split));
        if (split < netscape_url.size() - 1)
          drop_data_->url_title = UTF8ToUTF16(netscape_url.substr(split + 1));
      }
    } else if (data->target == ui::GetAtomForTarget(ui::CHROME_NAMED_URL)) {
      ui::ExtractNamedURL(data, &drop_data_->url, &drop_data_->url_title);
    }
  }

  // For CHROME_BOOKMARK_ITEM, we have to handle the case where the drag source
  // doesn't have any data available for us. In this case we try to synthesize a
  // URL bookmark.
  // Note that bookmark drag data is encoded in the same format for both
  // GTK and Views, hence we can share the same logic here.
  if (data->target == GetBookmarkTargetAtom()) {
    if (data->data && data->length > 0) {
      Profile* profile =
          Profile::FromBrowserContext(tab_contents_->browser_context());
      bookmark_drag_data_.ReadFromVector(
          bookmark_utils::GetNodesFromSelection(
              NULL, data,
              ui::CHROME_BOOKMARK_ITEM,
              profile, NULL, NULL));
      bookmark_drag_data_.SetOriginatingProfile(profile);
    } else {
      bookmark_drag_data_.ReadFromTuple(drop_data_->url,
                                        drop_data_->url_title);
    }
  }

  if (data_requests_ == 0) {
    // Tell the renderer about the drag.
    // |x| and |y| are seemingly arbitrary at this point.
    tab_contents_->render_view_host()->
        DragTargetDragEnter(*drop_data_.get(),
            gtk_util::ClientPoint(widget_),
            gtk_util::ScreenPoint(widget_),
            gtk_util::GdkDragActionToWebDragOp(context->actions));

    DCHECK(tab_);
    // This is non-null if tab_contents_ is showing an ExtensionWebUI with
    // support for (at the moment experimental) drag and drop extensions.
    if (tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()) {
      tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()->OnDragEnter(
          bookmark_drag_data_);
    }
    drag_over_time_ = time;
  }
}

// The drag has left our widget; forward this information to the renderer.
void WebDragDestGtk::OnDragLeave(GtkWidget* sender, GdkDragContext* context,
                                 guint time) {
  // Set |context_| to NULL to make sure we will recognize the next DragMotion
  // as an enter.
  context_ = NULL;
  drop_data_.reset();
  // When GTK sends us a drag-drop signal, it is shortly (and synchronously)
  // preceded by a drag-leave. The renderer doesn't like getting the signals
  // in this order so delay telling it about the drag-leave till we are sure
  // we are not getting a drop as well.
  MessageLoop::current()->PostTask(FROM_HERE,
      method_factory_.NewRunnableMethod(&WebDragDestGtk::DragLeave));
}

// Called by GTK when the user releases the mouse, executing a drop.
gboolean WebDragDestGtk::OnDragDrop(GtkWidget* sender, GdkDragContext* context,
                                    gint x, gint y, guint time) {
  // Cancel that drag leave!
  method_factory_.RevokeAll();

  tab_contents_->render_view_host()->
      DragTargetDrop(gtk_util::ClientPoint(widget_),
                     gtk_util::ScreenPoint(widget_));

  DCHECK(tab_);
  // This is non-null if tab_contents_ is showing an ExtensionWebUI with
  // support for (at the moment experimental) drag and drop extensions.
  if (tab_->bookmark_tab_helper()->GetBookmarkDragDelegate())
    tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()->OnDrop(
        bookmark_drag_data_);

  // Focus the target browser.
  Browser* browser = Browser::GetBrowserForController(
      &tab_contents_->controller(), NULL);
  if (browser)
    browser->window()->Show();

  // The second parameter is just an educated guess as to whether or not the
  // drag succeeded, but at least we will get the drag-end animation right
  // sometimes.
  gtk_drag_finish(context, is_drop_target_, FALSE, time);

  return TRUE;
}
<|endoftext|>