<commit_before>#include "cs296_base.hpp"
#include "render.hpp"

#ifdef __APPLE__
	#include <GLUT/glut.h>
#else
	#include "GL/freeglut.h"
#endif

#include <cstring>
using namespace std;

#include "dominos.hpp"

namespace cs296
{
   b2Body* frontgear;
   ///back wheel
   b2Body* wheel1;
  void dominos_t::keyboard(unsigned char key)
  {
	  switch(key){
		case('w'):
		frontgear->ApplyAngularImpulse( -50,0 );
		break;
		case('s'):
		wheel1->ApplyAngularImpulse( 50,0 );
		break;
	}
  }
  dominos_t::dominos_t()
  {
/////////////////////////////////////////////////////////////////////////////
    ///Ground
    {
      //ground floor
      b2EdgeShape shape;
      shape.Set(b2Vec2(-90.0f, 0.0f), b2Vec2(90.0f, 0.0f));
      b2FixtureDef *grnd = new b2FixtureDef;
      grnd->filter.categoryBits = 0x00F4;//
	  grnd->filter.maskBits = 0x00F2;//
	  grnd->shape=&shape;
	  b2BodyDef bd;
	  b2Body* b1=m_world->CreateBody(&bd);
      b1->CreateFixture(grnd);
    }
//////////////////////////////////////////////////////////////////////////////
	 ///Add wheels
	 b2CircleShape circleDef;
	 circleDef.m_radius = 8;
	 b2FixtureDef *fd2 = new b2FixtureDef;
	 fd2->density = 0.1f;
	 fd2->friction = 5;
	 fd2->restitution = 0.2;
	 fd2->filter.groupIndex = -1;
	 fd2->shape=new b2CircleShape;
	 fd2->shape=&circleDef;
	 fd2->filter.categoryBits = 0x00F2;//
	 fd2->filter.maskBits = 0x00F4;//

	 ///front wheel
	 b2Body* wheel2;
	 b2BodyDef* wheelDef = new b2BodyDef;
	 wheelDef->type = b2_dynamicBody;
	 wheelDef->allowSleep = false;

	 wheelDef->position.Set(-20,8);
	 wheel1 = m_world->CreateBody(wheelDef);
	 wheel1->CreateFixture(fd2);

	 wheelDef->position.Set(10,8);
	 wheel2 = m_world->CreateBody(wheelDef);
	 wheel2->CreateFixture(fd2);
//////////////////////////////////////////////////////////////////////////////
	 ///Add cycle frame
	 b2PolygonShape boxshape;
	 boxshape.SetAsBox(7,0.6,b2Vec2(7,0),0);
	 b2FixtureDef *fd1 = new b2FixtureDef;
	 fd1->density = 0.1f;

	 fd1->filter.categoryBits = 0x00F2;//
	 fd1->filter.maskBits = 0x00F4;//
	 fd1->friction = 0.5f;
	 fd1->restitution = 0.2f;
	 fd1->filter.groupIndex = -1;
	 fd1->shape = new b2PolygonShape;
	 fd1->shape = &boxshape;
	 b2BodyDef* rodDef=new b2BodyDef;
	 rodDef->type= b2_dynamicBody;

	 rodDef->position.Set(wheel1->GetWorldCenter().x, wheel1->GetWorldCenter().y);
	 b2Body* rodbody=m_world->CreateBody(rodDef);
	 rodbody->CreateFixture(fd1);

	 boxshape.SetAsBox(8,0.6,b2Vec2(8*cosf(b2_pi/3),8*sinf(b2_pi/3)),b2_pi/3);
	 rodbody->CreateFixture(fd1);

	 boxshape.SetAsBox(8,0.6,b2Vec2(30-8*cosf(b2_pi/3),8*sinf(b2_pi/3)),-b2_pi/3);
	 rodbody->CreateFixture(fd1);

	 boxshape.SetAsBox(7,0.6,b2Vec2(15,16*sinf(b2_pi/3)),0);
	 rodbody->CreateFixture(fd1);

	 boxshape.SetAsBox(8,0.6,b2Vec2(14+8*cosf(b2_pi/3),8*sinf(b2_pi/3)),b2_pi/3);
	 rodbody->CreateFixture(fd1);

//////////////////////////////////////////////////////////////////////////////
	 ///Adding Rovolute Joints between tires and cycle frame
	 b2RevoluteJointDef revoluteJointDef;
	 revoluteJointDef.enableMotor = true;

	 revoluteJointDef.Initialize(rodbody, wheel1, wheel1->GetWorldCenter());
	 m_world->CreateJoint(&revoluteJointDef);

	 revoluteJointDef.Initialize(rodbody, wheel2, wheel2->GetWorldCenter());
	 m_world->CreateJoint(&revoluteJointDef);

//////////////////////////////////////////////////////////////////////////////

	  ///back gear
	  b2CircleShape gearshape;
	  gearshape.m_radius = 3.0;
	  b2FixtureDef gearfd;
	  //ballfd.filter.groupIndex = -2;
	  gearfd.filter.categoryBits = 0x0002;//
	  gearfd.filter.maskBits = 0x0004;//
	  gearfd.shape = &gearshape;
	  gearfd.density = 5.0f;
	  gearfd.friction = 100.0f;
	  gearfd.restitution = 0.0f;
	  b2BodyDef gearbd;
	  gearbd.type = b2_dynamicBody;
	  gearbd.position.Set(-20.0f, 8.0f);
	  b2Body* gearbody1 = m_world->CreateBody(&gearbd);
	  gearbody1->CreateFixture(&gearfd);

	  ///Front gear
	  gearbd.position.Set(-6.0f, 8.0f);
	  frontgear = m_world->CreateBody(&gearbd);
	  frontgear->CreateFixture(&gearfd);

//////////////////////////////////////////////////////////////////////////////
	///Adding Revolute joints between gears and cycle frame
	b2RevoluteJointDef jointDef1;
	jointDef1.Initialize(gearbody1, rodbody, gearbody1->GetWorldCenter());
	m_world->CreateJoint(&jointDef1);

	b2RevoluteJointDef jointDef2;
	jointDef2.Initialize(frontgear, rodbody, frontgear->GetWorldCenter());
	m_world->CreateJoint(&jointDef2);
//////////////////////////////////////////////////////////////////////////////

b2Vec2 vs[44];
b2Body* conveyer[44];

 for (int i = 0; i < 16; ++i)
	{
	vs[i].Set(-21.0f+1.0f*i,11.0f);
    b2FixtureDef ballfd4;
    ballfd4.filter.categoryBits = 0x0004;
      ballfd4.filter.maskBits = 0x0002;ballfd4.filter.groupIndex = -1;

    //ballfd2.filter.groupIndex = -2;
	b2PolygonShape shape;
	shape.SetAsBox(.5f, 0.25f);
	ballfd4.shape = &shape;
	ballfd4.density=5.1f;
	gearfd.friction=100.0f;
	b2BodyDef bd4;
	bd4.type = b2_dynamicBody;
	bd4.position.Set(-20.5f+1.0f*i,11.0f);
	conveyer[i] = m_world->CreateBody(&bd4);
	conveyer[i]->CreateFixture(&ballfd4);
	}
 for (int i = 0; i < 6; ++i)
	{
		vs[16+i].Set(-5.0f,11.0f-i*1.0f);
		b2FixtureDef ballfd4;

    ballfd4.filter.categoryBits = 0x0004;
      ballfd4.filter.maskBits = 0x0002;ballfd4.filter.groupIndex = -1;
    //ballfd2.filter.groupIndex = -2;
	b2PolygonShape shape;
	shape.SetAsBox(.25f, 0.5f);
	ballfd4.shape = &shape;
		ballfd4.density=5.1f;
	gearfd.friction=100.0f;
	b2BodyDef bd4;
	bd4.type = b2_dynamicBody;
	bd4.position.Set(-5.0f,10.5f-i*1.0f);
	conveyer[i+16] = m_world->CreateBody(&bd4);
	conveyer[i+16]->CreateFixture(&ballfd4);
	}
 for (int i = 0; i < 16; ++i)
	{
		vs[22+i].Set(-5.0f-1.0f*i,5.0f);

    b2FixtureDef ballfd4;
    ballfd4.filter.categoryBits = 0x0004;
      ballfd4.filter.maskBits = 0x0002;ballfd4.filter.groupIndex = -1;
    //ballfd2.filter.groupIndex = -2;
	b2PolygonShape shape;
	shape.SetAsBox(.5f, 0.25f);
	ballfd4.shape = &shape;
	b2BodyDef bd4;
	ballfd4.density=5.1f;
	gearfd.friction=100.0f;
	bd4.type = b2_dynamicBody;
	bd4.position.Set(-5.5f-1.0f*i,5.0f);
	conveyer[i+22] = m_world->CreateBody(&bd4);
	conveyer[i+22]->CreateFixture(&ballfd4);
	}
 for (int i = 0; i < 6; ++i)
	{
		vs[38+i].Set(-21.0f,5.0f+1.0f*i);
    b2FixtureDef ballfd4;
    ballfd4.filter.categoryBits = 0x0004;
      ballfd4.filter.maskBits = 0x0002;ballfd4.filter.groupIndex = -1;
    //ballfd2.filter.groupIndex = -2;
	b2PolygonShape shape;
	shape.SetAsBox(.25f, 0.55f);
	ballfd4.shape = &shape;
	b2BodyDef bd4;
	ballfd4.density=5.1f;
	gearfd.friction=100.0f;
	bd4.type = b2_dynamicBody;
	bd4.position.Set(-21.0f,5.0f+1.0f*i+.5f);
	conveyer[i+38] = m_world->CreateBody(&bd4);
	conveyer[i+38]->CreateFixture(&ballfd4);
	}

for(int i=1;i<44;i++)
{
	b2RevoluteJointDef jointDef3;
	jointDef3.Initialize(conveyer[i-1], conveyer[i],vs[i]);
	m_world->CreateJoint(&jointDef3);
}
b2RevoluteJointDef jointDef3;
	jointDef3.Initialize(conveyer[0], conveyer[43],vs[0]);
	m_world->CreateJoint(&jointDef3);

	b2Body* b5;
      b2FixtureDef ballfd5;
      //ballfd2.filter.groupIndex = -2;
	ballfd5.filter.categoryBits = 0x0003;
      ballfd5.filter.maskBits = 0x0001;
      b2PolygonShape shape5;
	shape5.SetAsBox(.25f, 4.5f);
	ballfd5.shape = &shape5;
	ballfd5.density=2.0f;
	b2BodyDef bd5;
	bd5.type = b2_dynamicBody;
	bd5.position.Set(-6.0f, 8.0f);
	b5 = m_world->CreateBody(&bd5);
	b5->CreateFixture(&ballfd5);
	//b5->SetAngularVelocity(0.2f);
	b2WeldJointDef jointDef5;
	jointDef5.Initialize(frontgear, b5, frontgear->GetWorldCenter());//,frontgear->GetWorldCenter());//,frontgear->GetWorldCenter());
	m_world->CreateJoint(&jointDef5);
	//b2DistanceJointDef jointDef51;
	//b//2Vec2 a;
	//a.Set(18.5f,1.5f);
	//jointDef51.Initialize(frontgear, b5,a,a); //(18.5f,1.5f),(18.5f,1.5f));frontgear->GetWorldCenter());//,frontgear->GetWorldCenter());
	//m_world->CreateJoint(&jointDef51);

	b2Body* b6;
      b2FixtureDef ballfd6;
      //ballfd2.filter.groupIndex = -2;
	ballfd5.filter.categoryBits = 0x0008;
      ballfd5.filter.maskBits = 0x0008;
      b2PolygonShape shape6;
	shape6.SetAsBox(1.25f, .25f);
	ballfd6.shape = &shape6;
	b2BodyDef bd6;
	bd6.fixedRotation=true;
	bd6.type = b2_dynamicBody;
	bd6.position.Set(-6.0f, 4.0f);
	b6 = m_world->CreateBody(&bd6);
	b6->CreateFixture(&ballfd6);
	//b6->SetAngularVelocity(1.0f);
	b2RevoluteJointDef jointDef6;
	jointDef6.Initialize(b5, b6, b6->GetWorldCenter());//,frontgear->GetWorldCenter());//,frontgear->GetWorldCenter());
	m_world->CreateJoint(&jointDef6);
	b2Body* b7;
      b2FixtureDef ballfd7;
      //ballfd2.filter.groupIndex = -2;
	ballfd5.filter.categoryBits = 0x0008;
      ballfd5.filter.maskBits = 0x0008;
      b2PolygonShape shape7;
	shape7.SetAsBox(1.25f, .25f);
	ballfd7.shape = &shape7;
	b2BodyDef bd7;
	bd7.fixedRotation=true;
	bd7.type = b2_dynamicBody;
	bd7.position.Set(-6.0f, 12.0f);
	b7 = m_world->CreateBody(&bd7);
	b7->CreateFixture(&ballfd7);
	//b6->SetAngularVelocity(1.0f);
	b2RevoluteJointDef jointDef7;
	jointDef7.Initialize(b5, b7, b7->GetWorldCenter());//,frontgear->GetWorldCenter());//,frontgear->GetWorldCenter());
	m_world->CreateJoint(&jointDef7);
	//weld joining gear1 to wheel1
	b2WeldJointDef jointDef8;
	jointDef8.Initialize(gearbody1, wheel1, gearbody1->GetWorldCenter());//,frontgear->GetWorldCenter());//,frontgear->GetWorldCenter());
	m_world->CreateJoint(&jointDef8);
}
  sim_t *sim = new sim_t("Dominos", dominos_t::create);
}
<commit_msg>Organized,minimized,commented the complete code<commit_after>#include "cs296_base.hpp"
#include "render.hpp"

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include "GL/freeglut.h"
#endif

#include <cstring>
using namespace std;

#include "dominos.hpp"

namespace cs296
{
	b2Body* frontgear;
	///back wheel
	b2Body* wheel1;
	void dominos_t::keyboard(unsigned char key)
	{
	  switch(key){
		case('w'):
		frontgear->ApplyAngularImpulse( -50,0 );
		break;
		case('s'):
		wheel1->ApplyAngularImpulse( 50,0 );
		break;
	}
	}
dominos_t::dominos_t()
{
/////////////////////////////////////////////////////////////////////////////
	///Ground
	{
	  b2EdgeShape shape;
	  shape.Set(b2Vec2(-90.0f, 0.0f), b2Vec2(90.0f, 0.0f));
	  b2FixtureDef *grnd = new b2FixtureDef;
	  grnd->filter.categoryBits = 0x00F4;//
	  grnd->filter.maskBits = 0x00F2;//
	  grnd->shape=&shape;
	  b2BodyDef bd;
	  b2Body* b1=m_world->CreateBody(&bd);
	  b1->CreateFixture(grnd);
	}
//////////////////////////////////////////////////////////////////////////////
	 ///Add wheels
	 b2CircleShape circleDef;
	 circleDef.m_radius = 8;
	 b2FixtureDef *fd2 = new b2FixtureDef;
	 fd2->density = 0.1f;
	 fd2->friction = 5;
	 fd2->restitution = 0.2;
	 fd2->filter.groupIndex = -1;//
	 fd2->shape=new b2CircleShape;
	 fd2->shape=&circleDef;
	 fd2->filter.categoryBits = 0x00F2;//
	 fd2->filter.maskBits = 0x00F4;//

	 ///front wheel
	 b2Body* wheel2;
	 b2BodyDef* wheelDef = new b2BodyDef;
	 wheelDef->type = b2_dynamicBody;
	 wheelDef->allowSleep = false;

	 wheelDef->position.Set(-20,8);
	 wheel1 = m_world->CreateBody(wheelDef);
	 wheel1->CreateFixture(fd2);

	 wheelDef->position.Set(10,8);
	 wheel2 = m_world->CreateBody(wheelDef);
	 wheel2->CreateFixture(fd2);
//////////////////////////////////////////////////////////////////////////////
	 ///Add cycle frame
	 b2PolygonShape boxshape;
	 boxshape.SetAsBox(7,0.6,b2Vec2(7,0),0);
	 b2FixtureDef *fd1 = new b2FixtureDef;
	 fd1->density = 0.1f;

	 fd1->filter.categoryBits = 0x00F2;//
	 fd1->filter.maskBits = 0x00F4;//
	 fd1->friction = 0.5f;
	 fd1->restitution = 0.2f;
	 fd1->filter.groupIndex = -1;//
	 fd1->shape = new b2PolygonShape;
	 fd1->shape = &boxshape;
	 b2BodyDef* rodDef=new b2BodyDef;
	 rodDef->type= b2_dynamicBody;

	 rodDef->position.Set(wheel1->GetWorldCenter().x, wheel1->GetWorldCenter().y);
	 b2Body* rodbody=m_world->CreateBody(rodDef);
	 rodbody->CreateFixture(fd1);

	 boxshape.SetAsBox(8,0.6,b2Vec2(8*cosf(b2_pi/3),8*sinf(b2_pi/3)),b2_pi/3);
	 rodbody->CreateFixture(fd1);

	 boxshape.SetAsBox(8,0.6,b2Vec2(30-8*cosf(b2_pi/3),8*sinf(b2_pi/3)),-b2_pi/3);
	 rodbody->CreateFixture(fd1);

	 boxshape.SetAsBox(7,0.6,b2Vec2(15,16*sinf(b2_pi/3)),0);
	 rodbody->CreateFixture(fd1);

	 boxshape.SetAsBox(8,0.6,b2Vec2(14+8*cosf(b2_pi/3),8*sinf(b2_pi/3)),b2_pi/3);
	 rodbody->CreateFixture(fd1);

//////////////////////////////////////////////////////////////////////////////
	 ///Adding Rovolute Joints between tires and cycle frame
	 b2RevoluteJointDef revoluteJointDef;
	 revoluteJointDef.enableMotor = true;

	 revoluteJointDef.Initialize(rodbody, wheel1, wheel1->GetWorldCenter());
	 m_world->CreateJoint(&revoluteJointDef);

	 revoluteJointDef.Initialize(rodbody, wheel2, wheel2->GetWorldCenter());
	 m_world->CreateJoint(&revoluteJointDef);

//////////////////////////////////////////////////////////////////////////////

	///back gear
	b2CircleShape gearshape;
	gearshape.m_radius = 3.0;
	b2FixtureDef gearfd;
	//ballfd.filter.groupIndex = -2;
	gearfd.filter.categoryBits = 0x0002;//
	gearfd.filter.maskBits = 0x0004;//
	gearfd.shape = &gearshape;
	gearfd.density = 5.0f;
	gearfd.friction = 100.0f;
	gearfd.restitution = 0.0f;
	b2BodyDef gearbd;
	gearbd.type = b2_dynamicBody;
	gearbd.position.Set(-20.0f, 8.0f);
	b2Body* gearbody1 = m_world->CreateBody(&gearbd);
	gearbody1->CreateFixture(&gearfd);

	///Front gear
	gearbd.position.Set(-6.0f, 8.0f);
	frontgear = m_world->CreateBody(&gearbd);
	frontgear->CreateFixture(&gearfd);

//////////////////////////////////////////////////////////////////////////////
	///Adding Revolute joints between gears and cycle frame
	b2RevoluteJointDef jointDef1;
	jointDef1.Initialize(gearbody1, rodbody, gearbody1->GetWorldCenter());
	m_world->CreateJoint(&jointDef1);

	b2RevoluteJointDef jointDef2;
	jointDef2.Initialize(frontgear, rodbody, frontgear->GetWorldCenter());
	m_world->CreateJoint(&jointDef2);
//////////////////////////////////////////////////////////////////////////////
	///Adding the Chain
	b2Vec2 vs[44];
	b2Body* conveyer[44];

	b2FixtureDef chainfd;
    chainfd.filter.categoryBits = 0x0004;//these are different
    chainfd.filter.maskBits = 0x0002;//
    chainfd.filter.groupIndex = -1;//
    //ballfd2.filter.groupIndex = -2;
	b2PolygonShape chainshape;
	chainshape.SetAsBox(0.5f, 0.25f);
	chainfd.shape = &chainshape;
	chainfd.density=5.1f;
	b2BodyDef chainDef;
	chainDef.type = b2_dynamicBody;

	///The top chain units
 for (int i = 0; i < 16; ++i)
	{
	vs[i].Set(-21.0f+1.0f*i,11.0f);
	chainDef.position.Set(-20.5f+1.0f*i,11.0f);
	conveyer[i]=m_world->CreateBody(&chainDef);
	conveyer[i]->CreateFixture(&chainfd);
	}

	///The right chain units
	chainshape.SetAsBox(0.25f, 0.5f);
 for (int i = 0; i < 6; ++i)
	{
	vs[i+16].Set(-5.0f,11.0f-i*1.0f);
	chainDef.position.Set(-5.0f,10.5f-i*1.0f);
	conveyer[i+16]=m_world->CreateBody(&chainDef);
	conveyer[i+16]->CreateFixture(&chainfd);
	}

	///The Bottom chain units
	chainshape.SetAsBox(0.5f, 0.25f);
 for (int i = 0; i < 16; ++i)
	{
	vs[i+22].Set(-5.0f-1.0f*i,5.0f);
	chainDef.position.Set(-5.5f-1.0f*i,5.0f);
	conveyer[i+22]=m_world->CreateBody(&chainDef);
	conveyer[i+22]->CreateFixture(&chainfd);
	}

	///The left chain units
	chainshape.SetAsBox(0.25f, 0.5f);
 for (int i = 0; i < 6; ++i)
	{
	vs[i+38].Set(-21.0f,5.0f+1.0f*i);
	chainDef.position.Set(-21.0f,5.0f+1.0f*i+.5f);
	conveyer[i+38] = m_world->CreateBody(&chainDef);
	conveyer[i+38]->CreateFixture(&chainfd);
	}
//////////////////////////////////////////////////////////////////////////////
	///Adding Revolute joint between chain units
	b2RevoluteJointDef jointDef3;
 for(int i=1;i<44;i++)
	{
	jointDef3.Initialize(conveyer[i-1], conveyer[i],vs[i]);
	m_world->CreateJoint(&jointDef3);
	}

	jointDef3.Initialize(conveyer[0], conveyer[43],vs[0]);
	m_world->CreateJoint(&jointDef3);
//////////////////////////////////////////////////////////////////////////////
	///Creating connecting pedal rod and pedals
    b2FixtureDef pedalfd;
    //ballfd2.filter.groupIndex = -2;
	pedalfd.filter.categoryBits = 0x0003;
    pedalfd.filter.maskBits = 0x0001;
	pedalfd.density=2.0f;
	b2PolygonShape pedrodshape;
	pedrodshape.SetAsBox(.25f, 4.5f);
	pedalfd.shape = &pedrodshape;
	b2BodyDef pedalDef;
	pedalDef.type = b2_dynamicBody;
	pedalDef.position.Set(-6.0f, 8.0f);
	///Creating the rod connecting the pedals which i call pedalrod
	b2Body* pedalbody = m_world->CreateBody(&pedalDef);
	pedalbody->CreateFixture(&pedalfd);

	///welding pedalrod to cycle frame front gear
	b2WeldJointDef jointDef4;
	jointDef4.Initialize(frontgear, pedalbody, frontgear->GetWorldCenter());
	m_world->CreateJoint(&jointDef4);
//////////////////////////////////////////////////////////////////////////////
	///pedal1: Creating the first pedal
    //ballfd2.filter.groupIndex = -2;
	pedalfd.filter.categoryBits = 0x0008;
    pedalfd.filter.maskBits = 0x0008;
	pedrodshape.SetAsBox(1.25f, .25f);
	pedalDef.fixedRotation=true;
	pedalDef.position.Set(-6.0f, 4.0f);
	b2Body* pedal1 = m_world->CreateBody(&pedalDef);
	pedal1->CreateFixture(&pedalfd);

	///Creating a revolute joint between pedal1 and pedal rod
	b2RevoluteJointDef jointDef5;
	jointDef5.Initialize(pedalbody, pedal1, pedal1->GetWorldCenter());
	m_world->CreateJoint(&jointDef5);

//////////////////////////////////////////////////////////////////////////////
	///pedal2: Creating the second pedal
	pedalDef.position.Set(-6.0f, 12.0f);
	b2Body* pedal2 = m_world->CreateBody(&pedalDef);
	pedal2->CreateFixture(&pedalfd);

	///Creating a revolute joint between pedal2 and pedal rod
	b2RevoluteJointDef jointDef6;
	jointDef6.Initialize(pedalbody, pedal2, pedal2->GetWorldCenter());
	m_world->CreateJoint(&jointDef6);
//////////////////////////////////////////////////////////////////////////////
	///welding behind gear to behind tire
	b2WeldJointDef jointDef7;
	jointDef7.Initialize(gearbody1, wheel1, gearbody1->GetWorldCenter());
	m_world->CreateJoint(&jointDef7);
}
  sim_t *sim = new sim_t("Dominos", dominos_t::create);
}
<|endoftext|>


<commit_before>/** @file
    @brief Implementation

    @date 2015, 2016

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2015, 2016 Sensics, 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.

// Internal Includes
#include "PoseEstimator_RANSAC.h"
#include "LED.h"
#include "CameraParameters.h"
#include "cvToEigen.h"

// Library/third-party includes
#include <opencv2/core/core.hpp>
#include <opencv2/calib3d/calib3d.hpp>

// Standard includes
#include <algorithm>

namespace osvr {
namespace vbtracker {
    bool RANSACPoseEstimator::operator()(CameraParameters const &camParams,
                                         LedPtrList const &leds,
                                         BeaconStateVec const &beacons,
                                         std::vector<BeaconData> &beaconDebug,
                                         Eigen::Vector3d &outXlate,
                                         Eigen::Quaterniond &outQuat) {

        // We need to get a pair of matched vectors of points: 2D locations
        // with in the image and 3D locations in model space.  There needs to
        // be a correspondence between the points in these vectors, such that
        // the ith element in one matches the ith element in the other.  We
        // make these by looking up the locations of LEDs with known identifiers
        // and pushing both onto the vectors at the same time.

        std::vector<cv::Point3f> objectPoints;
        std::vector<cv::Point2f> imagePoints;
        std::vector<ZeroBasedBeaconId> beaconIds;
        for (auto const &led : leds) {
            auto id = makeZeroBased(led->getID());
            auto index = asIndex(id);
            beaconDebug[index].variance = -1;
            beaconDebug[index].measurement = led->getLocationForTracking();
            beaconIds.push_back(id);

            /// Effectively invert the image points here so we get the output of
            /// a coordinate system we want.
            imagePoints.push_back(led->getLocationForTracking());
            objectPoints.push_back(
                vec3dToCVPoint3f(beacons[index]->stateVector()));
        }

        // Make sure we have enough points to do our estimation.
        if (objectPoints.size() < m_permittedOutliers + m_requiredInliers) {
            return false;
        }

        // Produce an estimate of the translation and rotation needed to take
        // points from model space into camera space.  We allow for at most
        // m_permittedOutliers outliers. Even in simulation data, we sometimes
        // find duplicate IDs for LEDs, indicating that we are getting
        // mis-identified ones sometimes.
        // We tried using the previous guess to reduce the amount of computation
        // being done, but this got us stuck in infinite locations.  We seem to
        // do okay without using it, so leaving it out.
        // @todo Make number of iterations into a parameter.
        bool usePreviousGuess = false;
        int iterationsCount = 5;
        float maxReprojectionError = 6.f;
        cv::Mat inlierIndices;

        cv::Mat rvec;
        cv::Mat tvec;
#if CV_MAJOR_VERSION == 2
        cv::solvePnPRansac(
            objectPoints, imagePoints, camParams.cameraMatrix,
            camParams.distortionParameters, rvec, tvec, usePreviousGuess,
            iterationsCount, maxReprojectionError,
            static_cast<int>(objectPoints.size() - m_permittedOutliers),
            inlierIndices);
#elif CV_MAJOR_VERSION == 3
        // parameter added to the OpenCV 3.0 interface in place of the number of
        // inliers
        /// @todo how to determine this requested confidence from the data we're
        /// given?
        double confidence = 0.99;
        auto ransacResult = cv::solvePnPRansac(
            objectPoints, imagePoints, camParams.cameraMatrix,
            camParams.distortionParameters, rvec, tvec, usePreviousGuess,
            iterationsCount, maxReprojectionError, confidence, inlierIndices);
        if (!ransacResult) {
            return false;
        }
#else
#error "Unrecognized OpenCV version!"
#endif

        //==========================================================================
        // Make sure we got all the inliers we needed.  Otherwise, reject this
        // pose.
        if (inlierIndices.rows < static_cast<int>(m_requiredInliers)) {
            return false;
        }

        //==========================================================================
        // Reproject the inliers into the image and make sure they are actually
        // close to the expected location; otherwise, we have a bad pose.
        const double pixelReprojectionErrorForSingleAxisMax = 4;
        if (inlierIndices.rows > 0) {
            std::vector<cv::Point3f> inlierObjectPoints;
            std::vector<cv::Point2f> inlierImagePoints;
            std::vector<ZeroBasedBeaconId> inlierBeaconIds;
            for (int i = 0; i < inlierIndices.rows; i++) {
                inlierObjectPoints.push_back(objectPoints[i]);
                inlierImagePoints.push_back(imagePoints[i]);
                inlierBeaconIds.push_back(beaconIds[i]);
            }
            std::vector<cv::Point2f> reprojectedPoints;
            cv::projectPoints(
                inlierObjectPoints, rvec, tvec, camParams.cameraMatrix,
                camParams.distortionParameters, reprojectedPoints);

            for (size_t i = 0; i < reprojectedPoints.size(); i++) {
                if (reprojectedPoints[i].x - inlierImagePoints[i].x >
                    pixelReprojectionErrorForSingleAxisMax) {
                    return false;
                }
                if (reprojectedPoints[i].y - inlierImagePoints[i].y >
                    pixelReprojectionErrorForSingleAxisMax) {
                    return false;
                }
            }

            /// Now, we will sort that vector of inlier beacon IDs so we can
            /// rapidly binary search it to flag the LEDs we used.

            // Need a custom comparator for the ID type.
            auto idComparator = [](ZeroBasedBeaconId const &lhs,
                                   ZeroBasedBeaconId const &rhs) {
                return lhs.value() < rhs.value();
            };
            std::sort(begin(inlierBeaconIds), end(inlierBeaconIds),
                      idComparator);
            // This lambda wraps binary_search to do what it says: check to see
            // if a given beacon ID is in the list of inlier beacons.
            auto isAnInlierBeacon = [&inlierBeaconIds, &idComparator](
                ZeroBasedBeaconId const &needle) {
                return std::binary_search(begin(inlierBeaconIds),
                                          end(inlierBeaconIds), needle,
                                          idComparator);
            };
            for (auto &led : leds) {
                if (isAnInlierBeacon(led->getID())) {
                    led->markAsUsed();
                }
            }
        }

        //==========================================================================
        // Convert this into an OSVR representation of the transformation that
        // gives the pose of the HDK origin in the camera coordinate system,
        // switching units to meters and encoding the angle in a unit
        // quaternion.
        // The matrix described by rvec and tvec takes points in model space
        // (the space where the LEDs are defined, which is in mm away from an
        // implied origin) into a coordinate system where the center is at the
        // camera's origin, with X to the right, Y down, and Z in the direction
        // that the camera is facing (but still in the original units of mm):
        //  |Xc|   |r11 r12 r13 t1| |Xm|
        //  |Yc| = |r21 r22 r23 t2|*|Ym|
        //  |Zc|   |r31 r32 r33 t3| |Zm|
        //                          |1 |
        //  That is, it rotates into the camera coordinate system and then adds
        // the translation, which is in the camera coordinate system.
        //  This is the transformation we want, since it reports the sensor's
        // position and orientation in camera space, except that we want to
        // convert
        // the units into meters and the orientation into a Quaternion.
        //  NOTE: This is a right-handed coordinate system with X pointing
        // towards the right from the camera center of projection, Y pointing
        // down, and Z pointing along the camera viewing direction, if the input
        // points are not inverted.

        outXlate = cvToVector3d(tvec);
        outQuat = cvRotVecToQuat(rvec);
        return true;
    }

    /// Variance in Meters^2
    static const double InitialPositionStateError = 0.;
    /// Variance in Radians^2
    static const double InitialOrientationStateError = 0.5;
    static const double InitialVelocityStateError = 0.;
    static const double InitialAngVelStateError = 0.;
    static const double InitialStateError[] = {
        InitialPositionStateError,    InitialPositionStateError,
        InitialPositionStateError,    InitialOrientationStateError,
        InitialOrientationStateError, InitialOrientationStateError,
        InitialVelocityStateError,    InitialVelocityStateError,
        InitialVelocityStateError,    InitialAngVelStateError,
        InitialAngVelStateError,      InitialAngVelStateError};
    bool RANSACPoseEstimator::operator()(EstimatorInOutParams const &p,
                                         LedPtrList const &leds) {
        Eigen::Vector3d xlate;
        Eigen::Quaterniond quat;
        /// Call the main pose estimation to get the vector and quat.
        {
            auto ret = (*this)(p.camParams, leds, p.beacons, p.beaconDebug,
                               xlate, quat);
            if (!ret) {
                return false;
            }
        }
        /// OK, so if we're here, estimation succeeded and we have valid data in
        /// xlate and quat.
        p.state.position() = xlate;
        p.state.setQuaternion(quat);
/// Zero things we can't measure.
#if 1
        p.state.incrementalOrientation() = Eigen::Vector3d::Zero();
        p.state.velocity() = Eigen::Vector3d::Zero();
        p.state.angularVelocity() = Eigen::Vector3d::Zero();
#endif
        using StateVec = kalman::types::DimVector<BodyState>;
        using StateSquareMatrix = kalman::types::DimSquareMatrix<BodyState>;

        StateSquareMatrix covariance = StateVec(InitialStateError).asDiagonal();
        /// @todo Copy the existing angular velocity error covariance
        /*
        covariance.bottomRightCorner<3, 3>() =
            p.state.errorCovariance().bottomRightCorner<3, 3>();
            */
        p.state.setErrorCovariance(covariance);
        return true;
    }

} // namespace vbtracker
} // namespace osvr
<commit_msg>Re-organize, comment and disable the post-ransac reprojection cull<commit_after>/** @file
    @brief Implementation

    @date 2015, 2016

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2015, 2016 Sensics, 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.

// Internal Includes
#include "PoseEstimator_RANSAC.h"
#include "CameraParameters.h"
#include "LED.h"
#include "cvToEigen.h"

// Library/third-party includes
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/core/core.hpp>

// Standard includes
#include <algorithm>

/// This was enabled/primarily useful to reduce jitter when RANSAC was the only
/// tracking method, for culling a little tighter than the RANSAC PNP itself
/// did.
#undef OSVR_UVBI_TEST_RANSAC_REPROJECTION

namespace osvr {
namespace vbtracker {
    bool RANSACPoseEstimator::operator()(CameraParameters const &camParams,
                                         LedPtrList const &leds,
                                         BeaconStateVec const &beacons,
                                         std::vector<BeaconData> &beaconDebug,
                                         Eigen::Vector3d &outXlate,
                                         Eigen::Quaterniond &outQuat) {

        // We need to get a pair of matched vectors of points: 2D locations
        // with in the image and 3D locations in model space.  There needs to
        // be a correspondence between the points in these vectors, such that
        // the ith element in one matches the ith element in the other.  We
        // make these by looking up the locations of LEDs with known identifiers
        // and pushing both onto the vectors at the same time.

        std::vector<cv::Point3f> objectPoints;
        std::vector<cv::Point2f> imagePoints;
        std::vector<ZeroBasedBeaconId> beaconIds;
        for (auto const &led : leds) {
            auto id = makeZeroBased(led->getID());
            auto index = asIndex(id);
            beaconDebug[index].variance = -1;
            beaconDebug[index].measurement = led->getLocationForTracking();
            beaconIds.push_back(id);

            /// Effectively invert the image points here so we get the output of
            /// a coordinate system we want.
            imagePoints.push_back(led->getLocationForTracking());
            objectPoints.push_back(
                vec3dToCVPoint3f(beacons[index]->stateVector()));
        }

        // Make sure we have enough points to do our estimation.
        if (objectPoints.size() < m_permittedOutliers + m_requiredInliers) {
            return false;
        }

        // Produce an estimate of the translation and rotation needed to take
        // points from model space into camera space.  We allow for at most
        // m_permittedOutliers outliers. Even in simulation data, we sometimes
        // find duplicate IDs for LEDs, indicating that we are getting
        // mis-identified ones sometimes.
        // We tried using the previous guess to reduce the amount of computation
        // being done, but this got us stuck in infinite locations.  We seem to
        // do okay without using it, so leaving it out.
        // @todo Make number of iterations into a parameter.
        bool usePreviousGuess = false;
        int iterationsCount = 5;
        float maxReprojectionError = 6.f;
        cv::Mat inlierIndices;

        cv::Mat rvec;
        cv::Mat tvec;
#if CV_MAJOR_VERSION == 2
        cv::solvePnPRansac(
            objectPoints, imagePoints, camParams.cameraMatrix,
            camParams.distortionParameters, rvec, tvec, usePreviousGuess,
            iterationsCount, maxReprojectionError,
            static_cast<int>(objectPoints.size() - m_permittedOutliers),
            inlierIndices);
#elif CV_MAJOR_VERSION == 3
        // parameter added to the OpenCV 3.0 interface in place of the number of
        // inliers
        /// @todo how to determine this requested confidence from the data we're
        /// given?
        double confidence = 0.99;
        auto ransacResult = cv::solvePnPRansac(
            objectPoints, imagePoints, camParams.cameraMatrix,
            camParams.distortionParameters, rvec, tvec, usePreviousGuess,
            iterationsCount, maxReprojectionError, confidence, inlierIndices);
        if (!ransacResult) {
            return false;
        }
#else
#error "Unrecognized OpenCV version!"
#endif

        //==========================================================================
        // Make sure we got all the inliers we needed.  Otherwise, reject this
        // pose.
        if (inlierIndices.rows < static_cast<int>(m_requiredInliers)) {
            return false;
        }

        if (inlierIndices.rows > 0) {

#ifdef OSVR_UVBI_TEST_RANSAC_REPROJECTION
            //==========================================================================
            // Reproject the inliers into the image and make sure they are
            // actually
            // close to the expected location; otherwise, we have a bad pose.
            const double pixelReprojectionErrorForSingleAxisMax = 4;
            std::vector<cv::Point3f> inlierObjectPoints;
            std::vector<cv::Point2f> inlierImagePoints;
            for (int i = 0; i < inlierIndices.rows; i++) {
                inlierObjectPoints.push_back(objectPoints[i]);
                inlierImagePoints.push_back(imagePoints[i]);
                inlierBeaconIds.push_back(beaconIds[i]);
            }
            std::vector<cv::Point2f> reprojectedPoints;
            cv::projectPoints(
                inlierObjectPoints, rvec, tvec, camParams.cameraMatrix,
                camParams.distortionParameters, reprojectedPoints);

            for (size_t i = 0; i < reprojectedPoints.size(); i++) {
                if (reprojectedPoints[i].x - inlierImagePoints[i].x >
                    pixelReprojectionErrorForSingleAxisMax) {
                    std::cout << "Reject on reprojected beacon id "
                              << makeOneBased(inlierBeaconIds[i]).value()
                              << " x axis." << std::endl;
                    return false;
                }
                if (reprojectedPoints[i].y - inlierImagePoints[i].y >
                    pixelReprojectionErrorForSingleAxisMax) {
                    std::cout << "Reject on reprojected beacon id "
                              << makeOneBased(inlierBeaconIds[i]).value()
                              << " y axis." << std::endl;
                    return false;
                }
            }
#endif

            /// Make a vector of the inlier beacon IDs.
            std::vector<ZeroBasedBeaconId> inlierBeaconIds;
            for (int i = 0; i < inlierIndices.rows; i++) {
                inlierBeaconIds.push_back(beaconIds[i]);
            }

            /// Now, we will sort that vector of inlier beacon IDs so we can
            /// rapidly binary search it to flag the LEDs we used.

            // Need a custom comparator for the ID type.
            auto idComparator = [](ZeroBasedBeaconId const &lhs,
                                   ZeroBasedBeaconId const &rhs) {
                return lhs.value() < rhs.value();
            };
            std::sort(begin(inlierBeaconIds), end(inlierBeaconIds),
                      idComparator);
            // This lambda wraps binary_search to do what it says: check to see
            // if a given beacon ID is in the list of inlier beacons.
            auto isAnInlierBeacon = [&inlierBeaconIds, &idComparator](
                ZeroBasedBeaconId const &needle) {
                return std::binary_search(begin(inlierBeaconIds),
                                          end(inlierBeaconIds), needle,
                                          idComparator);
            };
            for (auto &led : leds) {
                if (isAnInlierBeacon(led->getID())) {
                    led->markAsUsed();
                }
            }
        }

        //==========================================================================
        // Convert this into an OSVR representation of the transformation that
        // gives the pose of the HDK origin in the camera coordinate system,
        // switching units to meters and encoding the angle in a unit
        // quaternion.
        // The matrix described by rvec and tvec takes points in model space
        // (the space where the LEDs are defined, which is in mm away from an
        // implied origin) into a coordinate system where the center is at the
        // camera's origin, with X to the right, Y down, and Z in the direction
        // that the camera is facing (but still in the original units of mm):
        //  |Xc|   |r11 r12 r13 t1| |Xm|
        //  |Yc| = |r21 r22 r23 t2|*|Ym|
        //  |Zc|   |r31 r32 r33 t3| |Zm|
        //                          |1 |
        //  That is, it rotates into the camera coordinate system and then adds
        // the translation, which is in the camera coordinate system.
        //  This is the transformation we want, since it reports the sensor's
        // position and orientation in camera space, except that we want to
        // convert
        // the units into meters and the orientation into a Quaternion.
        //  NOTE: This is a right-handed coordinate system with X pointing
        // towards the right from the camera center of projection, Y pointing
        // down, and Z pointing along the camera viewing direction, if the input
        // points are not inverted.

        outXlate = cvToVector3d(tvec);
        outQuat = cvRotVecToQuat(rvec);
        return true;
    }

    /// Variance in Meters^2
    static const double InitialPositionStateError = 0.;
    /// Variance in Radians^2
    static const double InitialOrientationStateError = 0.5;
    static const double InitialVelocityStateError = 0.;
    static const double InitialAngVelStateError = 0.;
    static const double InitialStateError[] = {
        InitialPositionStateError,    InitialPositionStateError,
        InitialPositionStateError,    InitialOrientationStateError,
        InitialOrientationStateError, InitialOrientationStateError,
        InitialVelocityStateError,    InitialVelocityStateError,
        InitialVelocityStateError,    InitialAngVelStateError,
        InitialAngVelStateError,      InitialAngVelStateError};
    bool RANSACPoseEstimator::operator()(EstimatorInOutParams const &p,
                                         LedPtrList const &leds) {
        Eigen::Vector3d xlate;
        Eigen::Quaterniond quat;
        /// Call the main pose estimation to get the vector and quat.
        {
            auto ret = (*this)(p.camParams, leds, p.beacons, p.beaconDebug,
                               xlate, quat);
            if (!ret) {
                return false;
            }
        }
        /// OK, so if we're here, estimation succeeded and we have valid data in
        /// xlate and quat.
        p.state.position() = xlate;
        p.state.setQuaternion(quat);
/// Zero things we can't measure.
#if 1
        p.state.incrementalOrientation() = Eigen::Vector3d::Zero();
        p.state.velocity() = Eigen::Vector3d::Zero();
        p.state.angularVelocity() = Eigen::Vector3d::Zero();
#endif
        using StateVec = kalman::types::DimVector<BodyState>;
        using StateSquareMatrix = kalman::types::DimSquareMatrix<BodyState>;

        StateSquareMatrix covariance = StateVec(InitialStateError).asDiagonal();
        /// @todo Copy the existing angular velocity error covariance
        /*
        covariance.bottomRightCorner<3, 3>() =
            p.state.errorCovariance().bottomRightCorner<3, 3>();
            */
        p.state.setErrorCovariance(covariance);
        return true;
    }

} // namespace vbtracker
} // namespace osvr
<|endoftext|>


<commit_before>// Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
#ifndef __RAPICORN_CPUASM_HH__
#define __RAPICORN_CPUASM_HH__

#include <rcore/cxxaux.hh>

// == RDTSC ==
#if defined __i386__ || defined __x86_64__
#define RAPICORN_HAVE_X86_RDTSC  1
#define RAPICORN_X86_RDTSC()     ({ Rapicorn::uint32 __l_, __h_, __s_; \
                                    __asm__ __volatile__ ("rdtsc" : "=a" (__l_), "=d" (__h_));  \
                                    __s_ = __l_ + (Rapicorn::uint64 (__h_) << 32); __s_; })
#else
#define RAPICORN_HAVE_X86_RDTSC  0
#define RAPICORN_X86_RDTSC()    (0)
#endif

#endif // __RAPICORN_CPUASM_HH__
<commit_msg>RCORE: add missing __amd64__ to rdtsc macro<commit_after>// Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
#ifndef __RAPICORN_CPUASM_HH__
#define __RAPICORN_CPUASM_HH__

#include <rcore/cxxaux.hh>

// == RDTSC ==
#if defined __i386__ || defined __x86_64__ || defined __amd64__
#define RAPICORN_HAVE_X86_RDTSC  1
#define RAPICORN_X86_RDTSC()     ({ Rapicorn::uint32 __l_, __h_, __s_; \
                                    __asm__ __volatile__ ("rdtsc" : "=a" (__l_), "=d" (__h_));  \
                                    __s_ = __l_ + (Rapicorn::uint64 (__h_) << 32); __s_; })
#else
#define RAPICORN_HAVE_X86_RDTSC  0
#define RAPICORN_X86_RDTSC()    (0)
#endif

#endif // __RAPICORN_CPUASM_HH__
<|endoftext|>


<commit_before>///
/// @file  pi_lmo_parallel3.cpp
/// @brief Parallel implementation of the Lagarias-Miller-Odlyzko
///        prime counting algorithm using OpenMP. This implementation
///        uses improved load balancing and counts the number of
///        unsieved elements using POPCNT without using any special
///        counting tree data structure.
///
/// Copyright (C) 2015 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <aligned_vector.hpp>
#include <BitSieve.hpp>
#include <generate.hpp>
#include <min_max.hpp>
#include <pmath.hpp>
#include <PhiTiny.hpp>
#include <S1.hpp>
#include <S2LoadBalancer.hpp>
#include <S2Status.hpp>
#include <Wheel.hpp>

#include <stdint.h>
#include <vector>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// Cross-off the multiples of prime in the sieve array.
/// @return  Count of crossed-off multiples.
///
int64_t cross_off(BitSieve& sieve,
                  int64_t low,
                  int64_t high,
                  int64_t prime,
                  WheelItem& w)
{
  int64_t unset = 0;
  int64_t m = w.next_multiple;
  int64_t wheel_index = w.wheel_index;

  for (; m < high; m += prime * Wheel::next_multiple_factor(&wheel_index))
  {
    // +1 if m is unset the first time
    unset += sieve[m - low];
    sieve.unset(m - low);
  }

  w.set(m, wheel_index);
  return unset;
}

/// Compute the S2 contribution for the interval
/// [low_process, low_process + segments * segment_size[.
/// The missing special leaf contributions for the interval
/// [1, low_process[ are later reconstructed and added in
/// the calling (parent) S2 function.
///
int64_t S2_thread(int64_t x,
                  int64_t y,
                  int64_t c,
                  int64_t segment_size,
                  int64_t segments_per_thread,
                  int64_t thread_num,
                  int64_t low,
                  int64_t limit,
                  vector<int32_t>& pi,
                  vector<int32_t>& primes,
                  vector<int32_t>& lpf,
                  vector<int32_t>& mu,
                  vector<int64_t>& mu_sum,
                  vector<int64_t>& phi)
{
  low += segment_size * segments_per_thread * thread_num;
  limit = min(low + segment_size * segments_per_thread, limit);
  int64_t size = pi[min(isqrt(x / low), y)] + 1;
  int64_t pi_sqrty = pi[isqrt(y)];
  int64_t pi_y = pi[y];
  int64_t S2_thread = 0;

  if (c >= size - 1)
    return 0;

  BitSieve sieve(segment_size);
  Wheel wheel(primes, size, low);
  phi.resize(size, 0);
  mu_sum.resize(size, 0);

  // Process the segments assigned to the current thread
  for (; low < limit; low += segment_size)
  {
    // Current segment = interval [low, high[
    int64_t high = min(low + segment_size, limit);
    int64_t b = c + 1;

    // pre-sieve the multiples of the first c primes
    sieve.pre_sieve(c, low);

    int64_t count_low_high = sieve.count((high - 1) - low);

    // For c + 1 <= b < pi_sqrty
    // Find all special leaves: n = primes[b] * m
    // which satisfy:  mu[m] != 0 && primes[b] < lpf[m], low <= (x / n) < high
    for (; b < min(pi_sqrty, size); b++)
    {
      int64_t prime = primes[b];
      int64_t min_m = max(x / (prime * high), y / prime);
      int64_t max_m = min(x / (prime * low), y);
      int64_t count = 0;
      int64_t i = 0;

      if (prime >= max_m)
        goto next_segment;

      for (int64_t m = max_m; m > min_m; m--)
      {
        if (mu[m] != 0 && prime < lpf[m])
        {
          int64_t xn = x / (prime * m);
          int64_t stop = xn - low;
          count += sieve.count(i, stop);
          i = stop + 1;
          int64_t phi_xn = phi[b] + count;
          S2_thread -= mu[m] * phi_xn;
          mu_sum[b] -= mu[m];
        }
      }

      phi[b] += count_low_high;
      count_low_high -= cross_off(sieve, low, high, prime, wheel[b]);
    }

    // For pi_sqrty <= b < pi_y
    // Find all special leaves: n = primes[b] * prime2
    // which satisfy: low <= (x / n) < high
    for (; b < min(pi_y, size); b++)
    {
      int64_t prime = primes[b];
      int64_t l = pi[min(x / (prime * low), y)];
      int64_t min_m = max3(x / (prime * high), y / prime, prime);
      int64_t count = 0;
      int64_t i = 0;

      if (prime >= primes[l])
        goto next_segment;

      for (; primes[l] > min_m; l--)
      {
        int64_t xn = x / (prime * primes[l]);
        int64_t stop = xn - low;
        count += sieve.count(i, stop);
        i = stop + 1;
        int64_t phi_xn = phi[b] + count;
        S2_thread += phi_xn;
        mu_sum[b]++;
      }

      phi[b] += count_low_high;
      count_low_high -= cross_off(sieve, low, high, prime, wheel[b]);
    }

    next_segment:;
  }

  return S2_thread;
}

/// Calculate the contribution of the special leaves.
/// This is a parallel implementation with advanced load balancing.
/// As most special leaves tend to be in the first segments we
/// start off with a small segment size and few segments
/// per thread, after each iteration we dynamically increase
/// the segment size and the segments per thread.
/// @pre y > 0 && c > 1
///
int64_t S2(int64_t x,
           int64_t y,
           int64_t c,
           int64_t s2_approx,
           vector<int32_t>& primes,
           vector<int32_t>& lpf,
           vector<int32_t>& mu,
           int threads)
{
  print("");
  print("=== S2(x, y) ===");
  print("Computation of the special leaves");

  int64_t S2_total = 0;
  int64_t low = 1;
  int64_t limit = x / y + 1;
  threads = validate_threads(threads, limit);

  S2Status status(x);
  S2LoadBalancer loadBalancer(x, y, limit, threads);
  int64_t segment_size = loadBalancer.get_min_segment_size();
  int64_t segments_per_thread = 1;

  double time = get_wtime();
  vector<int32_t> pi = generate_pi(y);
  vector<int64_t> phi_total(primes.size(), 0);

  while (low < limit)
  {
    int64_t segments = ceil_div(limit - low, segment_size);
    threads = in_between(1, threads, segments);
    segments_per_thread = in_between(1, segments_per_thread, ceil_div(segments, threads));

    aligned_vector<vector<int64_t> > phi(threads);
    aligned_vector<vector<int64_t> > mu_sum(threads);
    aligned_vector<double> timings(threads);

    #pragma omp parallel for num_threads(threads) reduction(+: S2_total)
    for (int i = 0; i < threads; i++)
    {
      timings[i] = get_wtime();
      S2_total += S2_thread(x, y, c, segment_size, segments_per_thread,
          i, low, limit, pi, primes, lpf, mu, mu_sum[i], phi[i]);
      timings[i] = get_wtime() - timings[i];
    }

    // Once all threads have finished reconstruct and add the
    // missing contribution of all special leaves. This must
    // be done in order as each thread (i) requires the sum of
    // the phi values from the previous threads.
    //
    for (int i = 0; i < threads; i++)
    {
      for (size_t j = 1; j < phi[i].size(); j++)
      {
        S2_total += phi_total[j] * mu_sum[i][j];
        phi_total[j] += phi[i][j];
      }
    }

    low += segments_per_thread * threads * segment_size;
    loadBalancer.update(low, threads, &segment_size, &segments_per_thread, timings);

    if (print_status())
      status.print(S2_total, s2_approx, loadBalancer.get_rsd());
  }

  print("S2", S2_total, time);
  return S2_total;
}

} // namespace

namespace primecount {

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm.
/// Run time: O(x^(2/3) / log x) operations, O(x^(1/3) * (log x)^2) space.
///
int64_t pi_lmo_parallel3(int64_t x, int threads)
{
  if (x < 2)
    return 0;

  double alpha = get_alpha_lmo(x);
  int64_t x13 = iroot<3>(x);
  int64_t y = (int64_t) (x13 * alpha);
  int64_t z = x / y;
  int64_t c = PhiTiny::get_c(y);

  print("");
  print("=== pi_lmo_parallel3(x) ===");
  print("pi(x) = S1 + S2 + pi(y) - 1 - P2");
  print(x, y, z, c, alpha, threads);

  int64_t p2 = P2(x, y, threads);
  vector<int32_t> mu = generate_moebius(y);
  vector<int32_t> lpf = generate_least_prime_factors(y);
  vector<int32_t> primes = generate_primes(y);

  int64_t pi_y = primes.size() - 1;
  int64_t s1 = S1(x, y, c, threads);
  int64_t s2_approx = S2_approx(x, pi_y, p2, s1);
  int64_t s2 = S2(x, y, c, s2_approx, primes, lpf, mu, threads);
  int64_t phi = s1 + s2;
  int64_t sum = phi + pi_y - 1 - p2;

  return sum;
}

} // namespace primecount
<commit_msg>Use all CPU cores<commit_after>///
/// @file  pi_lmo_parallel3.cpp
/// @brief Parallel implementation of the Lagarias-Miller-Odlyzko
///        prime counting algorithm using OpenMP. This implementation
///        uses improved load balancing and counts the number of
///        unsieved elements using POPCNT without using any special
///        counting tree data structure.
///
/// Copyright (C) 2015 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <aligned_vector.hpp>
#include <BitSieve.hpp>
#include <generate.hpp>
#include <min_max.hpp>
#include <pmath.hpp>
#include <PhiTiny.hpp>
#include <S1.hpp>
#include <S2LoadBalancer.hpp>
#include <S2Status.hpp>
#include <Wheel.hpp>

#include <stdint.h>
#include <vector>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// Cross-off the multiples of prime in the sieve array.
/// @return  Count of crossed-off multiples.
///
int64_t cross_off(BitSieve& sieve,
                  int64_t low,
                  int64_t high,
                  int64_t prime,
                  WheelItem& w)
{
  int64_t unset = 0;
  int64_t m = w.next_multiple;
  int64_t wheel_index = w.wheel_index;

  for (; m < high; m += prime * Wheel::next_multiple_factor(&wheel_index))
  {
    // +1 if m is unset the first time
    unset += sieve[m - low];
    sieve.unset(m - low);
  }

  w.set(m, wheel_index);
  return unset;
}

