1f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner// Use of this source code is governed by a BSD-style license that can be
3f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner// found in the LICENSE file.
4f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
5f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "content/common/gpu/stream_texture_android.h"
6f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
7f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "base/bind.h"
8f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "content/common/android/surface_texture_peer.h"
9f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "content/common/gpu/gpu_channel.h"
10f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "content/common/gpu/gpu_messages.h"
11f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "gpu/command_buffer/service/context_group.h"
12f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "gpu/command_buffer/service/context_state.h"
13f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
14f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "gpu/command_buffer/service/texture_manager.h"
15cd6636c737a82949ad13db2d0d918af6424fb78bDuncan Sands#include "ui/gfx/size.h"
16f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "ui/gl/scoped_make_current.h"
17f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
18f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnernamespace content {
19f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
20f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerusing gpu::gles2::ContextGroup;
21f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerusing gpu::gles2::GLES2Decoder;
22f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerusing gpu::gles2::TextureManager;
23f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerusing gpu::gles2::TextureRef;
24f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
25f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner// static
26f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerbool StreamTexture::Create(
27f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    GpuCommandBufferStub* owner_stub,
28f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    uint32 client_texture_id,
29f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    int stream_id) {
30f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  GLES2Decoder* decoder = owner_stub->decoder();
31db125cfaf57cc83e7dd7453de2d509bc8efd0e5eChris Lattner  TextureManager* texture_manager =
32db125cfaf57cc83e7dd7453de2d509bc8efd0e5eChris Lattner      decoder->GetContextGroup()->texture_manager();
33f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  TextureRef* texture = texture_manager->GetTexture(client_texture_id);
34c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner
35c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner  if (texture && (!texture->texture()->target() ||
36c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner                  texture->texture()->target() == GL_TEXTURE_EXTERNAL_OES)) {
37c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner
38c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner    // TODO: Ideally a valid image id was returned to the client so that
39c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner    // it could then call glBindTexImage2D() for doing the following.
40c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner    scoped_refptr<gfx::GLImage> gl_image(
41c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner        new StreamTexture(owner_stub, stream_id, texture->service_id()));
42c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner    gfx::Size size = gl_image->GetSize();
43f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    texture_manager->SetTarget(texture, GL_TEXTURE_EXTERNAL_OES);
44f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    texture_manager->SetLevelInfo(texture,
45f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                                  GL_TEXTURE_EXTERNAL_OES,
46f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                                  0,
47f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                                  GL_RGBA,
48c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner                                  size.width(),
49f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                                  size.height(),
50f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                                  1,
51f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                                  0,
52f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                                  GL_RGBA,
53f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                                  GL_UNSIGNED_BYTE,
54c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner                                  true);
55c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner    texture_manager->SetLevelImage(
56f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner        texture, GL_TEXTURE_EXTERNAL_OES, 0, gl_image);
57f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    return true;
58c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner  }
59c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner
60c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner  return false;
61c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner}
62c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner
63c8cb8ef9c2d5e354db661022d707a19b3533c00eChris LattnerStreamTexture::StreamTexture(GpuCommandBufferStub* owner_stub,
64c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner                             int32 route_id,
65f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                             uint32 texture_id)
66f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    : surface_texture_(gfx::SurfaceTexture::Create(texture_id)),
67f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      size_(0, 0),
68f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      has_valid_frame_(false),
69f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      has_pending_frame_(false),
70f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      owner_stub_(owner_stub),
71f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      route_id_(route_id),
72f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      has_listener_(false),
73f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      weak_factory_(this) {
74f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  owner_stub->AddDestructionObserver(this);
75f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  memset(current_matrix_, 0, sizeof(current_matrix_));
76f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  owner_stub->channel()->AddRoute(route_id, this);
77f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  surface_texture_->SetFrameAvailableCallback(base::Bind(
78f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      &StreamTexture::OnFrameAvailable, weak_factory_.GetWeakPtr()));
79f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner}
80f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
81f54e72962991005a3c0cc7dce0c550a14af90792Chris LattnerStreamTexture::~StreamTexture() {
82f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  if (owner_stub_) {
833ecfc861b4365f341c5c969b40e1afccde676e6fJay Foad    owner_stub_->RemoveDestructionObserver(this);
84f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    owner_stub_->channel()->RemoveRoute(route_id_);
85f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  }
86f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner}
87f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
88f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::OnWillDestroyStub() {
89f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  owner_stub_->RemoveDestructionObserver(this);
90f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  owner_stub_->channel()->RemoveRoute(route_id_);
913ecfc861b4365f341c5c969b40e1afccde676e6fJay Foad  owner_stub_ = NULL;
92f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
93f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  // If the owner goes away, there is no need to keep the SurfaceTexture around.
94f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  // The GL texture will keep working regardless with the currently bound frame.
95f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  surface_texture_ = NULL;
96f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner}
97f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
98f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::Destroy(bool have_context) {
99f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  NOTREACHED();
100f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner}
101f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
102f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::WillUseTexImage() {
103f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  if (!owner_stub_ || !surface_texture_.get())
104f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    return;
105f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
106f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  if (has_pending_frame_) {
107f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
108f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    bool needs_make_current =
109f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner        !owner_stub_->decoder()->GetGLContext()->IsCurrent(NULL);
110f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    // On Android we should not have to perform a real context switch here when
111f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    // using virtual contexts.
112f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    DCHECK(!needs_make_current || !owner_stub_->decoder()
113a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman                                       ->GetContextGroup()
114a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman                                       ->feature_info()
115a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman                                       ->workarounds()
116a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman                                       .use_virtualized_gl_contexts);
117a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman    if (needs_make_current) {
118a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman      scoped_make_current.reset(new ui::ScopedMakeCurrent(
119a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman          owner_stub_->decoder()->GetGLContext(), owner_stub_->surface()));
120c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner    }
121c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner    surface_texture_->UpdateTexImage();
122c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner    has_valid_frame_ = true;
123c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner    has_pending_frame_ = false;
124c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner    if (scoped_make_current.get()) {
125c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner      // UpdateTexImage() implies glBindTexture().
126a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman      // The cmd decoder takes care of restoring the binding for this GLImage as
127c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner      // far as the current context is concerned, but if we temporarily change
128f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      // it, we have to keep the state intact in *that* context also.
129f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      const gpu::gles2::ContextState* state =
130f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner          owner_stub_->decoder()->GetContextState();
131f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      const gpu::gles2::TextureUnit& active_unit =
132f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner          state->texture_units[state->active_texture_unit];
133f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      glBindTexture(GL_TEXTURE_EXTERNAL_OES,
134f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                    active_unit.bound_texture_external_oes
135f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                        ? active_unit.bound_texture_external_oes->service_id()
136f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                        : 0);
137f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    }
138f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  }
139f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
140f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  if (has_listener_ && has_valid_frame_) {
141f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    float mtx[16];
142f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    surface_texture_->GetTransformMatrix(mtx);
143f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
1444bd8217af3cf38f9fcce378fbc687162e28a7cf8Chris Lattner    // Only query the matrix once we have bound a valid frame.
1454bd8217af3cf38f9fcce378fbc687162e28a7cf8Chris Lattner    if (memcmp(current_matrix_, mtx, sizeof(mtx)) != 0) {
146f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      memcpy(current_matrix_, mtx, sizeof(mtx));
147f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
148f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      GpuStreamTextureMsg_MatrixChanged_Params params;
149f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      memcpy(&params.m00, mtx, sizeof(mtx));
150f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      owner_stub_->channel()->Send(
151f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner          new GpuStreamTextureMsg_MatrixChanged(route_id_, params));
152f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    }
1534bd8217af3cf38f9fcce378fbc687162e28a7cf8Chris Lattner  }
1544bd8217af3cf38f9fcce378fbc687162e28a7cf8Chris Lattner}
155f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
156f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::OnFrameAvailable() {
157f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  has_pending_frame_ = true;
158f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  if (has_listener_ && owner_stub_) {
159f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    owner_stub_->channel()->Send(
160f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner        new GpuStreamTextureMsg_FrameAvailable(route_id_));
161f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  }
162f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner}
163f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
164f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnergfx::Size StreamTexture::GetSize() {
165f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  return size_;
166f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner}
167f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
168f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerbool StreamTexture::OnMessageReceived(const IPC::Message& message) {
169f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  bool handled = true;
170f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  IPC_BEGIN_MESSAGE_MAP(StreamTexture, message)
171f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_StartListening, OnStartListening)
172f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_EstablishPeer, OnEstablishPeer)
173f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_SetSize, OnSetSize)
174f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    IPC_MESSAGE_UNHANDLED(handled = false)
175f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  IPC_END_MESSAGE_MAP()
176f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
177f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  DCHECK(handled);
178f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  return handled;
179f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner}
180f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
181f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::OnStartListening() {
182f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  DCHECK(!has_listener_);
183f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  has_listener_ = true;
184f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner}
185f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
186f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::OnEstablishPeer(int32 primary_id, int32 secondary_id) {
187f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  if (!owner_stub_)
188f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner    return;
189f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
190f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  base::ProcessHandle process = owner_stub_->channel()->renderer_pid();
191f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
192f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  SurfaceTexturePeer::GetInstance()->EstablishSurfaceTexturePeer(
193f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner      process, surface_texture_, primary_id, secondary_id);
194f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner}
195f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
196f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerbool StreamTexture::BindTexImage(unsigned target) {
197f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  NOTREACHED();
198f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  return false;
199f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner}
200f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
201f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::ReleaseTexImage(unsigned target) {
202f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  NOTREACHED();
203f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner}
204f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
205f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerbool StreamTexture::CopyTexImage(unsigned target) {
206f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  return false;
2073ecfc861b4365f341c5c969b40e1afccde676e6fJay Foad}
208f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
209f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerbool StreamTexture::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
210f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                                         int z_order,
211f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                                         gfx::OverlayTransform transform,
212f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                                         const gfx::Rect& bounds_rect,
213f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner                                         const gfx::RectF& crop_rect) {
214f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  NOTREACHED();
215f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner  return false;
216f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner}
217f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner
218f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner}  // namespace content
219f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner