summaryrefslogtreecommitdiffstats
path: root/cc/texture_draw_quad.cc
blob: 2f4868635a737ad2ef12d794efaba47812aa09fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cc/texture_draw_quad.h"

#include "base/logging.h"
#include "ui/gfx/vector2d_f.h"

namespace cc {

TextureDrawQuad::TextureDrawQuad()
    : resource_id(0),
      premultiplied_alpha(false),
      flipped(false) {
  this->vertex_opacity[0] = 0.f;
  this->vertex_opacity[1] = 0.f;
  this->vertex_opacity[2] = 0.f;
  this->vertex_opacity[3] = 0.f;
}

scoped_ptr<TextureDrawQuad> TextureDrawQuad::Create() {
  return make_scoped_ptr(new TextureDrawQuad);
}

void TextureDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
                             gfx::Rect rect, gfx::Rect opaque_rect,
                             unsigned resource_id, bool premultiplied_alpha,
                             gfx::PointF uv_top_left,
                             gfx::PointF uv_bottom_right,
                             const float vertex_opacity[4], bool flipped) {
  gfx::Rect visible_rect = rect;
  bool needs_blending = vertex_opacity[0] != 1.0f || vertex_opacity[1] != 1.0f
      || vertex_opacity[2] != 1.0f || vertex_opacity[3] != 1.0f;
  DrawQuad::SetAll(shared_quad_state, DrawQuad::TEXTURE_CONTENT, rect,
                   opaque_rect, visible_rect, needs_blending);
  this->resource_id = resource_id;
  this->premultiplied_alpha = premultiplied_alpha;
  this->uv_top_left = uv_top_left;
  this->uv_bottom_right = uv_bottom_right;
  this->vertex_opacity[0] = vertex_opacity[0];
  this->vertex_opacity[1] = vertex_opacity[1];
  this->vertex_opacity[2] = vertex_opacity[2];
  this->vertex_opacity[3] = vertex_opacity[3];
  this->flipped = flipped;
}

void TextureDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
                             gfx::Rect rect, gfx::Rect opaque_rect,
                             gfx::Rect visible_rect, bool needs_blending,
                             unsigned resource_id, bool premultiplied_alpha,
                             gfx::PointF uv_top_left,
                             gfx::PointF uv_bottom_right,
                             const float vertex_opacity[4], bool flipped) {
  DrawQuad::SetAll(shared_quad_state, DrawQuad::TEXTURE_CONTENT, rect,
                   opaque_rect, visible_rect, needs_blending);
  this->resource_id = resource_id;
  this->premultiplied_alpha = premultiplied_alpha;
  this->uv_top_left = uv_top_left;
  this->uv_bottom_right = uv_bottom_right;
  this->vertex_opacity[0] = vertex_opacity[0];
  this->vertex_opacity[1] = vertex_opacity[1];
  this->vertex_opacity[2] = vertex_opacity[2];
  this->vertex_opacity[3] = vertex_opacity[3];
  this->flipped = flipped;
}

void TextureDrawQuad::AppendResources(
    ResourceProvider::ResourceIdArray* resources) {
  resources->push_back(resource_id);
}

const TextureDrawQuad* TextureDrawQuad::MaterialCast(const DrawQuad* quad) {
  DCHECK(quad->material == DrawQuad::TEXTURE_CONTENT);
  return static_cast<const TextureDrawQuad*>(quad);
}

bool TextureDrawQuad::PerformClipping() {
  // This only occurs if the rect is only scaled and translated (and thus still
  // axis aligned).
  if (!quadTransform().IsPositiveScaleOrTranslation())
    return false;

  // Grab our scale and make sure it's positive.
  float x_scale = static_cast<float>(quadTransform().matrix().getDouble(0, 0));
  float y_scale = static_cast<float>(quadTransform().matrix().getDouble(1, 1));

  // Grab our offset.
  gfx::Vector2dF offset(
      static_cast<float>(quadTransform().matrix().getDouble(0, 3)),
      static_cast<float>(quadTransform().matrix().getDouble(1, 3)));

  // Transform the rect by the scale and offset.
  gfx::RectF rectF = rect;
  rectF.Scale(x_scale, y_scale);
  rectF += offset;

  // Perform clipping and check to see if the result is empty.
  gfx::RectF clippedRect = IntersectRects(rectF, clipRect());
  if (clippedRect.IsEmpty()) {
    rect = gfx::Rect();
    uv_top_left = gfx::PointF();
    uv_bottom_right = gfx::PointF();
    return true;
  }

  // Create a new uv-rect by clipping the old one to the new bounds.
  gfx::Vector2dF uv_scale(uv_bottom_right - uv_top_left);
  uv_scale.Scale(1.f / rectF.width(), 1.f / rectF.height());
  uv_bottom_right = uv_top_left +
      gfx::ScaleVector2d(
          clippedRect.bottom_right() - rectF.origin(),
          uv_scale.x(),
          uv_scale.y());
  uv_top_left = uv_top_left +
      gfx::ScaleVector2d(
          clippedRect.origin() - rectF.origin(),
          uv_scale.x(),
          uv_scale.y());

  // Indexing according to the quad vertex generation:
  // 1--2
  // |  |
  // 0--3
  if (vertex_opacity[0] != vertex_opacity[1]
      || vertex_opacity[0] != vertex_opacity[2]
      || vertex_opacity[0] != vertex_opacity[3]) {
    const float x1 = (clippedRect.x() - rectF.x()) / rectF.width();
    const float y1 = (clippedRect.y() - rectF.y()) / rectF.height();
    const float x3 = (clippedRect.right() - rectF.x()) / rectF.width();
    const float y3 = (clippedRect.bottom() - rectF.y()) / rectF.height();
    const float x1y1 = x1 * vertex_opacity[2] + (1.0f - x1) * vertex_opacity[1];
    const float x1y3 = x1 * vertex_opacity[3] + (1.0f - x1) * vertex_opacity[0];
    const float x3y1 = x3 * vertex_opacity[2] + (1.0f - x3) * vertex_opacity[1];
    const float x3y3 = x3 * vertex_opacity[3] + (1.0f - x3) * vertex_opacity[0];
    vertex_opacity[0] = y3 * x1y3 + (1.0f - y3) * x1y1;
    vertex_opacity[1] = y1 * x1y3 + (1.0f - y1) * x1y1;
    vertex_opacity[2] = y1 * x3y3 + (1.0f - y1) * x3y1;
    vertex_opacity[3] = y3 * x3y3 + (1.0f - y3) * x3y1;
  }

  // Move the clipped rectangle back into its space.
  clippedRect -= offset;
  clippedRect.Scale(1.0f / x_scale, 1.0f / y_scale);
  rect = gfx::Rect(static_cast<int>(clippedRect.x() + 0.5f),
                   static_cast<int>(clippedRect.y() + 0.5f),
                   static_cast<int>(clippedRect.width() + 0.5f),
                   static_cast<int>(clippedRect.height() + 0.5f));
  return true;
}

}  // namespace cc