/// Compute the S2 contribution for the interval
/// [low_process, low_process + segments * segment_size[.
/// The missing special leaf contributions for the interval
/// [1, low_process[ are later reconstructed and added in
/// the calling (parent) S2 function.
///
int64_t S2_thread(int64_t x,
                  int64_t y,
                  int64_t c,
                  int64_t segment_size,
                  int64_t segments_per_thread,
                  int64_t thread_num,
                  int64_t low,
                  int64_t limit,
                  vector<int32_t>& pi,
                  vector<int32_t>& primes,
                  vector<int32_t>& lpf,
                  vector<int32_t>& mu,
                  vector<int64_t>& mu_sum,
                  vector<int64_t>& phi)
{
  low += segment_size * segments_per_thread * thread_num;
  limit = min(low + segment_size * segments_per_thread, limit);
  int64_t size = pi[min(isqrt(x / low), y)] + 1;
  int64_t pi_sqrty = pi[isqrt(y)];
  int64_t pi_y = pi[y];
  int64_t S2_thread = 0;

  if (c >= size - 1)
    return 0;

  BitSieve sieve(segment_size);
  Wheel wheel(primes, size, low);
  phi.resize(size, 0);
  mu_sum.resize(size, 0);

  // Process the segments assigned to the current thread
  for (; low < limit; low += segment_size)
  {
    // Current segment = interval [low, high[
    int64_t high = min(low + segment_size, limit);
    int64_t b = c + 1;

    // pre-sieve the multiples of the first c primes
    sieve.pre_sieve(c, low);

    int64_t count_low_high = sieve.count((high - 1) - low);

    // For c + 1 <= b < pi_sqrty
    // Find all special leaves: n = primes[b] * m
    // which satisfy:  mu[m] != 0 && primes[b] < lpf[m], low <= (x / n) < high
    for (; b < min(pi_sqrty, size); b++)
    {
      int64_t prime = primes[b];
      int64_t min_m = max(x / (prime * high), y / prime);
      int64_t max_m = min(x / (prime * low), y);
      int64_t count = 0;
      int64_t i = 0;

      if (prime >= max_m)
        goto next_segment;

      for (int64_t m = max_m; m > min_m; m--)
      {
        if (mu[m] != 0 && prime < lpf[m])
        {
          int64_t xn = x / (prime * m);
          int64_t stop = xn - low;
          count += sieve.count(i, stop);
          i = stop + 1;
          int64_t phi_xn = phi[b] + count;
          S2_thread -= mu[m] * phi_xn;
          mu_sum[b] -= mu[m];
        }
      }

      phi[b] += count_low_high;
      count_low_high -= cross_off(sieve, low, high, prime, wheel[b]);
    }

    // For pi_sqrty <= b < pi_y
    // Find all special leaves: n = primes[b] * prime2
    // which satisfy: low <= (x / n) < high
    for (; b < min(pi_y, size); b++)
    {
      int64_t prime = primes[b];
      int64_t l = pi[min(x / (prime * low), y)];
      int64_t min_m = max3(x / (prime * high), y / prime, prime);
      int64_t count = 0;
      int64_t i = 0;

      if (prime >= primes[l])
        goto next_segment;

      for (; primes[l] > min_m; l--)
      {
        int64_t xn = x / (prime * primes[l]);
        int64_t stop = xn - low;
        count += sieve.count(i, stop);
        i = stop + 1;
        int64_t phi_xn = phi[b] + count;
        S2_thread += phi_xn;
        mu_sum[b]++;
      }

      phi[b] += count_low_high;
      count_low_high -= cross_off(sieve, low, high, prime, wheel[b]);
    }

    next_segment:;
  }

  return S2_thread;
}

/// Calculate the contribution of the special leaves.
/// This is a parallel implementation with advanced load balancing.
/// As most special leaves tend to be in the first segments we
/// start off with a small segment size and few segments
/// per thread, after each iteration we dynamically increase
/// the segment size and the segments per thread.
/// @pre y > 0 && c > 1
///
int64_t S2(int64_t x,
           int64_t y,
           int64_t c,
           int64_t s2_approx,
           vector<int32_t>& primes,
           vector<int32_t>& lpf,
           vector<int32_t>& mu,
           int threads)
{
  print("");
  print("=== S2(x, y) ===");
  print("Computation of the special leaves");

  int64_t S2_total = 0;
  int64_t low = 1;
  int64_t limit = x / y + 1;
  threads = validate_threads(threads, limit);

  S2Status status(x);
  S2LoadBalancer loadBalancer(x, y, limit, threads);
  int64_t min_segment_size = loadBalancer.get_min_segment_size();
  int64_t segment_size = min_segment_size;
  int64_t segments_per_thread = 1;

  double time = get_wtime();
  vector<int32_t> pi = generate_pi(y);
  vector<int64_t> phi_total(primes.size(), 0);

  while (low < limit)
  {
    // make sure we use all CPU cores
    segment_size = min(segment_size, (limit - low) / threads);
    segment_size = max(segment_size, min_segment_size);
    segment_size = prev_power_of_2(segment_size);

    int64_t segments = ceil_div(limit - low, segment_size);
    threads = in_between(1, threads, segments);
    segments_per_thread = in_between(1, segments_per_thread, ceil_div(segments, threads));

    aligned_vector<vector<int64_t> > phi(threads);
    aligned_vector<vector<int64_t> > mu_sum(threads);
    aligned_vector<double> timings(threads);

    #pragma omp parallel for num_threads(threads) reduction(+: S2_total)
    for (int i = 0; i < threads; i++)
    {
      timings[i] = get_wtime();
      S2_total += S2_thread(x, y, c, segment_size, segments_per_thread,
          i, low, limit, pi, primes, lpf, mu, mu_sum[i], phi[i]);
      timings[i] = get_wtime() - timings[i];
    }

    // Once all threads have finished reconstruct and add the
    // missing contribution of all special leaves. This must
    // be done in order as each thread (i) requires the sum of
    // the phi values from the previous threads.
    //
    for (int i = 0; i < threads; i++)
    {
      for (size_t j = 1; j < phi[i].size(); j++)
      {
        S2_total += phi_total[j] * mu_sum[i][j];
        phi_total[j] += phi[i][j];
      }
    }

    low += segments_per_thread * threads * segment_size;
    loadBalancer.update(low, threads, &segment_size, &segments_per_thread, timings);

    if (print_status())
      status.print(S2_total, s2_approx, loadBalancer.get_rsd());
  }

  print("S2", S2_total, time);
  return S2_total;
}

} // namespace

namespace primecount {

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm.
/// Run time: O(x^(2/3) / log x) operations, O(x^(1/3) * (log x)^2) space.
///
int64_t pi_lmo_parallel3(int64_t x, int threads)
{
  if (x < 2)
    return 0;

  double alpha = get_alpha_lmo(x);
  int64_t x13 = iroot<3>(x);
  int64_t y = (int64_t) (x13 * alpha);
  int64_t z = x / y;
  int64_t c = PhiTiny::get_c(y);

  print("");
  print("=== pi_lmo_parallel3(x) ===");
  print("pi(x) = S1 + S2 + pi(y) - 1 - P2");
  print(x, y, z, c, alpha, threads);

  int64_t p2 = P2(x, y, threads);
  vector<int32_t> mu = generate_moebius(y);
  vector<int32_t> lpf = generate_least_prime_factors(y);
  vector<int32_t> primes = generate_primes(y);

  int64_t pi_y = primes.size() - 1;
  int64_t s1 = S1(x, y, c, threads);
  int64_t s2_approx = S2_approx(x, pi_y, p2, s1);
  int64_t s2 = S2(x, y, c, s2_approx, primes, lpf, mu, threads);
  int64_t phi = s1 + s2;
  int64_t sum = phi + pi_y - 1 - p2;

  return sum;
}

} // namespace primecount
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006 Eric Seidel <eric@webkit.org>
 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "core/svg/graphics/SVGImage.h"

#include "core/animation/DocumentTimeline.h"
#include "core/dom/NodeTraversal.h"
#include "core/dom/shadow/ComposedTreeWalker.h"
#include "core/frame/FrameView.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h"
#include "core/loader/FrameLoadRequest.h"
#include "core/page/Chrome.h"
#include "core/rendering/style/RenderStyle.h"
#include "core/rendering/svg/RenderSVGRoot.h"
#include "core/svg/SVGDocument.h"
#include "core/svg/SVGFEImageElement.h"
#include "core/svg/SVGImageElement.h"
#include "core/svg/SVGSVGElement.h"
#include "core/svg/animation/SMILTimeContainer.h"
#include "core/svg/graphics/SVGImageChromeClient.h"
#include "platform/LengthFunctions.h"
#include "platform/geometry/IntRect.h"
#include "platform/graphics/GraphicsContextStateSaver.h"
#include "platform/graphics/ImageBuffer.h"
#include "platform/graphics/ImageObserver.h"
#include "wtf/PassRefPtr.h"

namespace WebCore {

SVGImage::SVGImage(ImageObserver* observer)
    : Image(observer)
{
}

SVGImage::~SVGImage()
{
    if (m_page) {
        // Store m_page in a local variable, clearing m_page, so that SVGImageChromeClient knows we're destructed.
        OwnPtr<Page> currentPage = m_page.release();
        currentPage->mainFrame()->loader().frameDetached(); // Break both the loader and view references to the frame
    }

    // Verify that page teardown destroyed the Chrome
    ASSERT(!m_chromeClient || !m_chromeClient->image());
}

bool SVGImage::isInSVGImage(const Element* element)
{
    ASSERT(element);

    Page* page = element->document().page();
    if (!page)
        return false;

    return page->chrome().client().isSVGImageChromeClient();
}

bool SVGImage::currentFrameHasSingleSecurityOrigin() const
{
    if (!m_page)
        return true;

    LocalFrame* frame = m_page->mainFrame();

    RELEASE_ASSERT(frame->document()->loadEventFinished());

    SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement();
    if (!rootElement)
        return true;

    // Don't allow foreignObject elements or images that are not known to be
    // single-origin since these can leak cross-origin information.
    ComposedTreeWalker walker(rootElement);
    while (Node* node = walker.get()) {
        if (isSVGForeignObjectElement(*node))
            return false;
        if (isSVGImageElement(*node)) {
            if (!toSVGImageElement(*node).currentFrameHasSingleSecurityOrigin())
                return false;
        } else if (isSVGFEImageElement(*node)) {
            if (!toSVGFEImageElement(*node).currentFrameHasSingleSecurityOrigin())
                return false;
        }
        walker.next();
    }

    // Because SVG image rendering disallows external resources and links, these
    // images effectively are restricted to a single security origin.
    return true;
}

void SVGImage::setContainerSize(const IntSize& size)
{
    if (!m_page || !usesContainerSize())
        return;

    LocalFrame* frame = m_page->mainFrame();
    SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement();
    if (!rootElement)
        return;

    FrameView* view = frameView();
    view->resize(this->containerSize());

    RenderSVGRoot* renderer = toRenderSVGRoot(rootElement->renderer());
    if (!renderer)
        return;
    renderer->setContainerSize(size);
}

IntSize SVGImage::containerSize() const
{
    if (!m_page)
        return IntSize();
    LocalFrame* frame = m_page->mainFrame();
    SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement();
    if (!rootElement)
        return IntSize();

    RenderSVGRoot* renderer = toRenderSVGRoot(rootElement->renderer());
    if (!renderer)
        return IntSize();

    // If a container size is available it has precedence.
    IntSize containerSize = renderer->containerSize();
    if (!containerSize.isEmpty())
        return containerSize;

    // Assure that a container size is always given for a non-identity zoom level.
    ASSERT(renderer->style()->effectiveZoom() == 1);

    FloatSize currentSize;
    if (rootElement->intrinsicWidth().isFixed() && rootElement->intrinsicHeight().isFixed())
        currentSize = rootElement->currentViewportSize();
    else
        currentSize = rootElement->currentViewBoxRect().size();

    if (!currentSize.isEmpty())
        return IntSize(static_cast<int>(ceilf(currentSize.width())), static_cast<int>(ceilf(currentSize.height())));

    // As last resort, use CSS default intrinsic size.
    return IntSize(300, 150);
}

void SVGImage::drawForContainer(GraphicsContext* context, const FloatSize containerSize, float zoom, const FloatRect& dstRect,
    const FloatRect& srcRect, CompositeOperator compositeOp, blink::WebBlendMode blendMode)
{
    if (!m_page)
        return;

    // Temporarily disable the image observer to prevent changeInRect() calls due re-laying out the image.
    ImageObserverDisabler imageObserverDisabler(this);

    IntSize roundedContainerSize = roundedIntSize(containerSize);
    setContainerSize(roundedContainerSize);

    FloatRect scaledSrc = srcRect;
    scaledSrc.scale(1 / zoom);

    // Compensate for the container size rounding by adjusting the source rect.
    FloatSize adjustedSrcSize = scaledSrc.size();
    adjustedSrcSize.scale(roundedContainerSize.width() / containerSize.width(), roundedContainerSize.height() / containerSize.height());
    scaledSrc.setSize(adjustedSrcSize);

    draw(context, dstRect, scaledSrc, compositeOp, blendMode);
}

PassRefPtr<NativeImageSkia> SVGImage::nativeImageForCurrentFrame()
{
    if (!m_page)
        return nullptr;

    OwnPtr<ImageBuffer> buffer = ImageBuffer::create(size());
    if (!buffer)
        return nullptr;

    drawForContainer(buffer->context(), size(), 1, rect(), rect(), CompositeSourceOver, blink::WebBlendModeNormal);

    // FIXME: WK(Bug 113657): We should use DontCopyBackingStore here.
    return buffer->copyImage(CopyBackingStore)->nativeImageForCurrentFrame();
}

void SVGImage::drawPatternForContainer(GraphicsContext* context, const FloatSize containerSize, float zoom, const FloatRect& srcRect,
    const FloatSize& scale, const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& dstRect, blink::WebBlendMode blendMode, const IntSize& repeatSpacing)
{
    FloatRect zoomedContainerRect = FloatRect(FloatPoint(), containerSize);
    zoomedContainerRect.scale(zoom);

    // The ImageBuffer size needs to be scaled to match the final resolution.
    // FIXME: No need to get the full CTM here, we just need the scale.
    AffineTransform transform = context->getCTM();
    FloatSize imageBufferScale = FloatSize(transform.xScale(), transform.yScale());
    ASSERT(imageBufferScale.width());
    ASSERT(imageBufferScale.height());

    FloatSize scaleWithoutCTM(scale.width() / imageBufferScale.width(), scale.height() / imageBufferScale.height());

    FloatRect imageBufferSize = zoomedContainerRect;
    imageBufferSize.scale(imageBufferScale.width(), imageBufferScale.height());

    OwnPtr<ImageBuffer> buffer = ImageBuffer::create(expandedIntSize(imageBufferSize.size()));
    if (!buffer) // Failed to allocate buffer.
        return;

    drawForContainer(buffer->context(), containerSize, zoom, imageBufferSize, zoomedContainerRect, CompositeSourceOver, blink::WebBlendModeNormal);
    RefPtr<Image> image = buffer->copyImage(DontCopyBackingStore, Unscaled);

    // Adjust the source rect and transform due to the image buffer's scaling.
    FloatRect scaledSrcRect = srcRect;
    scaledSrcRect.scale(imageBufferScale.width(), imageBufferScale.height());

    image->drawPattern(context, scaledSrcRect, scaleWithoutCTM, phase, compositeOp, dstRect, blendMode, repeatSpacing);
}

void SVGImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, blink::WebBlendMode blendMode)
{
    if (!m_page)
        return;

    GraphicsContextStateSaver stateSaver(*context);
    context->setCompositeOperation(compositeOp, blendMode);
    context->clip(enclosingIntRect(dstRect));

    bool compositingRequiresTransparencyLayer = compositeOp != CompositeSourceOver || blendMode != blink::WebBlendModeNormal;
    float opacity = context->getNormalizedAlpha() / 255.f;
    bool requiresTransparencyLayer = compositingRequiresTransparencyLayer || opacity < 1;
    if (requiresTransparencyLayer) {
        context->beginTransparencyLayer(opacity);
        if (compositingRequiresTransparencyLayer)
            context->setCompositeOperation(CompositeSourceOver, blink::WebBlendModeNormal);
    }

    FloatSize scale(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height());

    // We can only draw the entire frame, clipped to the rect we want. So compute where the top left
    // of the image would be if we were drawing without clipping, and translate accordingly.
    FloatSize topLeftOffset(srcRect.location().x() * scale.width(), srcRect.location().y() * scale.height());
    FloatPoint destOffset = dstRect.location() - topLeftOffset;

    context->translate(destOffset.x(), destOffset.y());
    context->scale(scale);

    FrameView* view = frameView();
    view->resize(containerSize());

    if (view->needsLayout())
        view->layout();

    view->paint(context, enclosingIntRect(srcRect));

    if (requiresTransparencyLayer)
        context->endLayer();

    stateSaver.restore();

    if (imageObserver())
        imageObserver()->didDraw(this);

    // Start any (SMIL) animations if needed. This will restart or continue
    // animations if preceded by calls to resetAnimation or stopAnimation
    // respectively.
    startAnimation();
}

RenderBox* SVGImage::embeddedContentBox() const
{
    if (!m_page)
        return 0;
    LocalFrame* frame = m_page->mainFrame();
    SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement();
    if (!rootElement)
        return 0;
    return toRenderBox(rootElement->renderer());
}

FrameView* SVGImage::frameView() const
{
    if (!m_page)
        return 0;

    return m_page->mainFrame()->view();
}

bool SVGImage::hasRelativeWidth() const
{
    if (!m_page)
        return false;
    LocalFrame* frame = m_page->mainFrame();
    SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement();
    if (!rootElement)
        return false;
    return rootElement->intrinsicWidth().isPercent();
}

bool SVGImage::hasRelativeHeight() const
{
    if (!m_page)
        return false;
    LocalFrame* frame = m_page->mainFrame();
    SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement();
    if (!rootElement)
        return false;
    return rootElement->intrinsicHeight().isPercent();
}

void SVGImage::computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio)
{
    if (!m_page)
        return;
    LocalFrame* frame = m_page->mainFrame();
    SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement();
    if (!rootElement)
        return;

    intrinsicWidth = rootElement->intrinsicWidth();
    intrinsicHeight = rootElement->intrinsicHeight();
    if (rootElement->preserveAspectRatio()->currentValue()->align() == SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE)
        return;

    intrinsicRatio = rootElement->viewBox()->currentValue()->value().size();
    if (intrinsicRatio.isEmpty() && intrinsicWidth.isFixed() && intrinsicHeight.isFixed())
        intrinsicRatio = FloatSize(floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0));
}

// FIXME: support catchUpIfNecessary.
void SVGImage::startAnimation(bool /* catchUpIfNecessary */)
{
    if (!m_page)
        return;
    LocalFrame* frame = m_page->mainFrame();
    SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement();
    if (!rootElement || !rootElement->animationsPaused())
        return;
    rootElement->unpauseAnimations();
}

void SVGImage::stopAnimation()
{
    if (!m_page)
        return;
    LocalFrame* frame = m_page->mainFrame();
    SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement();
    if (!rootElement)
        return;
    rootElement->pauseAnimations();
}

void SVGImage::resetAnimation()
{
    if (!m_page)
        return;
    LocalFrame* frame = m_page->mainFrame();
    SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement();
    if (!rootElement)
        return;
    rootElement->pauseAnimations();
    rootElement->setCurrentTime(0);
}

bool SVGImage::hasAnimations() const
{
    if (!m_page)
        return false;
    LocalFrame* frame = m_page->mainFrame();
    SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement();
    if (!rootElement)
        return false;
    return rootElement->timeContainer()->hasAnimations() || frame->document()->timeline().hasPendingUpdates();
}

bool SVGImage::dataChanged(bool allDataReceived)
{
    TRACE_EVENT0("webkit", "SVGImage::dataChanged");

    // Don't do anything if is an empty image.
    if (!data()->size())
        return true;

    if (allDataReceived) {
        static FrameLoaderClient* dummyFrameLoaderClient = new EmptyFrameLoaderClient;

        Page::PageClients pageClients;
        fillWithEmptyClients(pageClients);
        m_chromeClient = adoptPtr(new SVGImageChromeClient(this));
        pageClients.chromeClient = m_chromeClient.get();

        // FIXME: If this SVG ends up loading itself, we might leak the world.
        // The Cache code does not know about ImageResources holding Frames and
        // won't know to break the cycle.
        // This will become an issue when SVGImage will be able to load other
        // SVGImage objects, but we're safe now, because SVGImage can only be
        // loaded by a top-level document.
        OwnPtr<Page> page = adoptPtr(new Page(pageClients));
        page->settings().setScriptEnabled(false);
        page->settings().setPluginsEnabled(false);
        page->settings().setAcceleratedCompositingEnabled(false);

        RefPtr<LocalFrame> frame = LocalFrame::create(dummyFrameLoaderClient, &page->frameHost(), 0);
        frame->setView(FrameView::create(frame.get()));
        frame->init();
        FrameLoader& loader = frame->loader();
        loader.forceSandboxFlags(SandboxAll);

        frame->view()->setScrollbarsSuppressed(true);
        frame->view()->setCanHaveScrollbars(false); // SVG Images will always synthesize a viewBox, if it's not available, and thus never see scrollbars.
        frame->view()->setTransparent(true); // SVG Images are transparent.

        m_page = page.release();

        loader.load(FrameLoadRequest(0, blankURL(), SubstituteData(data(), "image/svg+xml", "UTF-8", KURL(), ForceSynchronousLoad)));
        // Set the intrinsic size before a container size is available.
        m_intrinsicSize = containerSize();
    }

    return m_page;
}

String SVGImage::filenameExtension() const
{
    return "svg";
}

}
<commit_msg>Reduce rootElement access boilerplate in SVGImage<commit_after>/*
 * Copyright (C) 2006 Eric Seidel <eric@webkit.org>
 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "core/svg/graphics/SVGImage.h"

#include "core/animation/DocumentTimeline.h"
#include "core/dom/NodeTraversal.h"
#include "core/dom/shadow/ComposedTreeWalker.h"
#include "core/frame/FrameView.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h"
#include "core/loader/FrameLoadRequest.h"
#include "core/page/Chrome.h"
#include "core/rendering/style/RenderStyle.h"
#include "core/rendering/svg/RenderSVGRoot.h"
#include "core/svg/SVGDocument.h"
#include "core/svg/SVGFEImageElement.h"
#include "core/svg/SVGImageElement.h"
#include "core/svg/SVGSVGElement.h"
#include "core/svg/animation/SMILTimeContainer.h"
#include "core/svg/graphics/SVGImageChromeClient.h"
#include "platform/LengthFunctions.h"
#include "platform/geometry/IntRect.h"
#include "platform/graphics/GraphicsContextStateSaver.h"
#include "platform/graphics/ImageBuffer.h"
#include "platform/graphics/ImageObserver.h"
#include "wtf/PassRefPtr.h"

namespace WebCore {

SVGImage::SVGImage(ImageObserver* observer)
    : Image(observer)
{
}

SVGImage::~SVGImage()
{
    if (m_page) {
        // Store m_page in a local variable, clearing m_page, so that SVGImageChromeClient knows we're destructed.
        OwnPtr<Page> currentPage = m_page.release();
        currentPage->mainFrame()->loader().frameDetached(); // Break both the loader and view references to the frame
    }

    // Verify that page teardown destroyed the Chrome
    ASSERT(!m_chromeClient || !m_chromeClient->image());
}

bool SVGImage::isInSVGImage(const Element* element)
{
    ASSERT(element);

    Page* page = element->document().page();
    if (!page)
        return false;

    return page->chrome().client().isSVGImageChromeClient();
}

bool SVGImage::currentFrameHasSingleSecurityOrigin() const
{
    if (!m_page)
        return true;

    LocalFrame* frame = m_page->mainFrame();

    RELEASE_ASSERT(frame->document()->loadEventFinished());

    SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement();
    if (!rootElement)
        return true;

    // Don't allow foreignObject elements or images that are not known to be
    // single-origin since these can leak cross-origin information.
    ComposedTreeWalker walker(rootElement);
    while (Node* node = walker.get()) {
        if (isSVGForeignObjectElement(*node))
            return false;
        if (isSVGImageElement(*node)) {
            if (!toSVGImageElement(*node).currentFrameHasSingleSecurityOrigin())
                return false;
        } else if (isSVGFEImageElement(*node)) {
            if (!toSVGFEImageElement(*node).currentFrameHasSingleSecurityOrigin())
                return false;
        }
        walker.next();
    }

    // Because SVG image rendering disallows external resources and links, these
    // images effectively are restricted to a single security origin.
    return true;
}

static SVGSVGElement* svgRootElement(Page* page)
{
    if (!page)
        return 0;
    LocalFrame* frame = page->mainFrame();
    return toSVGDocument(frame->document())->rootElement();
}

void SVGImage::setContainerSize(const IntSize& size)
{
    if (!usesContainerSize())
        return;

    SVGSVGElement* rootElement = svgRootElement(m_page.get());
    if (!rootElement)
        return;

    FrameView* view = frameView();
    view->resize(this->containerSize());

    RenderSVGRoot* renderer = toRenderSVGRoot(rootElement->renderer());
    if (!renderer)
        return;
    renderer->setContainerSize(size);
}

IntSize SVGImage::containerSize() const
{
    SVGSVGElement* rootElement = svgRootElement(m_page.get());
    if (!rootElement)
        return IntSize();

    RenderSVGRoot* renderer = toRenderSVGRoot(rootElement->renderer());
    if (!renderer)
        return IntSize();

    // If a container size is available it has precedence.
    IntSize containerSize = renderer->containerSize();
    if (!containerSize.isEmpty())
        return containerSize;

    // Assure that a container size is always given for a non-identity zoom level.
    ASSERT(renderer->style()->effectiveZoom() == 1);

    FloatSize currentSize;
    if (rootElement->intrinsicWidth().isFixed() && rootElement->intrinsicHeight().isFixed())
        currentSize = rootElement->currentViewportSize();
    else
        currentSize = rootElement->currentViewBoxRect().size();

    if (!currentSize.isEmpty())
        return IntSize(static_cast<int>(ceilf(currentSize.width())), static_cast<int>(ceilf(currentSize.height())));

    // As last resort, use CSS default intrinsic size.
    return IntSize(300, 150);
}

void SVGImage::drawForContainer(GraphicsContext* context, const FloatSize containerSize, float zoom, const FloatRect& dstRect,
    const FloatRect& srcRect, CompositeOperator compositeOp, blink::WebBlendMode blendMode)
{
    if (!m_page)
        return;

    // Temporarily disable the image observer to prevent changeInRect() calls due re-laying out the image.
    ImageObserverDisabler imageObserverDisabler(this);

    IntSize roundedContainerSize = roundedIntSize(containerSize);
    setContainerSize(roundedContainerSize);

    FloatRect scaledSrc = srcRect;
    scaledSrc.scale(1 / zoom);

    // Compensate for the container size rounding by adjusting the source rect.
    FloatSize adjustedSrcSize = scaledSrc.size();
    adjustedSrcSize.scale(roundedContainerSize.width() / containerSize.width(), roundedContainerSize.height() / containerSize.height());
    scaledSrc.setSize(adjustedSrcSize);

    draw(context, dstRect, scaledSrc, compositeOp, blendMode);
}

PassRefPtr<NativeImageSkia> SVGImage::nativeImageForCurrentFrame()
{
    if (!m_page)
        return nullptr;

    OwnPtr<ImageBuffer> buffer = ImageBuffer::create(size());
    if (!buffer)
        return nullptr;

    drawForContainer(buffer->context(), size(), 1, rect(), rect(), CompositeSourceOver, blink::WebBlendModeNormal);

    // FIXME: WK(Bug 113657): We should use DontCopyBackingStore here.
    return buffer->copyImage(CopyBackingStore)->nativeImageForCurrentFrame();
}

void SVGImage::drawPatternForContainer(GraphicsContext* context, const FloatSize containerSize, float zoom, const FloatRect& srcRect,
    const FloatSize& scale, const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& dstRect, blink::WebBlendMode blendMode, const IntSize& repeatSpacing)
{
    FloatRect zoomedContainerRect = FloatRect(FloatPoint(), containerSize);
    zoomedContainerRect.scale(zoom);

    // The ImageBuffer size needs to be scaled to match the final resolution.
    // FIXME: No need to get the full CTM here, we just need the scale.
    AffineTransform transform = context->getCTM();
    FloatSize imageBufferScale = FloatSize(transform.xScale(), transform.yScale());
    ASSERT(imageBufferScale.width());
    ASSERT(imageBufferScale.height());

    FloatSize scaleWithoutCTM(scale.width() / imageBufferScale.width(), scale.height() / imageBufferScale.height());

    FloatRect imageBufferSize = zoomedContainerRect;
    imageBufferSize.scale(imageBufferScale.width(), imageBufferScale.height());

    OwnPtr<ImageBuffer> buffer = ImageBuffer::create(expandedIntSize(imageBufferSize.size()));
    if (!buffer) // Failed to allocate buffer.
        return;

    drawForContainer(buffer->context(), containerSize, zoom, imageBufferSize, zoomedContainerRect, CompositeSourceOver, blink::WebBlendModeNormal);
    RefPtr<Image> image = buffer->copyImage(DontCopyBackingStore, Unscaled);

    // Adjust the source rect and transform due to the image buffer's scaling.
    FloatRect scaledSrcRect = srcRect;
    scaledSrcRect.scale(imageBufferScale.width(), imageBufferScale.height());

    image->drawPattern(context, scaledSrcRect, scaleWithoutCTM, phase, compositeOp, dstRect, blendMode, repeatSpacing);
}

void SVGImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, blink::WebBlendMode blendMode)
{
    if (!m_page)
        return;

    GraphicsContextStateSaver stateSaver(*context);
    context->setCompositeOperation(compositeOp, blendMode);
    context->clip(enclosingIntRect(dstRect));

    bool compositingRequiresTransparencyLayer = compositeOp != CompositeSourceOver || blendMode != blink::WebBlendModeNormal;
    float opacity = context->getNormalizedAlpha() / 255.f;
    bool requiresTransparencyLayer = compositingRequiresTransparencyLayer || opacity < 1;
    if (requiresTransparencyLayer) {
        context->beginTransparencyLayer(opacity);
        if (compositingRequiresTransparencyLayer)
            context->setCompositeOperation(CompositeSourceOver, blink::WebBlendModeNormal);
    }

    FloatSize scale(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height());

    // We can only draw the entire frame, clipped to the rect we want. So compute where the top left
    // of the image would be if we were drawing without clipping, and translate accordingly.
    FloatSize topLeftOffset(srcRect.location().x() * scale.width(), srcRect.location().y() * scale.height());
    FloatPoint destOffset = dstRect.location() - topLeftOffset;

    context->translate(destOffset.x(), destOffset.y());
    context->scale(scale);

    FrameView* view = frameView();
    view->resize(containerSize());

    if (view->needsLayout())
        view->layout();

    view->paint(context, enclosingIntRect(srcRect));

    if (requiresTransparencyLayer)
        context->endLayer();

    stateSaver.restore();

    if (imageObserver())
        imageObserver()->didDraw(this);

    // Start any (SMIL) animations if needed. This will restart or continue
    // animations if preceded by calls to resetAnimation or stopAnimation
    // respectively.
    startAnimation();
}

RenderBox* SVGImage::embeddedContentBox() const
{
    SVGSVGElement* rootElement = svgRootElement(m_page.get());
    if (!rootElement)
        return 0;
    return toRenderBox(rootElement->renderer());
}

FrameView* SVGImage::frameView() const
{
    if (!m_page)
        return 0;

    return m_page->mainFrame()->view();
}

bool SVGImage::hasRelativeWidth() const
{
    SVGSVGElement* rootElement = svgRootElement(m_page.get());
    if (!rootElement)
        return false;
    return rootElement->intrinsicWidth().isPercent();
}

bool SVGImage::hasRelativeHeight() const
{
    SVGSVGElement* rootElement = svgRootElement(m_page.get());
    if (!rootElement)
        return false;
    return rootElement->intrinsicHeight().isPercent();
}

void SVGImage::computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio)
{
    SVGSVGElement* rootElement = svgRootElement(m_page.get());
    if (!rootElement)
        return;

    intrinsicWidth = rootElement->intrinsicWidth();
    intrinsicHeight = rootElement->intrinsicHeight();
    if (rootElement->preserveAspectRatio()->currentValue()->align() == SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE)
        return;

    intrinsicRatio = rootElement->viewBox()->currentValue()->value().size();
    if (intrinsicRatio.isEmpty() && intrinsicWidth.isFixed() && intrinsicHeight.isFixed())
        intrinsicRatio = FloatSize(floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0));
}

// FIXME: support catchUpIfNecessary.
void SVGImage::startAnimation(bool /* catchUpIfNecessary */)
{
    SVGSVGElement* rootElement = svgRootElement(m_page.get());
    if (!rootElement || !rootElement->animationsPaused())
        return;
    rootElement->unpauseAnimations();
}

void SVGImage::stopAnimation()
{
    SVGSVGElement* rootElement = svgRootElement(m_page.get());
    if (!rootElement)
        return;
    rootElement->pauseAnimations();
}

void SVGImage::resetAnimation()
{
    SVGSVGElement* rootElement = svgRootElement(m_page.get());
    if (!rootElement)
        return;
    rootElement->pauseAnimations();
    rootElement->setCurrentTime(0);
}

bool SVGImage::hasAnimations() const
{
    SVGSVGElement* rootElement = svgRootElement(m_page.get());
    if (!rootElement)
        return false;
    return rootElement->timeContainer()->hasAnimations() || m_page->mainFrame()->document()->timeline().hasPendingUpdates();
}

bool SVGImage::dataChanged(bool allDataReceived)
{
    TRACE_EVENT0("webkit", "SVGImage::dataChanged");

    // Don't do anything if is an empty image.
    if (!data()->size())
        return true;

    if (allDataReceived) {
        static FrameLoaderClient* dummyFrameLoaderClient = new EmptyFrameLoaderClient;

        Page::PageClients pageClients;
        fillWithEmptyClients(pageClients);
        m_chromeClient = adoptPtr(new SVGImageChromeClient(this));
        pageClients.chromeClient = m_chromeClient.get();

        // FIXME: If this SVG ends up loading itself, we might leak the world.
        // The Cache code does not know about ImageResources holding Frames and
        // won't know to break the cycle.
        // This will become an issue when SVGImage will be able to load other
        // SVGImage objects, but we're safe now, because SVGImage can only be
        // loaded by a top-level document.
        OwnPtr<Page> page = adoptPtr(new Page(pageClients));
        page->settings().setScriptEnabled(false);
        page->settings().setPluginsEnabled(false);
        page->settings().setAcceleratedCompositingEnabled(false);

        RefPtr<LocalFrame> frame = LocalFrame::create(dummyFrameLoaderClient, &page->frameHost(), 0);
        frame->setView(FrameView::create(frame.get()));
        frame->init();
        FrameLoader& loader = frame->loader();
        loader.forceSandboxFlags(SandboxAll);

        frame->view()->setScrollbarsSuppressed(true);
        frame->view()->setCanHaveScrollbars(false); // SVG Images will always synthesize a viewBox, if it's not available, and thus never see scrollbars.
        frame->view()->setTransparent(true); // SVG Images are transparent.

        m_page = page.release();

        loader.load(FrameLoadRequest(0, blankURL(), SubstituteData(data(), "image/svg+xml", "UTF-8", KURL(), ForceSynchronousLoad)));
        // Set the intrinsic size before a container size is available.
        m_intrinsicSize = containerSize();
    }

    return m_page;
}

String SVGImage::filenameExtension() const
{
    return "svg";
}

}
<|endoftext|>