Import Cobalt 20.master.0.217501
diff --git a/src/LICENSE b/src/LICENSE
index 3d0f7d3..a32e00c 100644
--- a/src/LICENSE
+++ b/src/LICENSE
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
diff --git a/src/cobalt/CHANGELOG.md b/src/cobalt/CHANGELOG.md
index 6f368aa..45f312d 100644
--- a/src/cobalt/CHANGELOG.md
+++ b/src/cobalt/CHANGELOG.md
@@ -3,11 +3,22 @@
This document records all notable changes made to Cobalt since the last release.
## Version 20
- - **Improvements and Bug Fixes**
- - Fix bug where Cobalt would not refresh the layout when the textContent
- property of a DOM TextNode is modified.
- - **Add support for decoding JPEG images as multi-plane YUV**
+ - **Support for QUIC and SPDY is now enabled.**
+
+ QUIC and SPDY networking protocol support is added and these are enabled by
+ default (if the server supports the protocol). This reduces roundtrip
+ overhead and will improve networking overhead performance, especially on
+ lower quality connections.
+
+ - **BoringSSL replaces OpenSSL enabling architecture-specific optimizations.**
+
+ The update to BoringSSL brings with it the introduction of assembly-optimized
+ architecture-specific optimizations that can bring a 5x speed up to
+ cryptographic functions. This is especially useful when decrypting TLS for
+ high-bandwidth video.
+
+ - **Added support for decoding JPEG images as multi-plane YUV.**
JPEG images are decoded into RGBA in previous versions of Cobalt. The native
format of most JPEG images is YV12, which takes only 3/8 of memory compare to
@@ -19,6 +30,108 @@
parameter "allow_image_decoding_to_multi_plane" to Cobalt with value "true"
or "false".
+ - **Improved image cache purge strategy.**
+
+ Cobalt's image cache is now more aware of which images are likely to be
+ reused (e.g. the ones referenced by HTMLImageElements, even if they are not
+ currently displayed), and will now prioritize purging completely unreferenced
+ images before weakly referenced images.
+
+ - **Added support for encoded image caching.**
+
+ Cobalt now has support for caching the encoded image data fetched from the
+ network. This enables Cobalt to keep the cached encoded image data resident
+ so that when the user resumes, Cobalt does not need to do a network fetch
+ for images again. The size of this cache can be adjusted via the gyp
+ option `encoded_image_cache_size_in_bytes`, or the command line switch
+ `--encoded_image_cache_size_in_bytes`.
+
+ - **Added support for Device Authentication URL signing.**
+
+ Cobalt will now add URL parameters signed with the device's secret key and
+ certification scope to the initial URL.
+
+ - **Updated Chromium net and base libraries from m25 to m70.**
+
+ Cobalt now has rebased its m25 net and base libraries to Chromium's m70
+ version of those libraries, bringing with it more functionality, better
+ performance, and fewer bugs.
+
+ - **Media Codec Support.**
+
+ Cobalt now supports the AV1 codec, the HEVC (H.265) codec, Dolby Digital
+ (AC-3) and Dolby Digital Plus (Enhanced AC-3, or EAC-3).
+
+ - **Flexbox support added.**
+
+ Cobalt now supports the Flexible Box Module, enabling web applications to
+ take advantage of the more expressive layout model.
+
+ - **Support added for Chromium DevTools with V8.**
+
+ Cobalt now supports the Chromium DevTools to help debug web applications.
+ You can access it on non-gold builds by first starting Cobalt, and then using
+ a browser to navigate to `http://YOUR_DEVICE_IP:9222`. The Elements,
+ Sources, Console and Performance panels are supported.
+
+ - **Support added for Intersection Observer Web API.**
+
+ Cobalt now supports the Intersection Observer Web API to enable more
+ performant checking of whether HTML elements are visible or not. Note that
+ Cobalt's implementation currently does not support triggering visibility
+ events that occur during CSS animation/transition playback.
+
+ - **Support for custom interface HTMLVideoElement.setMaxVideoCapabilities()**
+
+ This allows the web application to express a guarantee to the platform's
+ video player that a video will never exceed a maximum quality in a particular
+ property. You could use this for example to indicate that a video will never
+ adapt past a maximum resolution.
+
+ - **Platform Services API added**
+
+ This API enables web applications to communicate directly to
+ platform-specific services and systems, assuming the platform explicitly
+ enables the given service.
+
+ - **EGL/GLES-based reference implementation of the Blitter API now available.**
+
+ The Blitter API is now much easier to test locally on desktop computers or
+ any device that already supports EGL/GLES. The new platform configuration
+ is named `linux-x64x11-blittergles`.
+
+ - **Add support for AbortController to the Fetch API.**
+
+ The Fetch API is now updated to support the `AbortController` feature.
+
+ - **Support added for HTMLAudioElement HTML tag.**
+
+ This can be used to play audio-only media.
+
+ - **Add support for CSS3 Media Queries “dpi” value.**
+
+ This can be used by the web application to adjust its layout depending
+ on the physical size of the display device, if known.
+
+ - **Add support for scrollWidth, scrollHeight, scrollLeft, and scrollTop.**
+
+ The web application can now query and set scroll properties of containers.
+
+ - **Initial support for Cobalt Evergreen automatic software updater added.**
+
+ Cobalt is transitioning towards a runtime-linkable environment in order to
+ support automatic software updates. Changes have been made around the
+ Starboard interface in anticipation of this. Most notably, the EGL/GLES
+ interface is no longer assumed to be available but rather Cobalt will now
+ query the Starboard implementation for a structure of function pointers that
+ implement the EGL/GLES APIs.
+
+ Part of this process involves moving options that were formerly build-time
+ options to be instead run-time options. This will primarily be enabled
+ by the new Starboard extensions framework. An example of an platform
+ specific option added in this way can be found in
+ `cobalt/extension/graphis.h`.
+
- **Cobalt code assumes that no errors are generated for unused parameters**
There now exists Cobalt code where input parameters may be unused, and it
@@ -45,6 +158,19 @@
that may be copied and queried on any thread to get a coherent view of
attributes set by the the web app on the `MediaSession`.
+ - **Improvements and Bug Fixes**
+
+ - Fix bug where Cobalt would not refresh the layout when the textContent
+ property of a DOM TextNode is modified.
+ - Media codecs can now be disabled with the “--disable_media_codecs” command
+ line option to help with debugging.
+ - Enable “--proxy” command line flag in gold builds of Cobalt.
+ - Add `GetMaximumFrameIntervalInMilliseconds()` platform Cobalt configuration
+ setting (in `cobalt/extension/graphics.h`) to allow a platform to indicate a
+ minimum framerate causing Cobalt to rerender the display even if nothing has
+ changed after the specified interval.
+
+
## Version 19
- **Add support for V8 JavaScript Engine**
diff --git a/src/cobalt/audio/audio_device.cc b/src/cobalt/audio/audio_device.cc
index 73f91bc..11ed4d2 100644
--- a/src/cobalt/audio/audio_device.cc
+++ b/src/cobalt/audio/audio_device.cc
@@ -30,17 +30,13 @@
namespace {
const int kRenderBufferSizeFrames = 1024;
+// AudioDevice will keep writing silence frames at the end of playback until the
+// buffer is full to ensure the audible frames being played on platforms with
+// strict underflow control. A large |kFramesPerChannel| will increase the
+// silence between two sounds. So it shouldn't be set to a very large number.
const int kFramesPerChannel = kRenderBufferSizeFrames * 8;
} // namespace
-namespace {
-// Write |kTailSizeInFrames| frames of silence at the end of playback to ensure
-// the audible frames being played on platforms with strict underflow control.
-// Increasing this value will also increase the silence between two sounds. So
-// it shouldn't be set to a very too large.
-const int kTailSizeInFrames = kRenderBufferSizeFrames * 8;
-} // namespace
-
class AudioDevice::Impl {
public:
Impl(int number_of_channels, RenderCallback* callback);
@@ -162,6 +158,9 @@
bool* is_playing,
bool* is_eos_reached) {
TRACE_EVENT0("cobalt::audio", "AudioDevice::Impl::UpdateSourceStatus()");
+ // AudioDevice may be reused after stopped but before destroyed. Keep writing
+ // silence before destroyed to let |audio_sink_| keep working without
+ // underflow. It will cause latency between two sounds.
*is_playing = true;
*is_eos_reached = false;
@@ -182,28 +181,23 @@
render_callback_->FillAudioBus(all_consumed, &input_audio_bus_, &silence);
- bool fill_output = true;
if (silence) {
- fill_output = kTailSizeInFrames > silence_written_;
silence_written_ += kRenderBufferSizeFrames;
} else {
// Reset |silence_written_| if a new sound is played after some silence
// frames were injected.
silence_written_ = 0;
}
- if (fill_output) {
- FillOutputAudioBus();
- frames_rendered_ += kRenderBufferSizeFrames;
- *frames_in_buffer += kRenderBufferSizeFrames;
- }
+ FillOutputAudioBus();
+
+ frames_rendered_ += kRenderBufferSizeFrames;
+ *frames_in_buffer += kRenderBufferSizeFrames;
was_silence_last_update_ = silence;
}
*offset_in_frames = frames_consumed_ % kFramesPerChannel;
- *is_playing =
- !(silence_written_ != 0 && *frames_in_buffer <= silence_written_);
}
void AudioDevice::Impl::ConsumeFrames(int frames_consumed) {
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index fad5331..1708028 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -465,7 +465,11 @@
#endif
}
-void BrowserModule::Navigate(const GURL& url) {
+void BrowserModule::Navigate(const GURL& url_reference) {
+ // The argument is sometimes |pending_navigate_url_|, and Navigate can modify
+ // |pending_navigate_url_|, so we want to keep a copy of the argument to
+ // preserve its original value.
+ GURL url = url_reference;
DLOG(INFO) << "In BrowserModule::Navigate " << url;
TRACE_EVENT1("cobalt::browser", "BrowserModule::Navigate()", "url",
url.spec());
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index 74e0fc3..0bc7d1a 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -125,7 +125,7 @@
// currently suspended, this defers the navigation and instead sets
// |pending_navigate_url_| to the specified url, which will trigger a
// navigation when Cobalt resumes.
- void Navigate(const GURL& url);
+ void Navigate(const GURL& url_reference);
// Reloads web module.
void Reload();
diff --git a/src/cobalt/build/all.gyp b/src/cobalt/build/all.gyp
index 8909d7a..a53c52f 100644
--- a/src/cobalt/build/all.gyp
+++ b/src/cobalt/build/all.gyp
@@ -86,6 +86,7 @@
'<(DEPTH)/cobalt/websocket/websocket.gyp:*',
'<(DEPTH)/cobalt/xhr/xhr.gyp:*',
'<(DEPTH)/crypto/crypto.gyp:crypto_unittests',
+ '<(DEPTH)/third_party/boringssl/boringssl_tool.gyp:*',
'<(DEPTH)/net/net.gyp:net_unittests',
'<(DEPTH)/sql/sql.gyp:sql_unittests',
],
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 04c18cb..80c1e89 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-215766
\ No newline at end of file
+217501
\ No newline at end of file
diff --git a/src/cobalt/cssom/cssom.gyp b/src/cobalt/cssom/cssom.gyp
index bab7890..3fdf9f1 100644
--- a/src/cobalt/cssom/cssom.gyp
+++ b/src/cobalt/cssom/cssom.gyp
@@ -233,7 +233,6 @@
'unicode_range_value.h',
'universal_selector.cc',
'universal_selector.h',
- 'used_style.h',
'user_agent_style_sheet.cc',
'user_agent_style_sheet.h',
'url_src_value.cc',
diff --git a/src/cobalt/cssom/used_style.h b/src/cobalt/cssom/used_style.h
deleted file mode 100644
index 7aa05c7..0000000
--- a/src/cobalt/cssom/used_style.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2019 The Cobalt Authors. All Rights Reserved.
-//
-// 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.
-
-#ifndef COBALT_CSSOM_USED_STYLE_H_
-#define COBALT_CSSOM_USED_STYLE_H_
-
-#include "base/optional.h"
-#include "cobalt/cssom/calc_value.h"
-#include "cobalt/cssom/length_value.h"
-#include "cobalt/cssom/percentage_value.h"
-#include "cobalt/cssom/property_value_visitor.h"
-#include "cobalt/layout/layout_unit.h"
-
-namespace cobalt {
-namespace cssom {
-
-template <typename LengthType>
-class UsedLengthValueProvider : public NotReachedPropertyValueVisitor {
- public:
- explicit UsedLengthValueProvider(LengthType percentage_base,
- bool calc_permitted = false)
- : percentage_base_(percentage_base), calc_permitted_(calc_permitted) {}
-
- void VisitLength(LengthValue* length) {
- depends_on_containing_block_ = false;
-
- DCHECK_EQ(kPixelsUnit, length->unit());
- used_length_ = LengthType(length->value());
- }
-
- void VisitPercentage(PercentageValue* percentage) {
- depends_on_containing_block_ = true;
- used_length_ = percentage->value() * percentage_base_;
- }
-
- void VisitCalc(CalcValue* calc) {
- if (!calc_permitted_) {
- NOTREACHED();
- }
- depends_on_containing_block_ = true;
- used_length_ = LengthType(calc->length_value()->value()) +
- calc->percentage_value()->value() * percentage_base_;
- }
-
- bool depends_on_containing_block() const {
- return depends_on_containing_block_;
- }
-
- const base::Optional<LengthType>& used_length() const { return used_length_; }
-
- protected:
- bool depends_on_containing_block_;
-
- private:
- const LengthType percentage_base_;
- const bool calc_permitted_;
-
- base::Optional<LengthType> used_length_;
-
- DISALLOW_COPY_AND_ASSIGN(UsedLengthValueProvider);
-};
-
-} // namespace cssom
-} // namespace cobalt
-
-#endif // COBALT_CSSOM_USED_STYLE_H_
diff --git a/src/cobalt/demos/content/media-element-demo/multi-video-demo.js b/src/cobalt/demos/content/media-element-demo/multi-video-demo.js
index 6df7c71..cab4d58 100644
--- a/src/cobalt/demos/content/media-element-demo/multi-video-demo.js
+++ b/src/cobalt/demos/content/media-element-demo/multi-video-demo.js
@@ -37,7 +37,7 @@
}
onsourceopen() {
- if (this.video_url.base::EndsWith('.mp4')) {
+ if (this.video_url.endsWith('.mp4')) {
this.video_source_buffer = this.mediasource.addSourceBuffer(
'video/mp4; codecs="avc1.640028"');
} else {
diff --git a/src/cobalt/dom/dom.gyp b/src/cobalt/dom/dom.gyp
index 7d1278a..f20646d 100644
--- a/src/cobalt/dom/dom.gyp
+++ b/src/cobalt/dom/dom.gyp
@@ -99,6 +99,8 @@
'dom_token_list.h',
'element.cc',
'element.h',
+ 'element_intersection_observer_module.cc',
+ 'element_intersection_observer_module.h',
'eme/media_encrypted_event.cc',
'eme/media_encrypted_event.h',
'eme/media_key_message_event.cc',
@@ -193,9 +195,6 @@
'intersection_observer_entry.h',
'intersection_observer_entry_init.h',
'intersection_observer_init.h',
- 'intersection_observer_registration.h',
- 'intersection_observer_target.h',
- 'intersection_observer_target.cc',
'intersection_observer_task_manager.cc',
'intersection_observer_task_manager.h',
'keyboard_event.cc',
@@ -264,8 +263,6 @@
'progress_event.h',
'pseudo_element.cc',
'pseudo_element.h',
- 'intersection_observer_registration_list.cc',
- 'intersection_observer_registration_list.h',
'registered_observer.h',
'registered_observer_list.cc',
'registered_observer_list.h',
diff --git a/src/cobalt/dom/element.cc b/src/cobalt/dom/element.cc
index dd4638f..04aff96 100644
--- a/src/cobalt/dom/element.cc
+++ b/src/cobalt/dom/element.cc
@@ -15,7 +15,6 @@
#include "cobalt/dom/element.h"
#include <algorithm>
-#include <ctime>
#include "base/lazy_instance.h"
#include "base/strings/string_util.h"
@@ -240,7 +239,7 @@
if (document && GetRootNode() == document) {
document->OnDOMMutation();
}
- OnSetAttribute(name, value);
+ OnSetAttribute(attr_name, value);
}
// Algorithm for RemoveAttribute:
@@ -302,7 +301,7 @@
if (document && GetRootNode() == document) {
document->OnDOMMutation();
}
- OnRemoveAttribute(name);
+ OnRemoveAttribute(attr_name);
}
// Algorithm for tag_name:
@@ -625,37 +624,71 @@
}
}
-void Element::RegisterIntersectionObserverTarget(
- const scoped_refptr<IntersectionObserver>& observer) {
- if (!intersection_observer_target_) {
- intersection_observer_target_ = std::unique_ptr<IntersectionObserverTarget>(
- new IntersectionObserverTarget(this));
+void Element::RegisterIntersectionObserverRoot(IntersectionObserver* observer) {
+ EnsureIntersectionObserverModuleInitialized();
+ element_intersection_observer_module_->RegisterIntersectionObserverForRoot(
+ observer);
+}
+
+void Element::UnregisterIntersectionObserverRoot(
+ IntersectionObserver* observer) {
+ if (element_intersection_observer_module_) {
+ element_intersection_observer_module_
+ ->UnregisterIntersectionObserverForRoot(observer);
}
- intersection_observer_target_->RegisterIntersectionObserver(observer);
+}
+
+void Element::RegisterIntersectionObserverTarget(
+ IntersectionObserver* observer) {
+ EnsureIntersectionObserverModuleInitialized();
+ element_intersection_observer_module_->RegisterIntersectionObserverForTarget(
+ observer);
}
void Element::UnregisterIntersectionObserverTarget(
- const scoped_refptr<IntersectionObserver>& observer) {
- intersection_observer_target_->UnregisterIntersectionObserver(observer);
+ IntersectionObserver* observer) {
+ element_intersection_observer_module_
+ ->UnregisterIntersectionObserverForTarget(observer);
}
-void Element::UpdateIntersectionObservationsForTarget(
- const scoped_refptr<IntersectionObserver>& observer) {
- intersection_observer_target_->UpdateIntersectionObservationsForTarget(
- observer);
+ElementIntersectionObserverModule::LayoutIntersectionObserverRootVector
+Element::GetLayoutIntersectionObserverRoots() {
+ ElementIntersectionObserverModule::LayoutIntersectionObserverRootVector
+ layout_roots;
+ if (element_intersection_observer_module_) {
+ layout_roots = element_intersection_observer_module_
+ ->GetLayoutIntersectionObserverRootsForElement();
+ }
+ return layout_roots;
+}
+
+ElementIntersectionObserverModule::LayoutIntersectionObserverTargetVector
+Element::GetLayoutIntersectionObserverTargets() {
+ ElementIntersectionObserverModule::LayoutIntersectionObserverTargetVector
+ layout_targets;
+ if (element_intersection_observer_module_) {
+ layout_targets = element_intersection_observer_module_
+ ->GetLayoutIntersectionObserverTargetsForElement();
+ }
+ return layout_targets;
}
scoped_refptr<HTMLElement> Element::AsHTMLElement() { return NULL; }
// Explicitly defined because DOMTokenList is forward declared and held by
// scoped_refptr in Element's header.
-Element::~Element() {}
+Element::~Element() {
+ // Reset the ElementIntersectionObserverModule so that functions such as
+ // UnregisterIntersectionRoot/Target will not be called on deleted objects.
+ element_intersection_observer_module_.reset();
+}
void Element::TraceMembers(script::Tracer* tracer) {
Node::TraceMembers(tracer);
tracer->Trace(named_node_map_);
tracer->Trace(class_list_);
+ tracer->Trace(element_intersection_observer_module_);
}
bool Element::GetBooleanAttribute(const std::string& name) const {
@@ -695,5 +728,13 @@
LOG(WARNING) << "Error when parsing inner HTML or outer HTML: " << error;
}
+void Element::EnsureIntersectionObserverModuleInitialized() {
+ if (!element_intersection_observer_module_) {
+ element_intersection_observer_module_ =
+ std::unique_ptr<ElementIntersectionObserverModule>(
+ new ElementIntersectionObserverModule(this));
+ }
+}
+
} // namespace dom
} // namespace cobalt
diff --git a/src/cobalt/dom/element.h b/src/cobalt/dom/element.h
index 22b1bfd..d37f9bc 100644
--- a/src/cobalt/dom/element.h
+++ b/src/cobalt/dom/element.h
@@ -25,8 +25,8 @@
#include "cobalt/base/token.h"
#include "cobalt/cssom/style_sheet_list.h"
#include "cobalt/dom/dom_exception.h"
+#include "cobalt/dom/element_intersection_observer_module.h"
#include "cobalt/dom/intersection_observer.h"
-#include "cobalt/dom/intersection_observer_target.h"
#include "cobalt/dom/node.h"
#include "cobalt/script/exception_state.h"
#include "cobalt/web_animations/animation_set.h"
@@ -199,17 +199,14 @@
return animations_;
}
- void RegisterIntersectionObserverTarget(
- const scoped_refptr<IntersectionObserver>& observer);
-
- void UnregisterIntersectionObserverTarget(
- const scoped_refptr<IntersectionObserver>& observer);
-
- // Queues an IntersectionObserverEntry if the thresholdIndex or isIntersecting
- // properties have changed for the IntersectionObserverRegistration record
- // corresponding to the given observer and this element (the target).
- void UpdateIntersectionObservationsForTarget(
- const scoped_refptr<IntersectionObserver>& observer);
+ void RegisterIntersectionObserverRoot(IntersectionObserver* observer);
+ void UnregisterIntersectionObserverRoot(IntersectionObserver* observer);
+ void RegisterIntersectionObserverTarget(IntersectionObserver* observer);
+ void UnregisterIntersectionObserverTarget(IntersectionObserver* observer);
+ ElementIntersectionObserverModule::LayoutIntersectionObserverRootVector
+ GetLayoutIntersectionObserverRoots();
+ ElementIntersectionObserverModule::LayoutIntersectionObserverTargetVector
+ GetLayoutIntersectionObserverTargets();
DEFINE_WRAPPABLE_TYPE(Element);
void TraceMembers(script::Tracer* tracer) override;
@@ -243,6 +240,8 @@
// Callback for error when parsing inner / outer HTML.
void HTMLParseError(const std::string& error);
+ void EnsureIntersectionObserverModuleInitialized();
+
// Local name of the element.
base::Token local_name_;
// A map that holds the actual element attributes.
@@ -261,7 +260,8 @@
// A set of all animations currently applied to this element.
scoped_refptr<web_animations::AnimationSet> animations_;
- std::unique_ptr<IntersectionObserverTarget> intersection_observer_target_;
+ std::unique_ptr<ElementIntersectionObserverModule>
+ element_intersection_observer_module_;
};
} // namespace dom
diff --git a/src/cobalt/dom/element_intersection_observer_module.cc b/src/cobalt/dom/element_intersection_observer_module.cc
new file mode 100644
index 0000000..01fb8a3
--- /dev/null
+++ b/src/cobalt/dom/element_intersection_observer_module.cc
@@ -0,0 +1,183 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/dom/element_intersection_observer_module.h"
+
+#include "cobalt/dom/document.h"
+#include "cobalt/dom/dom_rect_read_only.h"
+#include "cobalt/dom/element.h"
+#include "cobalt/dom/intersection_observer_entry_init.h"
+#include "cobalt/dom/performance.h"
+
+namespace cobalt {
+namespace dom {
+
+ElementIntersectionObserverModule::ElementIntersectionObserverModule(
+ Element* element)
+ : element_(element) {}
+
+void ElementIntersectionObserverModule::RegisterIntersectionObserverForRoot(
+ IntersectionObserver* observer) {
+ for (auto it = root_registered_intersection_observers_.begin();
+ it != root_registered_intersection_observers_.end(); ++it) {
+ if (*it == observer) {
+ return;
+ }
+ }
+ root_registered_intersection_observers_.push_back(
+ base::WrapRefCounted(observer));
+
+ // Also create the observer's layout root at this time.
+ scoped_refptr<layout::IntersectionObserverRoot> new_root =
+ new layout::IntersectionObserverRoot(
+ observer->root_margin_property_value(),
+ observer->thresholds_vector());
+ observer->set_layout_root(new_root);
+
+ InvalidateLayoutBoxesForElement();
+}
+
+void ElementIntersectionObserverModule::UnregisterIntersectionObserverForRoot(
+ IntersectionObserver* observer) {
+ for (auto it = root_registered_intersection_observers_.begin();
+ it != root_registered_intersection_observers_.end(); ++it) {
+ if (*it == observer) {
+ root_registered_intersection_observers_.erase(it);
+ InvalidateLayoutBoxesForElement();
+ return;
+ }
+ }
+ NOTREACHED()
+ << "Did not find an intersection observer to unregister for the root.";
+}
+
+void ElementIntersectionObserverModule::RegisterIntersectionObserverForTarget(
+ IntersectionObserver* observer) {
+ for (auto it = target_registered_intersection_observers_.begin();
+ it != target_registered_intersection_observers_.end(); ++it) {
+ if (*it == observer) {
+ return;
+ }
+ }
+ target_registered_intersection_observers_.push_back(
+ base::WrapRefCounted(observer));
+ AddLayoutTargetForObserver(observer);
+
+ InvalidateLayoutBoxesForElement();
+}
+
+void ElementIntersectionObserverModule::UnregisterIntersectionObserverForTarget(
+ IntersectionObserver* observer) {
+ for (auto it = target_registered_intersection_observers_.begin();
+ it != target_registered_intersection_observers_.end(); ++it) {
+ if (*it == observer) {
+ target_registered_intersection_observers_.erase(it);
+ RemoveLayoutTargetForObserver(observer);
+ InvalidateLayoutBoxesForElement();
+ return;
+ }
+ }
+ NOTREACHED()
+ << "Did not find an intersection observer to unregister for the target.";
+}
+
+ElementIntersectionObserverModule::LayoutIntersectionObserverRootVector
+ElementIntersectionObserverModule::
+ GetLayoutIntersectionObserverRootsForElement() {
+ ElementIntersectionObserverModule::LayoutIntersectionObserverRootVector
+ layout_roots;
+ for (const auto& intersection_observer :
+ root_registered_intersection_observers_) {
+ layout_roots.push_back(intersection_observer->layout_root());
+ }
+ return layout_roots;
+}
+
+ElementIntersectionObserverModule::LayoutIntersectionObserverTargetVector
+ElementIntersectionObserverModule::
+ GetLayoutIntersectionObserverTargetsForElement() {
+ return layout_targets_;
+}
+
+void ElementIntersectionObserverModule::
+ CreateIntersectionObserverEntryForObserver(
+ const base::WeakPtr<IntersectionObserver>& observer,
+ math::RectF root_bounds, math::RectF target_rect,
+ math::RectF intersection_rect, bool is_intersecting,
+ float intersection_ratio) {
+ if (!observer) {
+ return;
+ }
+
+ IntersectionObserverEntryInit init_dict;
+ init_dict.set_time(element_->owner_document()
+ ->window()
+ ->performance()
+ ->timing()
+ ->GetNavigationStartClock()
+ ->Now()
+ .InMillisecondsF());
+ init_dict.set_root_bounds(
+ base::WrapRefCounted(new DOMRectReadOnly(root_bounds)));
+ init_dict.set_bounding_client_rect(
+ base::WrapRefCounted(new DOMRectReadOnly(target_rect)));
+ init_dict.set_intersection_rect(
+ base::WrapRefCounted(new DOMRectReadOnly(intersection_rect)));
+ init_dict.set_is_intersecting(is_intersecting);
+ init_dict.set_intersection_ratio(intersection_ratio);
+ init_dict.set_target(base::WrapRefCounted(element_));
+ observer->QueueIntersectionObserverEntry(
+ base::WrapRefCounted(new IntersectionObserverEntry(init_dict)));
+}
+
+void ElementIntersectionObserverModule::TraceMembers(script::Tracer* tracer) {
+ tracer->TraceItems(root_registered_intersection_observers_);
+ tracer->TraceItems(target_registered_intersection_observers_);
+}
+
+void ElementIntersectionObserverModule::AddLayoutTargetForObserver(
+ IntersectionObserver* observer) {
+ layout::IntersectionObserverTarget::OnIntersectionCallback
+ on_intersection_callback =
+ base::Bind(&ElementIntersectionObserverModule::
+ CreateIntersectionObserverEntryForObserver,
+ base::Unretained(this), base::AsWeakPtr(observer));
+ scoped_refptr<layout::IntersectionObserverTarget> layout_target =
+ new layout::IntersectionObserverTarget(on_intersection_callback,
+ observer->layout_root());
+ layout_targets_.push_back(layout_target);
+}
+
+void ElementIntersectionObserverModule::RemoveLayoutTargetForObserver(
+ IntersectionObserver* observer) {
+ for (auto it = layout_targets_.begin(); it != layout_targets_.end(); ++it) {
+ if ((*it)->intersection_observer_root() == observer->layout_root()) {
+ layout_targets_.erase(it);
+ return;
+ }
+ }
+ NOTREACHED() << "Did not find a layout target to remove";
+}
+
+void ElementIntersectionObserverModule::InvalidateLayoutBoxesForElement() {
+ HTMLElement* html_element = element_->AsHTMLElement();
+ if (!html_element) {
+ NOTREACHED();
+ return;
+ }
+ html_element->InvalidateLayoutBoxesOfNodeAndDescendants();
+}
+
+} // namespace dom
+} // namespace cobalt
diff --git a/src/cobalt/dom/element_intersection_observer_module.h b/src/cobalt/dom/element_intersection_observer_module.h
new file mode 100644
index 0000000..348dddc
--- /dev/null
+++ b/src/cobalt/dom/element_intersection_observer_module.h
@@ -0,0 +1,76 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef COBALT_DOM_ELEMENT_INTERSECTION_OBSERVER_MODULE_H_
+#define COBALT_DOM_ELEMENT_INTERSECTION_OBSERVER_MODULE_H_
+
+#include <vector>
+
+#include "cobalt/dom/intersection_observer.h"
+#include "cobalt/math/rect_f.h"
+#include "cobalt/script/tracer.h"
+
+namespace cobalt {
+namespace dom {
+
+class Element;
+
+// This helper class groups the methods and data related to the root and target
+// elements outlined in the intersection observer spec.
+// https://www.w3.org/TR/intersection-observer
+class ElementIntersectionObserverModule : public script::Traceable {
+ public:
+ typedef std::vector<scoped_refptr<IntersectionObserver>>
+ IntersectionObserverVector;
+ typedef std::vector<scoped_refptr<layout::IntersectionObserverRoot>>
+ LayoutIntersectionObserverRootVector;
+ typedef std::vector<scoped_refptr<layout::IntersectionObserverTarget>>
+ LayoutIntersectionObserverTargetVector;
+
+ explicit ElementIntersectionObserverModule(Element* element);
+ ~ElementIntersectionObserverModule() {}
+
+ void RegisterIntersectionObserverForRoot(IntersectionObserver* observer);
+ void UnregisterIntersectionObserverForRoot(IntersectionObserver* observer);
+ void RegisterIntersectionObserverForTarget(IntersectionObserver* observer);
+ void UnregisterIntersectionObserverForTarget(IntersectionObserver* observer);
+
+ LayoutIntersectionObserverRootVector
+ GetLayoutIntersectionObserverRootsForElement();
+ LayoutIntersectionObserverTargetVector
+ GetLayoutIntersectionObserverTargetsForElement();
+
+ void CreateIntersectionObserverEntryForObserver(
+ const base::WeakPtr<IntersectionObserver>& observer,
+ math::RectF root_bounds, math::RectF target_rect,
+ math::RectF intersection_rect, bool is_intersecting,
+ float intersection_ratio);
+
+ void TraceMembers(script::Tracer* tracer) override;
+
+ private:
+ void InvalidateLayoutBoxesForElement();
+ void AddLayoutTargetForObserver(IntersectionObserver* observer);
+ void RemoveLayoutTargetForObserver(IntersectionObserver* observer);
+
+ Element* element_;
+ IntersectionObserverVector root_registered_intersection_observers_;
+ IntersectionObserverVector target_registered_intersection_observers_;
+ LayoutIntersectionObserverTargetVector layout_targets_;
+};
+
+} // namespace dom
+} // namespace cobalt
+
+#endif // COBALT_DOM_ELEMENT_INTERSECTION_OBSERVER_MODULE_H_
diff --git a/src/cobalt/dom/html_anchor_element.cc b/src/cobalt/dom/html_anchor_element.cc
index 74c96aa..c262595 100644
--- a/src/cobalt/dom/html_anchor_element.cc
+++ b/src/cobalt/dom/html_anchor_element.cc
@@ -32,12 +32,16 @@
if (!ResolveAndSetURL(value)) {
url_utils_.set_url(GURL(value));
}
+ } else {
+ HTMLElement::OnSetAttribute(name, value);
}
}
void HTMLAnchorElement::OnRemoveAttribute(const std::string& name) {
if (name == "href") {
url_utils_.set_url(GURL());
+ } else {
+ HTMLElement::OnRemoveAttribute(name);
}
}
diff --git a/src/cobalt/dom/html_element.cc b/src/cobalt/dom/html_element.cc
index 4cb3861..636ef72 100644
--- a/src/cobalt/dom/html_element.cc
+++ b/src/cobalt/dom/html_element.cc
@@ -1015,7 +1015,7 @@
descendant_computed_styles_valid_ = true;
}
-void HTMLElement::MarkDisplayNoneOnNodeAndDescendants() {
+void HTMLElement::MarkNotDisplayedOnNodeAndDescendants() {
// While we do want to clear the animations immediately, we also want to
// ensure that they are also reset starting with the next computed style
// update. This ensures that for example a transition will not be triggered
@@ -1039,7 +1039,7 @@
}
}
- MarkDisplayNoneOnDescendants();
+ MarkNotDisplayedOnDescendants();
}
void HTMLElement::PurgeCachedBackgroundImagesOfNodeAndDescendants() {
@@ -1727,7 +1727,7 @@
}
if (invalidation_flags.mark_descendants_as_display_none) {
- MarkDisplayNoneOnDescendants();
+ MarkNotDisplayedOnDescendants();
}
if (invalidation_flags.invalidate_computed_styles_of_descendants) {
InvalidateComputedStylesOfDescendants();
diff --git a/src/cobalt/dom/html_element.h b/src/cobalt/dom/html_element.h
index de9d187..abb2f2e 100644
--- a/src/cobalt/dom/html_element.h
+++ b/src/cobalt/dom/html_element.h
@@ -278,7 +278,7 @@
const base::TimeDelta& style_change_event_time,
AncestorsAreDisplayed ancestor_is_displayed);
- void MarkDisplayNoneOnNodeAndDescendants() override;
+ void MarkNotDisplayedOnNodeAndDescendants() override;
void PurgeCachedBackgroundImagesOfNodeAndDescendants() override;
void InvalidateComputedStylesOfNodeAndDescendants() override;
void InvalidateLayoutBoxesOfNodeAndAncestors() override;
@@ -346,6 +346,11 @@
void OnInsertedIntoDocument() override;
void OnRemovedFromDocument() override;
+ // From Element.
+ void OnSetAttribute(const std::string& name,
+ const std::string& value) override;
+ void OnRemoveAttribute(const std::string& name) override;
+
// HTMLElement keeps a pointer to the dom stat tracker to ensure that it can
// make stat updates even after its weak pointer to its document has been
// deleted. This is protected because some derived classes need access to it.
@@ -355,11 +360,6 @@
// From Node.
void OnMutation() override;
- // From Element.
- void OnSetAttribute(const std::string& name,
- const std::string& value) override;
- void OnRemoveAttribute(const std::string& name) override;
-
bool IsFocusable();
bool HasTabindexFocusFlag() const;
bool IsBeingRendered();
diff --git a/src/cobalt/dom/html_element_test.cc b/src/cobalt/dom/html_element_test.cc
index df6f1be..8fa740f 100644
--- a/src/cobalt/dom/html_element_test.cc
+++ b/src/cobalt/dom/html_element_test.cc
@@ -68,6 +68,11 @@
const char kFooBarDeclarationString[] = "foo: bar;";
const char kDisplayInlineDeclarationString[] = "display: inline;";
+const char* kHtmlElementTagNames[] = {
+ // "audio", "script", and "video" are excluded since they need more setup.
+ "a", "body", "br", "div", "head", "h1", "html", "img", "link",
+ "meta", "p", "span", "style", "title"
+};
class MockLayoutBoxes : public LayoutBoxes {
public:
@@ -204,31 +209,48 @@
}
TEST_F(HTMLElementTest, Dir) {
- scoped_refptr<HTMLElement> html_element =
- document_->CreateElement("div")->AsHTMLElement();
- EXPECT_EQ("", html_element->dir());
+ for (size_t i = 0; i < arraysize(kHtmlElementTagNames); ++i) {
+ scoped_refptr<HTMLElement> html_element =
+ document_->CreateElement(kHtmlElementTagNames[i])->AsHTMLElement();
+ EXPECT_EQ("", html_element->dir());
- html_element->set_dir("invalid");
- EXPECT_EQ("", html_element->dir());
+ html_element->set_dir("invalid");
+ EXPECT_EQ("", html_element->dir());
- html_element->set_dir("ltr");
- EXPECT_EQ("ltr", html_element->dir());
+ html_element->set_dir("ltr");
+ EXPECT_EQ("ltr", html_element->dir());
- html_element->set_dir("rtl");
- EXPECT_EQ("rtl", html_element->dir());
+ html_element->set_dir("rtl");
+ EXPECT_EQ("rtl", html_element->dir());
- // Value "auto" is not supported.
- html_element->set_dir("auto");
- EXPECT_EQ("", html_element->dir());
+ // Value "auto" is not supported.
+ html_element->set_dir("auto");
+ EXPECT_EQ("", html_element->dir());
+
+ html_element->SetAttribute("Dir", "rtl");
+ EXPECT_EQ("rtl", html_element->dir());
+
+ html_element->RemoveAttribute("diR");
+ EXPECT_EQ("", html_element->dir());
+ }
}
TEST_F(HTMLElementTest, TabIndex) {
- scoped_refptr<HTMLElement> html_element =
- document_->CreateElement("div")->AsHTMLElement();
- EXPECT_EQ(0, html_element->tab_index());
+ for (size_t i = 0; i < arraysize(kHtmlElementTagNames); ++i) {
+ scoped_refptr<HTMLElement> html_element =
+ document_->CreateElement(kHtmlElementTagNames[i])->AsHTMLElement();
- html_element->set_tab_index(-1);
- EXPECT_EQ(-1, html_element->tab_index());
+ EXPECT_EQ(0, html_element->tab_index());
+
+ html_element->set_tab_index(-1);
+ EXPECT_EQ(-1, html_element->tab_index());
+
+ html_element->SetAttribute("tabIndex", "-2");
+ EXPECT_EQ(-2, html_element->tab_index());
+
+ html_element->RemoveAttribute("Tabindex");
+ EXPECT_EQ(0, html_element->tab_index());
+ }
}
TEST_F(HTMLElementTest, Focus) {
diff --git a/src/cobalt/dom/html_image_element.cc b/src/cobalt/dom/html_image_element.cc
index b98a5f9..511d83c 100644
--- a/src/cobalt/dom/html_image_element.cc
+++ b/src/cobalt/dom/html_image_element.cc
@@ -51,7 +51,7 @@
}
void HTMLImageElement::OnSetAttribute(const std::string& name,
- const std::string& /* value */) {
+ const std::string& value) {
// A user agent that obtains images immediately must synchronously update the
// image data of an img element whenever that element is created with a src
// attribute. A user agent that obtains images immediately must also
@@ -59,6 +59,8 @@
// has its src or crossorigin attribute set, changed, or removed.
if (name == "src") {
UpdateImageData();
+ } else {
+ HTMLElement::OnSetAttribute(name, value);
}
}
@@ -70,6 +72,8 @@
// has its src or crossorigin attribute set, changed, or removed.
if (name == "src") {
UpdateImageData();
+ } else {
+ HTMLElement::OnRemoveAttribute(name);
}
}
diff --git a/src/cobalt/dom/intersection_observer.cc b/src/cobalt/dom/intersection_observer.cc
index 7af988a..6fce9cd 100644
--- a/src/cobalt/dom/intersection_observer.cc
+++ b/src/cobalt/dom/intersection_observer.cc
@@ -81,13 +81,23 @@
}
IntersectionObserver::~IntersectionObserver() {
- task_manager()->OnIntersectionObserverDestroyed(this);
+ if (root_) {
+ root_->UnregisterIntersectionObserverRoot(this);
+ }
+ if (intersection_observer_task_manager_) {
+ intersection_observer_task_manager_->OnIntersectionObserverDestroyed(this);
+ }
}
-script::Sequence<double> const IntersectionObserver::thresholds() {
+void IntersectionObserver::set_layout_root(
+ const scoped_refptr<layout::IntersectionObserverRoot>& layout_root) {
+ layout_root_ = layout_root;
+}
+
+script::Sequence<double> IntersectionObserver::thresholds() const {
script::Sequence<double> result;
- for (std::vector<double>::iterator it = thresholds_.begin();
+ for (std::vector<double>::const_iterator it = thresholds_.begin();
it != thresholds_.end(); ++it) {
result.push_back(*it);
}
@@ -101,7 +111,7 @@
NOTREACHED();
return;
}
- target->RegisterIntersectionObserverTarget(base::WrapRefCounted(this));
+ target->RegisterIntersectionObserverTarget(this);
TrackObservationTarget(target);
}
@@ -112,7 +122,7 @@
NOTREACHED();
return;
}
- target->UnregisterIntersectionObserverTarget(base::WrapRefCounted(this));
+ target->UnregisterIntersectionObserverTarget(this);
UntrackObservationTarget(target);
}
@@ -125,7 +135,7 @@
it != observation_targets_.end(); ++it) {
Element* target = it->get();
if (target != NULL) {
- target->UnregisterIntersectionObserverTarget(base::WrapRefCounted(this));
+ target->UnregisterIntersectionObserverTarget(this);
}
}
observation_targets_.clear();
@@ -146,21 +156,8 @@
TRACE_EVENT0("cobalt::dom",
"IntersectionObserver::QueueIntersectionObserverEntry()");
queued_entries_.push_back(entry);
- task_manager()->QueueIntersectionObserverTask();
-}
-
-void IntersectionObserver::UpdateObservationTargets() {
- TRACE_EVENT0("cobalt::dom",
- "IntersectionObserver::UpdateObservationTargets()");
- // https://www.w3.org/TR/intersection-observer/#notify-intersection-observers-algo
- // Step 2 of "run the update intersection observations steps" algorithm:
- // 1. Let rootBounds be observer's root intersection rectangle.
- // 2. For each target in observer's internal [[ObservationTargets]] slot,
- // processed in the same order that observe() was called on each
- // target, run a set of subtasks (subtasks are implemented in
- // IntersectionObserverRegistration::Update):
- for (auto target : observation_targets_) {
- target->UpdateIntersectionObservationsForTarget(this);
+ if (intersection_observer_task_manager_) {
+ intersection_observer_task_manager_->QueueIntersectionObserverTask();
}
}
@@ -184,35 +181,18 @@
}
void IntersectionObserver::TraceMembers(script::Tracer* tracer) {
+ tracer->Trace(root_);
tracer->TraceItems(observation_targets_);
tracer->TraceItems(queued_entries_);
}
-IntersectionObserverTaskManager* IntersectionObserver::task_manager() {
- return root_->owner_document()->intersection_observer_task_manager();
-}
-
void IntersectionObserver::InitIntersectionObserverInternal(
script::EnvironmentSettings* settings,
const IntersectionObserverCallbackArg& callback,
const IntersectionObserverInit& options,
script::ExceptionState* exception_state) {
// https://www.w3.org/TR/intersection-observer/#intersection-observer-interface
- // 1. Let this be a new IntersectionObserver object
- // 2. Set this's internal [[callback]] slot to callback.
- callback_.reset(new ScriptCallback(callback, this));
-
- // 3. Set this.root to options.root.
- if (options.root()) {
- root_ = options.root();
- } else {
- root_ = base::polymorphic_downcast<dom::DOMSettings*>(settings)
- ->window()
- ->document()
- ->document_element();
- }
-
- // 4. Attempt to parse a root margin from options.rootMargin. If a list is
+ // Attempt to parse a root margin from options.rootMargin. If a list is
// returned, set this's internal [[rootMargin]] slot to that. Otherwise, throw
// a SyntaxError exception.
// https://www.w3.org/TR/intersection-observer/#parse-a-root-margin
@@ -237,12 +217,9 @@
"Not able to parse IntersectionObserver root margin.");
}
- // 5. Let thresholds be a list equal to options.threshold.
- // 6. If any value in thresholds is less than 0.0 or greater than 1.0, throw a
+ // Let thresholds be a list equal to options.threshold.
+ // If any value in thresholds is less than 0.0 or greater than 1.0, throw a
// RangeError exception.
- // 7. Sort thresholds in ascending order.
- // 8. If thresholds is empty, append 0 to thresholds.
- // 9. Set this.thresholds to thresholds.
ThresholdType threshold = options.threshold();
if (threshold.IsType<double>()) {
if (threshold.AsType<double>() < 0 || threshold.AsType<double>() > 1) {
@@ -266,13 +243,33 @@
}
thresholds_.push_back(*it);
}
+ // Sort thresholds in ascending order.
sort(thresholds_.begin(), thresholds_.end());
}
+ // If thresholds is empty, append 0 to thresholds.
+
if (thresholds_.empty()) {
thresholds_.push_back(0);
}
- task_manager()->OnIntersectionObserverCreated(this);
+ // Set this's internal [[callback]] slot to callback.
+ callback_.reset(new ScriptCallback(callback, this));
+
+ // Set this.root to options.root.
+ if (options.root()) {
+ root_ = base::AsWeakPtr(options.root().get());
+ } else {
+ root_ =
+ base::AsWeakPtr(base::polymorphic_downcast<dom::DOMSettings*>(settings)
+ ->window()
+ ->document()
+ ->document_element()
+ .get());
+ }
+ root_->RegisterIntersectionObserverRoot(this);
+ intersection_observer_task_manager_ =
+ root_->owner_document()->intersection_observer_task_manager();
+ intersection_observer_task_manager_->OnIntersectionObserverCreated(this);
}
void IntersectionObserver::TrackObservationTarget(
@@ -288,7 +285,7 @@
}
++it;
}
- observation_targets_.push_back(base::WrapRefCounted(target.get()));
+ observation_targets_.push_back(base::AsWeakPtr(target.get()));
}
void IntersectionObserver::UntrackObservationTarget(
diff --git a/src/cobalt/dom/intersection_observer.h b/src/cobalt/dom/intersection_observer.h
index 10b6bab..c1b6ba6 100644
--- a/src/cobalt/dom/intersection_observer.h
+++ b/src/cobalt/dom/intersection_observer.h
@@ -20,8 +20,11 @@
#include "base/callback.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "cobalt/cssom/property_list_value.h"
#include "cobalt/dom/intersection_observer_entry.h"
+#include "cobalt/layout/intersection_observer_root.h"
+#include "cobalt/layout/intersection_observer_target.h"
#include "cobalt/script/callback_function.h"
#include "cobalt/script/environment_settings.h"
#include "cobalt/script/exception_state.h"
@@ -40,7 +43,8 @@
// The IntersectionObserver can be used to observe changes in the intersection
// of an intersection root and one or more target Elements.
// https://www.w3.org/TR/intersection-observer/#intersection-observer-interfaces
-class IntersectionObserver : public script::Wrappable {
+class IntersectionObserver : public base::SupportsWeakPtr<IntersectionObserver>,
+ public script::Wrappable {
public:
typedef script::Sequence<scoped_refptr<IntersectionObserverEntry>>
IntersectionObserverEntrySequence;
@@ -64,17 +68,24 @@
script::ExceptionState* exception_state);
~IntersectionObserver();
- const scoped_refptr<Element>& root() { return root_; }
+ const base::WeakPtr<Element>& root() const { return root_; }
+ void set_layout_root(
+ const scoped_refptr<layout::IntersectionObserverRoot>& layout_root);
+ const scoped_refptr<layout::IntersectionObserverRoot>& layout_root() const {
+ return layout_root_;
+ }
// Part of the IntersectionObserver interface, but differs from the web spec
// in that it returns the exact string passed into |options|, regardless of
// whether it is formatted as four space-separated pixels lengths/percentages.
std::string root_margin() const { return root_margin_; }
// Not part of the IntersectionObserver interface. Returns the root margin
// parsed as a PropertyListValue.
- const scoped_refptr<cssom::PropertyListValue>& root_margin_property_value() {
+ const scoped_refptr<cssom::PropertyListValue>& root_margin_property_value()
+ const {
return root_margin_property_value_;
}
- script::Sequence<double> const thresholds();
+ script::Sequence<double> thresholds() const;
+ std::vector<double> thresholds_vector() const { return thresholds_; }
void Observe(const scoped_refptr<Element>& target);
void Unobserve(const scoped_refptr<Element>& target);
void Disconnect();
@@ -86,11 +97,6 @@
void QueueIntersectionObserverEntry(
const scoped_refptr<IntersectionObserverEntry>& entry);
- // Not part of the IntersectionObserver interface. Implements step (2) of the
- // "run the update intersection observations steps" algorithm.
- // https://www.w3.org/TR/intersection-observer/#notify-intersection-observers-algo
- void UpdateObservationTargets();
-
// Not part of the the IntersectionObserver interface. Implements step (3) of
// the "notify intersection observers" algorithm.
// https://www.w3.org/TR/intersection-observer/#notify-intersection-observers-algo
@@ -115,13 +121,16 @@
void UntrackObservationTarget(const scoped_refptr<Element>& target);
std::unique_ptr<CallbackInternal> callback_;
- scoped_refptr<Element> root_;
+ base::WeakPtr<Element> root_;
+ scoped_refptr<layout::IntersectionObserverRoot> layout_root_;
std::string root_margin_;
scoped_refptr<cssom::PropertyListValue> root_margin_property_value_;
std::vector<double> thresholds_;
- typedef std::vector<scoped_refptr<Element>> ElementVector;
+ typedef std::vector<base::WeakPtr<Element>> ElementVector;
ElementVector observation_targets_;
IntersectionObserverEntrySequence queued_entries_;
+ scoped_refptr<IntersectionObserverTaskManager>
+ intersection_observer_task_manager_;
};
} // namespace dom
diff --git a/src/cobalt/dom/intersection_observer_registration.h b/src/cobalt/dom/intersection_observer_registration.h
deleted file mode 100644
index 4979227..0000000
--- a/src/cobalt/dom/intersection_observer_registration.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2019 The Cobalt Authors. All Rights Reserved.
-//
-// 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.
-
-#ifndef COBALT_DOM_INTERSECTION_OBSERVER_REGISTRATION_H_
-#define COBALT_DOM_INTERSECTION_OBSERVER_REGISTRATION_H_
-
-#include "base/memory/ref_counted.h"
-#include "cobalt/dom/intersection_observer.h"
-#include "cobalt/script/tracer.h"
-
-namespace cobalt {
-namespace dom {
-
-class Element;
-
-// Represents the concept of an "intersection observer registration" as
-// described in the Intersection Observer spec.
-// https://www.w3.org/TR/intersection-observer/#intersectionobserverregistration
-// This class is expected to be used internally in the Element class as a part
-// of intersection reporting.
-class IntersectionObserverRegistration : public script::Traceable {
- public:
- // An IntersectionObserverRegistration must not outlive the |target| element
- // that is being observed.
- IntersectionObserverRegistration(
- const scoped_refptr<IntersectionObserver>& observer)
- : observer_(observer),
- previous_threshold_index_(-1),
- previous_is_intersecting_(false) {}
-
- const IntersectionObserver* observer() const { return observer_; }
- int32 previous_threshold_index() const { return previous_threshold_index_; }
- void set_previous_threshold_index(int32 previous_threshold_index) {
- previous_threshold_index_ = previous_threshold_index;
- }
- bool previous_is_intersecting() const { return previous_is_intersecting_; }
- void set_previous_is_intersecting(bool previous_is_intersecting) {
- previous_is_intersecting_ = previous_is_intersecting;
- }
-
- void TraceMembers(script::Tracer* tracer) override {
- tracer->Trace(observer_);
- }
-
- private:
- IntersectionObserver* observer_;
- int32 previous_threshold_index_;
- bool previous_is_intersecting_;
-};
-
-} // namespace dom
-} // namespace cobalt
-
-#endif // COBALT_DOM_INTERSECTION_OBSERVER_REGISTRATION_H_
diff --git a/src/cobalt/dom/intersection_observer_registration_list.cc b/src/cobalt/dom/intersection_observer_registration_list.cc
deleted file mode 100644
index 14b0541..0000000
--- a/src/cobalt/dom/intersection_observer_registration_list.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2019 The Cobalt Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "cobalt/dom/intersection_observer_registration_list.h"
-
-namespace cobalt {
-namespace dom {
-
-void IntersectionObserverRegistrationList::AddIntersectionObserver(
- const scoped_refptr<IntersectionObserver>& observer) {
- // https://www.w3.org/TR/intersection-observer/#ref-for-dom-intersectionobserver-observe
- // 1. If target is in this's internal [[ObservationTargets]] slot, return.
- for (auto it = registered_intersection_observers_.begin();
- it != registered_intersection_observers_.end(); ++it) {
- if (it->observer() == observer) {
- registered_intersection_observers_.erase(it);
- return;
- }
- }
- // 2. Let intersectionObserverRegistration be an
- // IntersectionObserverRegistration record with an observer property set to
- // this, a previousThresholdIndex property set to -1, and a
- // previousIsIntersecting property set to false.
- // 3. Append intersectionObserverRegistration to target's internal
- // [[RegisteredIntersectionObservers]] slot.
- registered_intersection_observers_.push_back(
- IntersectionObserverRegistration(observer));
- return;
-}
-
-void IntersectionObserverRegistrationList::RemoveIntersectionObserver(
- const scoped_refptr<IntersectionObserver>& observer) {
- for (auto it = registered_intersection_observers_.begin();
- it != registered_intersection_observers_.end(); ++it) {
- if (it->observer() == observer) {
- registered_intersection_observers_.erase(it);
- return;
- }
- }
- NOTREACHED() << "Did not find an intersection observer to unregister.";
-}
-
-IntersectionObserverRegistration*
-IntersectionObserverRegistrationList::FindRegistrationForObserver(
- const scoped_refptr<IntersectionObserver>& observer) {
- for (auto& record : registered_intersection_observers_) {
- if (record.observer() == observer) {
- return &record;
- }
- }
- return NULL;
-}
-
-void IntersectionObserverRegistrationList::TraceMembers(
- script::Tracer* tracer) {
- tracer->TraceItems(registered_intersection_observers_);
-}
-
-} // namespace dom
-} // namespace cobalt
diff --git a/src/cobalt/dom/intersection_observer_registration_list.h b/src/cobalt/dom/intersection_observer_registration_list.h
deleted file mode 100644
index c3f5b07..0000000
--- a/src/cobalt/dom/intersection_observer_registration_list.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2019 The Cobalt Authors. All Rights Reserved.
-//
-// 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.
-
-#ifndef COBALT_DOM_INTERSECTION_OBSERVER_REGISTRATION_LIST_H_
-#define COBALT_DOM_INTERSECTION_OBSERVER_REGISTRATION_LIST_H_
-
-#include <vector>
-
-#include "base/memory/ref_counted.h"
-#include "cobalt/dom/intersection_observer.h"
-#include "cobalt/dom/intersection_observer_registration.h"
-
-namespace cobalt {
-namespace dom {
-
-// A list of "intersection observer registrations" as described in the
-// Intersection Observer spec.
-// https://www.w3.org/TR/intersection-observer/#intersectionobserverregistration
-//
-// Implements the functionality described in the IntersectionObserver.observe
-// method:
-// https://www.w3.org/TR/intersection-observer/#ref-for-dom-intersectionobserver-observe
-class IntersectionObserverRegistrationList : public script::Traceable {
- public:
- typedef std::vector<IntersectionObserverRegistration>
- IntersectionObserverRegistrationVector;
-
- IntersectionObserverRegistrationList() {}
-
- // Implement the IntersectionObserver.observe method
- // https://www.w3.org/TR/intersection-observer/#ref-for-dom-intersectionobserver-observe
- void AddIntersectionObserver(
- const scoped_refptr<IntersectionObserver>& observer);
- // Implement the IntersectionObserver.unobserve method
- // https://www.w3.org/TR/intersection-observer/#dom-intersectionobserver-unobserve
- void RemoveIntersectionObserver(
- const scoped_refptr<IntersectionObserver>& observer);
-
- IntersectionObserverRegistration* FindRegistrationForObserver(
- const scoped_refptr<IntersectionObserver>& observer);
-
- const IntersectionObserverRegistrationVector&
- registered_intersection_observers() {
- return registered_intersection_observers_;
- }
-
- void TraceMembers(script::Tracer* tracer) override;
-
- private:
- IntersectionObserverRegistrationVector registered_intersection_observers_;
-};
-
-} // namespace dom
-} // namespace cobalt
-
-#endif // COBALT_DOM_INTERSECTION_OBSERVER_REGISTRATION_LIST_H_
diff --git a/src/cobalt/dom/intersection_observer_target.cc b/src/cobalt/dom/intersection_observer_target.cc
deleted file mode 100644
index 36c944c..0000000
--- a/src/cobalt/dom/intersection_observer_target.cc
+++ /dev/null
@@ -1,440 +0,0 @@
-// Copyright 2019 The Cobalt Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "cobalt/dom/intersection_observer_target.h"
-
-#include <algorithm>
-
-#include "cobalt/cssom/computed_style_utils.h"
-#include "cobalt/cssom/css_computed_style_data.h"
-#include "cobalt/cssom/used_style.h"
-#include "cobalt/dom/document.h"
-#include "cobalt/dom/element.h"
-#include "cobalt/dom/html_element.h"
-#include "cobalt/dom/intersection_observer_entry_init.h"
-#include "cobalt/dom/performance.h"
-#include "cobalt/script/sequence.h"
-
-namespace cobalt {
-namespace dom {
-
-namespace {
-
-HTMLElement* GetContainingBlockOfHTMLElement(HTMLElement* html_element) {
- // Establish the containing block, as described in
- // http://www.w3.org/TR/CSS2/visudet.html#containing-block-details
- DCHECK(html_element->node_document());
- html_element->node_document()->DoSynchronousLayout();
-
- scoped_refptr<cssom::PropertyValue> position =
- html_element->computed_style()->position();
-
- // The containing block in which the root element lives is a rectangle called
- // the initial containing block. For continuous media, it has the dimensions
- // of the viewport and is anchored at the canvas origin; it is the page area
- // for paged media.
- if (html_element->IsRootElement()) {
- return html_element->owner_document()->document_element()->AsHTMLElement();
- }
-
- for (Node* ancestor_node = html_element->parent_node(); ancestor_node;
- ancestor_node = ancestor_node->parent_node()) {
- Element* ancestor_element = ancestor_node->AsElement();
- if (!ancestor_element) {
- continue;
- }
- HTMLElement* ancestor_html_element = ancestor_element->AsHTMLElement();
- if (!ancestor_html_element) {
- continue;
- }
-
- // If the element has 'position: absolute', the containing block is
- // established by the nearest ancestor with a 'position' of 'absolute',
- // 'relative' or 'fixed'.
- // Transformed elements also act as a containing block for all descendants.
- // https://www.w3.org/TR/css-transforms-1/#transform-rendering.
- if (position == cssom::KeywordValue::GetAbsolute() &&
- ancestor_html_element->computed_style()->position() ==
- cssom::KeywordValue::GetStatic() &&
- ancestor_html_element->computed_style()->transform() ==
- cssom::KeywordValue::GetNone()) {
- continue;
- }
-
- // If the element has 'position: fixed', the containing block is established
- // by the viewport in the case of continuous media or the page area in the
- // case of paged media.
- // Transformed elements also act as a containing block for all descendants.
- // https://www.w3.org/TR/css-transforms-1/#transform-rendering.
- if (position == cssom::KeywordValue::GetFixed() &&
- ancestor_html_element->computed_style()->transform() ==
- cssom::KeywordValue::GetNone()) {
- continue;
- }
-
- // For other elements, if the element's position is 'relative' or 'static',
- // the containing block is formed by the content edge of the nearest block
- // container ancestor box.
- return ancestor_html_element;
- }
-
- // If there is no such ancestor, the containing block is the initial
- // containing block.
- return html_element->owner_document()->document_element()->AsHTMLElement();
-}
-
-bool IsInContainingBlockChain(const HTMLElement* potential_containing_block,
- HTMLElement* html_element) {
- // Walk up the containing block chain, as described in
- // http://www.w3.org/TR/CSS2/visudet.html#containing-block-details
- HTMLElement* containing_block_element =
- GetContainingBlockOfHTMLElement(html_element);
- while (containing_block_element != potential_containing_block) {
- if (!containing_block_element->parent_element()) {
- return false;
- }
- containing_block_element =
- GetContainingBlockOfHTMLElement(containing_block_element);
- }
- return true;
-}
-
-} // namespace
-
-IntersectionObserverTarget::IntersectionObserverTarget(Element* target_element)
- : target_element_(target_element) {}
-
-void IntersectionObserverTarget::RegisterIntersectionObserver(
- const scoped_refptr<IntersectionObserver>& observer) {
- intersection_observer_registration_list_.AddIntersectionObserver(observer);
-}
-
-void IntersectionObserverTarget::UnregisterIntersectionObserver(
- const scoped_refptr<IntersectionObserver>& observer) {
- intersection_observer_registration_list_.RemoveIntersectionObserver(observer);
-}
-
-void IntersectionObserverTarget::UpdateIntersectionObservationsForTarget(
- const scoped_refptr<IntersectionObserver>& observer) {
- // https://www.w3.org/TR/intersection-observer/#update-intersection-observations-algo
- // Subtasks for step 2 of the "run the update intersection observations steps"
- // algorithm:
- // 1. If the intersection root is not the implicit root and target is
- // not a descendant of the intersection root in the containing block
- // chain, skip further processing for target.
- HTMLElement* html_target = target_element_->AsHTMLElement();
- HTMLElement* html_intersection_root = observer->root()->AsHTMLElement();
- if (!html_target || !html_intersection_root) {
- NOTREACHED();
- return;
- }
-
- if (html_intersection_root !=
- target_element_->owner_document()->document_element() &&
- !IsInContainingBlockChain(html_intersection_root, html_target)) {
- return;
- }
-
- // 2. If the intersection root is not the implicit root, and target is
- // not in the same Document as the intersection root, skip further
- // processing for target.
- if (html_intersection_root !=
- target_element_->owner_document()->document_element() &&
- html_intersection_root->owner_document() !=
- target_element_->owner_document()) {
- return;
- }
-
- // 3. Let targetRect be a DOMRectReadOnly obtained by running the
- // getBoundingClientRect() algorithm on target.
- scoped_refptr<DOMRectReadOnly> target_rect =
- target_element_->GetBoundingClientRect();
-
- // 4. Let intersectionRect be the result of running the compute the
- // intersection algorithm on target.
- scoped_refptr<DOMRectReadOnly> root_bounds = GetRootBounds(
- html_intersection_root, observer->root_margin_property_value());
- scoped_refptr<DOMRectReadOnly> intersection_rect =
- ComputeIntersectionBetweenTargetAndRoot(
- html_intersection_root, root_bounds, target_rect,
- base::WrapRefCounted(html_target));
-
- // 5. Let targetArea be targetRect's area.
- float target_area = target_rect->rect().size().GetArea();
-
- // 6. Let intersectionArea be intersectionRect's area.
- float intersection_area = intersection_rect->rect().size().GetArea();
-
- // 7. Let isIntersecting be true if targetRect and rootBounds intersect or
- // are edge-adjacent, even if the intersection has zero area (because
- // rootBounds or targetRect have zero area); otherwise, let
- // isIntersecting be false.
- bool is_intersecting =
- intersection_rect->width() != 0 || intersection_rect->height() != 0;
-
- // 8. If targetArea is non-zero, let intersectionRatio be intersectionArea
- // divided by targetArea. Otherwise, let intersectionRatio be 1 if
- // isIntersecting is true, or 0 if isIntersecting is false.
- float intersection_ratio = is_intersecting ? 1.0f : 0.0f;
- if (target_area != 0) {
- intersection_ratio = intersection_area / target_area;
- }
-
- // 9. Let thresholdIndex be the index of the first entry in
- // observer.thresholds whose value is greater than intersectionRatio,
- // or the length of observer.thresholds if intersectionRatio is greater
- // than or equal to the last entry in observer.thresholds.
- const script::Sequence<double>& thresholds = observer->thresholds();
- size_t threshold_index;
- for (threshold_index = 0; threshold_index < thresholds.size();
- ++threshold_index) {
- if (thresholds.at(threshold_index) > intersection_ratio) {
- break;
- }
- }
-
- // 10. Let intersectionObserverRegistration be the
- // IntersectionObserverRegistration record in target's internal
- // [[RegisteredIntersectionObservers]] slot whose observer property is
- // equal to observer.
- IntersectionObserverRegistration* intersection_observer_registration =
- intersection_observer_registration_list_.FindRegistrationForObserver(
- observer);
-
- if (!intersection_observer_registration) {
- NOTREACHED();
- return;
- }
-
- // 11. Let previousThresholdIndex be the
- // intersectionObserverRegistration's previousThresholdIndex property.
- int32 previous_threshold_index =
- intersection_observer_registration->previous_threshold_index();
-
- // 12. Let previousIsIntersecting be the
- // intersectionObserverRegistration's previousIsIntersecting property.
- bool previous_is_intersecting =
- intersection_observer_registration->previous_is_intersecting();
-
- // 13. If thresholdIndex does not equal previousThresholdIndex or if
- // isIntersecting does not equal previousIsIntersecting, queue an
- // IntersectionObserverEntry, passing in observer, time, rootBounds,
- // boundingClientRect, intersectionRect, isIntersecting, and target.
- if (static_cast<int32>(threshold_index) != previous_threshold_index ||
- is_intersecting != previous_is_intersecting) {
- IntersectionObserverEntryInit init_dict;
- init_dict.set_time(target_element_->owner_document()
- ->window()
- ->performance()
- ->timing()
- ->GetNavigationStartClock()
- ->Now()
- .InMillisecondsF());
- init_dict.set_root_bounds(root_bounds);
- init_dict.set_bounding_client_rect(target_rect);
- init_dict.set_intersection_rect(intersection_rect);
- init_dict.set_is_intersecting(is_intersecting);
- init_dict.set_intersection_ratio(intersection_ratio);
- init_dict.set_target(base::WrapRefCounted(target_element_));
- observer->QueueIntersectionObserverEntry(
- base::WrapRefCounted(new IntersectionObserverEntry(init_dict)));
- }
-
- // 14. Assign threshold to intersectionObserverRegistration's
- // previousThresholdIndex property.
- intersection_observer_registration->set_previous_threshold_index(
- static_cast<int32>(threshold_index));
-
- // 15. Assign isIntersecting to intersectionObserverRegistration's
- // previousIsIntersecting property.
- intersection_observer_registration->set_previous_is_intersecting(
- is_intersecting);
-}
-
-scoped_refptr<DOMRectReadOnly> IntersectionObserverTarget::GetRootBounds(
- const scoped_refptr<HTMLElement>& html_intersection_root,
- scoped_refptr<cssom::PropertyListValue> root_margin_property_value) {
- // https://www.w3.org/TR/intersection-observer/#intersectionobserver-root-intersection-rectangle
- // Rules for determining the root intersection rectangle bounds.
- LayoutBoxes* intersection_root_layout_boxes =
- html_intersection_root->layout_boxes();
- DCHECK(intersection_root_layout_boxes);
-
- math::RectF root_bounds_without_margins;
- // If the intersection root is the implicit root, it's the viewport's size.
- if (html_intersection_root ==
- html_intersection_root->owner_document()->document_element()) {
- root_bounds_without_margins = math::RectF(
- 0.0, 0.0,
- html_intersection_root->owner_document()->viewport_size().width(),
- html_intersection_root->owner_document()->viewport_size().height());
- } else if (IsOverflowCropped(html_intersection_root->computed_style())) {
- // If the intersection root has an overflow clip, it's the element's content
- // area.
- math::Vector2dF content_edge_offset =
- intersection_root_layout_boxes->GetContentEdgeOffset();
- root_bounds_without_margins =
- math::RectF(content_edge_offset.x(), content_edge_offset.y(),
- intersection_root_layout_boxes->GetContentEdgeWidth(),
- intersection_root_layout_boxes->GetContentEdgeHeight());
- } else {
- // Otherwise, it's the result of running the getBoundingClientRect()
- // algorithm on the intersection root.
- root_bounds_without_margins =
- math::RectF(html_intersection_root->GetBoundingClientRect()->rect());
- }
- int32 top_margin = GetUsedLengthOfRootMarginPropertyValue(
- root_margin_property_value->value()[0],
- root_bounds_without_margins.height());
- int32 right_margin = GetUsedLengthOfRootMarginPropertyValue(
- root_margin_property_value->value()[1],
- root_bounds_without_margins.width());
- int32 bottom_margin = GetUsedLengthOfRootMarginPropertyValue(
- root_margin_property_value->value()[2],
- root_bounds_without_margins.height());
- int32 left_margin = GetUsedLengthOfRootMarginPropertyValue(
- root_margin_property_value->value()[3],
- root_bounds_without_margins.width());
-
- // Remember to grow or shrink the root intersection rectangle bounds based
- // on the root margin property.
- scoped_refptr<DOMRectReadOnly> root_bounds = new DOMRectReadOnly(
- root_bounds_without_margins.x() - left_margin,
- root_bounds_without_margins.y() - top_margin,
- root_bounds_without_margins.width() + left_margin + right_margin,
- root_bounds_without_margins.height() + top_margin + bottom_margin);
- return root_bounds;
-}
-
-int32 IntersectionObserverTarget::GetUsedLengthOfRootMarginPropertyValue(
- const scoped_refptr<cssom::PropertyValue>& length_property_value,
- float percentage_base) {
- cssom::UsedLengthValueProvider<float> used_length_provider(percentage_base);
- length_property_value->Accept(&used_length_provider);
- // Not explicitly stated in web spec, but has been observed that Chrome
- // truncates root margin decimal values
- return static_cast<int32>(used_length_provider.used_length().value_or(0.0f));
-}
-
-scoped_refptr<DOMRectReadOnly>
-IntersectionObserverTarget::ComputeIntersectionBetweenTargetAndRoot(
- const scoped_refptr<HTMLElement>& html_intersection_root,
- const scoped_refptr<DOMRectReadOnly>& root_bounds,
- const scoped_refptr<DOMRectReadOnly>& target_rect,
- const scoped_refptr<HTMLElement>& html_target) {
- // https://www.w3.org/TR/intersection-observer/#calculate-intersection-rect-algo
- // To compute the intersection between a target and the observer's
- // intersection root, run these steps:
- // 1. Let intersectionRect be the result of running the
- // getBoundingClientRect() algorithm on the target.
- math::RectF intersection_rect = target_rect->rect();
-
- // 2. Let container be the containing block of the target.
- LayoutBoxes* target_layout_boxes = html_target->layout_boxes();
- DCHECK(target_layout_boxes);
- math::Vector2dF total_offset_from_containing_block =
- target_layout_boxes->GetBorderEdgeOffsetFromContainingBlock();
-
- HTMLElement* prev_container = html_target;
- HTMLElement* container = GetContainingBlockOfHTMLElement(prev_container);
-
- // 3. While container is not the intersection root:
- while (container != html_intersection_root) {
- // 1. Map intersectionRect to the coordinate space of container.
- intersection_rect.set_x(total_offset_from_containing_block.x());
- intersection_rect.set_y(total_offset_from_containing_block.y());
-
- // 2. If container has overflow clipping or a css clip-path property,
- // update intersectionRect by applying container's clip.
- // (Note: The containing block of an element with 'position: absolute'
- // is formed by the padding edge of the ancestor.
- // https://www.w3.org/TR/CSS2/visudet.html)
- LayoutBoxes* container_layout_boxes = container->layout_boxes();
- DCHECK(container_layout_boxes);
- if (IsOverflowCropped(container->computed_style())) {
- math::Vector2dF container_clip_dimensions =
- prev_container->computed_style()->position() ==
- cssom::KeywordValue::GetAbsolute()
- ? math::Vector2dF(container_layout_boxes->GetPaddingEdgeWidth(),
- container_layout_boxes->GetPaddingEdgeHeight())
- : math::Vector2dF(container_layout_boxes->GetContentEdgeWidth(),
- container_layout_boxes->GetContentEdgeHeight());
- math::RectF container_clip(0, 0, container_clip_dimensions.x(),
- container_clip_dimensions.y());
- intersection_rect =
- IntersectIntersectionObserverRects(intersection_rect, container_clip);
- }
-
- // 3. If container is the root element of a nested browsing context,
- // update container to be the browsing context container of container,
- // and update intersectionRect by clipping to the viewport of the nested
- // browsing context. Otherwise, update container to be the containing
- // block of container.
- // (Note: The containing block of an element with 'position: absolute'
- // is formed by the padding edge of the ancestor.
- // https://www.w3.org/TR/CSS2/visudet.html)
- math::Vector2dF next_offset_from_containing_block =
- prev_container->computed_style()->position() ==
- cssom::KeywordValue::GetAbsolute()
- ? container_layout_boxes->GetPaddingEdgeOffsetFromContainingBlock()
- : container_layout_boxes->GetContentEdgeOffsetFromContainingBlock();
- total_offset_from_containing_block += next_offset_from_containing_block;
-
- prev_container = container;
- container = GetContainingBlockOfHTMLElement(prev_container);
- }
-
- // Modification of steps 4-6:
- // Map intersectionRect to the coordinate space of the viewport of the
- // Document containing the target.
- // (Note: The containing block of an element with 'position: absolute'
- // is formed by the padding edge of the ancestor.
- // https://www.w3.org/TR/CSS2/visudet.html)
- LayoutBoxes* container_layout_boxes = container->layout_boxes();
- DCHECK(container_layout_boxes);
- math::Vector2dF containing_block_offset_from_origin =
- prev_container->computed_style()->position() ==
- cssom::KeywordValue::GetAbsolute()
- ? container_layout_boxes->GetPaddingEdgeOffset()
- : container_layout_boxes->GetContentEdgeOffset();
-
- intersection_rect.set_x(total_offset_from_containing_block.x() +
- containing_block_offset_from_origin.x());
- intersection_rect.set_y(total_offset_from_containing_block.y() +
- containing_block_offset_from_origin.y());
-
- // Update intersectionRect by intersecting it with the root intersection
- // rectangle, which is already in this coordinate space.
- intersection_rect = IntersectIntersectionObserverRects(intersection_rect,
- root_bounds->rect());
-
- return base::WrapRefCounted(new DOMRectReadOnly(intersection_rect));
-}
-
-math::RectF IntersectionObserverTarget::IntersectIntersectionObserverRects(
- const math::RectF& a, const math::RectF& b) {
- float rx = std::max(a.x(), b.x());
- float ry = std::max(a.y(), b.y());
- float rr = std::min(a.right(), b.right());
- float rb = std::min(a.bottom(), b.bottom());
-
- if (rx > rr || ry > rb) {
- return math::RectF(0.0f, 0.0f, 0.0f, 0.0f);
- }
-
- return math::RectF(rx, ry, rr - rx, rb - ry);
-}
-
-} // namespace dom
-} // namespace cobalt
diff --git a/src/cobalt/dom/intersection_observer_target.h b/src/cobalt/dom/intersection_observer_target.h
deleted file mode 100644
index 9ac0b4e..0000000
--- a/src/cobalt/dom/intersection_observer_target.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2019 The Cobalt Authors. All Rights Reserved.
-//
-// 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.
-
-#ifndef COBALT_DOM_INTERSECTION_OBSERVER_TARGET_H_
-#define COBALT_DOM_INTERSECTION_OBSERVER_TARGET_H_
-
-#include "cobalt/dom/intersection_observer_registration_list.h"
-#include "cobalt/math/rect_f.h"
-
-namespace cobalt {
-namespace dom {
-
-class Element;
-class HTMLElement;
-
-// The Intersection Observer spec describes a sequence of steps to update the
-// the target elements of an observer in step 2.2 of the "Run the Update
-// Intersection Observations Steps" algorithm. This helper class represents
-// one of those target elements.
-// https://www.w3.org/TR/intersection-observer/#update-intersection-observations-algo
-class IntersectionObserverTarget {
- public:
- explicit IntersectionObserverTarget(Element* target_element);
-
- void RegisterIntersectionObserver(
- const scoped_refptr<IntersectionObserver>& observer);
-
- void UnregisterIntersectionObserver(
- const scoped_refptr<IntersectionObserver>& observer);
-
- void UpdateIntersectionObservationsForTarget(
- const scoped_refptr<IntersectionObserver>& observer);
-
- private:
- scoped_refptr<DOMRectReadOnly> GetRootBounds(
- const scoped_refptr<HTMLElement>& html_intersection_root,
- scoped_refptr<cssom::PropertyListValue> root_margin_property_value);
-
- int32 GetUsedLengthOfRootMarginPropertyValue(
- const scoped_refptr<cssom::PropertyValue>& length_property_value,
- float percentage_base);
-
- scoped_refptr<DOMRectReadOnly> ComputeIntersectionBetweenTargetAndRoot(
- const scoped_refptr<HTMLElement>& intersection_root,
- const scoped_refptr<DOMRectReadOnly>& root_bounds,
- const scoped_refptr<DOMRectReadOnly>& target_rect,
- const scoped_refptr<HTMLElement>& html_target);
-
- // Similar to the IntersectRects function in math::RectF, but handles edge
- // adjacent intersections as valid intersections (instead of returning a
- // rectangle with zero dimensions)
- math::RectF IntersectIntersectionObserverRects(const math::RectF& a,
- const math::RectF& b);
-
- Element* target_element_;
-
- IntersectionObserverRegistrationList intersection_observer_registration_list_;
-};
-
-} // namespace dom
-} // namespace cobalt
-
-#endif // COBALT_DOM_INTERSECTION_OBSERVER_TARGET_H_
diff --git a/src/cobalt/dom/intersection_observer_task_manager.cc b/src/cobalt/dom/intersection_observer_task_manager.cc
index 4ce591b..c46c09d 100644
--- a/src/cobalt/dom/intersection_observer_task_manager.cc
+++ b/src/cobalt/dom/intersection_observer_task_manager.cc
@@ -71,23 +71,6 @@
base::Unretained(this)));
}
-void IntersectionObserverTaskManager::UpdateIntersectionObservations() {
- TRACE_EVENT0(
- "cobalt::dom",
- "IntersectionObserverTaskManager::UpdateIntersectionObservations()");
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
- // https://www.w3.org/TR/intersection-observer/#update-intersection-observations-algo
- // To run the update intersection observations steps for a Document document
- // given a timestamp time, run these steps: 1. Let observer list be a list of
- // all IntersectionObservers whose root is in the DOM tree of document.
- // 2. For each observer in observer list, run a set of subtasks (subtasks are
- // implemented in IntersectionObserver::UpdateObservationTargets):
- for (auto observer : observer_list_) {
- observer->UpdateObservationTargets();
- }
-}
-
void IntersectionObserverTaskManager::TraceMembers(script::Tracer* tracer) {
tracer->TraceItems(observer_list_);
}
diff --git a/src/cobalt/dom/intersection_observer_task_manager.h b/src/cobalt/dom/intersection_observer_task_manager.h
index 21b960f..5d78e9b 100644
--- a/src/cobalt/dom/intersection_observer_task_manager.h
+++ b/src/cobalt/dom/intersection_observer_task_manager.h
@@ -48,10 +48,6 @@
// posted.
void QueueIntersectionObserverTask();
- // Update intersection observer registrations for intersection observers whose
- // root is in the DOM tree of document
- void UpdateIntersectionObservations();
-
void TraceMembers(script::Tracer* tracer) override;
private:
diff --git a/src/cobalt/dom/layout_boxes.h b/src/cobalt/dom/layout_boxes.h
index 79fc8c3..69c160e 100644
--- a/src/cobalt/dom/layout_boxes.h
+++ b/src/cobalt/dom/layout_boxes.h
@@ -59,7 +59,6 @@
virtual float GetBorderEdgeTop() const = 0;
virtual float GetBorderEdgeWidth() const = 0;
virtual float GetBorderEdgeHeight() const = 0;
- virtual math::Vector2dF GetBorderEdgeOffsetFromContainingBlock() const = 0;
// Returns the border width (thickness) values.
virtual float GetBorderLeftWidth() const = 0;
@@ -75,14 +74,6 @@
virtual math::Vector2dF GetPaddingEdgeOffset() const = 0;
virtual float GetPaddingEdgeWidth() const = 0;
virtual float GetPaddingEdgeHeight() const = 0;
- virtual math::Vector2dF GetPaddingEdgeOffsetFromContainingBlock() const = 0;
-
- // Returns content edge values.
- // See https://www.w3.org/TR/CSS21/box.html#box-dimensions
- virtual math::Vector2dF GetContentEdgeOffset() const = 0;
- virtual float GetContentEdgeWidth() const = 0;
- virtual float GetContentEdgeHeight() const = 0;
- virtual math::Vector2dF GetContentEdgeOffsetFromContainingBlock() const = 0;
// Return scrolling area.
// See https://www.w3.org/TR/cssom-view-1/#scrolling-area
diff --git a/src/cobalt/dom/node.cc b/src/cobalt/dom/node.cc
index 8e6ed9d..c7f01b7 100644
--- a/src/cobalt/dom/node.cc
+++ b/src/cobalt/dom/node.cc
@@ -497,8 +497,8 @@
}
}
-void Node::MarkDisplayNoneOnNodeAndDescendants() {
- MarkDisplayNoneOnDescendants();
+void Node::MarkNotDisplayedOnNodeAndDescendants() {
+ MarkNotDisplayedOnDescendants();
}
void Node::PurgeCachedBackgroundImagesOfNodeAndDescendants() {
@@ -517,10 +517,10 @@
InvalidateLayoutBoxesOfDescendants();
}
-void Node::MarkDisplayNoneOnDescendants() {
+void Node::MarkNotDisplayedOnDescendants() {
Node* child = first_child_.get();
while (child) {
- child->MarkDisplayNoneOnNodeAndDescendants();
+ child->MarkNotDisplayedOnNodeAndDescendants();
child = child->next_sibling_.get();
}
}
@@ -772,6 +772,7 @@
bool was_inserted_to_document = node->inserted_into_document_;
if (was_inserted_to_document) {
node->OnRemovedFromDocument();
+ node->MarkNotDisplayedOnNodeAndDescendants();
}
// 1. 5. Not needed by Cobalt.
diff --git a/src/cobalt/dom/node.h b/src/cobalt/dom/node.h
index 3653d7c..3f6cd23 100644
--- a/src/cobalt/dom/node.h
+++ b/src/cobalt/dom/node.h
@@ -250,7 +250,7 @@
virtual bool IsInDocument() const { return inserted_into_document_; }
- virtual void MarkDisplayNoneOnNodeAndDescendants();
+ virtual void MarkNotDisplayedOnNodeAndDescendants();
virtual void PurgeCachedBackgroundImagesOfNodeAndDescendants();
virtual void InvalidateComputedStylesOfNodeAndDescendants();
virtual void InvalidateLayoutBoxesOfNodeAndAncestors();
@@ -260,7 +260,7 @@
virtual void InvalidateLayoutBoxCrossReferences() {}
virtual void InvalidateLayoutBoxRenderTreeNodes() {}
- void MarkDisplayNoneOnDescendants();
+ void MarkNotDisplayedOnDescendants();
void PurgeCachedBackgroundImagesOfDescendants();
void InvalidateComputedStylesOfDescendants();
void InvalidateLayoutBoxesOfAncestors();
diff --git a/src/cobalt/layout/box.cc b/src/cobalt/layout/box.cc
index 521051f..403fc1a 100644
--- a/src/cobalt/layout/box.cc
+++ b/src/cobalt/layout/box.cc
@@ -706,6 +706,11 @@
UpdateUiNavigationItem();
}
+ // Update intersection observers for any targets represented by this box.
+ if (box_intersection_observer_module_) {
+ box_intersection_observer_module_->UpdateIntersectionObservations();
+ }
+
// The painting order is:
// - background color.
// - background image.
@@ -2102,5 +2107,30 @@
return true;
}
+void Box::AddIntersectionObserverRootsAndTargets(
+ BoxIntersectionObserverModule::IntersectionObserverRootVector&& roots,
+ BoxIntersectionObserverModule::IntersectionObserverTargetVector&& targets) {
+ if (!box_intersection_observer_module_) {
+ box_intersection_observer_module_ =
+ std::unique_ptr<BoxIntersectionObserverModule>(
+ new BoxIntersectionObserverModule(this));
+ }
+
+ box_intersection_observer_module_->AddIntersectionObserverRoots(
+ std::move(roots));
+ box_intersection_observer_module_->AddIntersectionObserverTargets(
+ std::move(targets));
+}
+
+bool Box::ContainsIntersectionObserverRoot(
+ const scoped_refptr<IntersectionObserverRoot>& intersection_observer_root)
+ const {
+ if (box_intersection_observer_module_) {
+ return box_intersection_observer_module_
+ ->BoxContainsIntersectionObserverRoot(intersection_observer_root);
+ }
+ return false;
+}
+
} // namespace layout
} // namespace cobalt
diff --git a/src/cobalt/layout/box.h b/src/cobalt/layout/box.h
index 2368108..596b2b4 100644
--- a/src/cobalt/layout/box.h
+++ b/src/cobalt/layout/box.h
@@ -26,6 +26,7 @@
#include "cobalt/cssom/css_style_declaration.h"
#include "cobalt/dom/node.h"
#include "cobalt/layout/base_direction.h"
+#include "cobalt/layout/box_intersection_observer_module.h"
#include "cobalt/layout/insets_layout_unit.h"
#include "cobalt/layout/layout_stat_tracker.h"
#include "cobalt/layout/layout_unit.h"
@@ -643,6 +644,14 @@
ui_nav_item_ = item;
}
+ void AddIntersectionObserverRootsAndTargets(
+ BoxIntersectionObserverModule::IntersectionObserverRootVector&& roots,
+ BoxIntersectionObserverModule::IntersectionObserverTargetVector&&
+ targets);
+ bool ContainsIntersectionObserverRoot(
+ const scoped_refptr<IntersectionObserverRoot>& intersection_observer_root)
+ const;
+
protected:
UsedStyleProvider* used_style_provider() const {
return used_style_provider_;
@@ -927,6 +936,9 @@
// UI navigation items are used to help animate certain elements.
scoped_refptr<ui_navigation::NavItem> ui_nav_item_;
+ std::unique_ptr<BoxIntersectionObserverModule>
+ box_intersection_observer_module_;
+
// For write access to parent/containing_block members.
friend class ContainerBox;
friend class LayoutBoxes;
diff --git a/src/cobalt/layout/box_generator.cc b/src/cobalt/layout/box_generator.cc
index 2b85645..b9fe273 100644
--- a/src/cobalt/layout/box_generator.cc
+++ b/src/cobalt/layout/box_generator.cc
@@ -990,6 +990,13 @@
container_box_before_split->SetUiNavItem(html_element->GetUiNavItem());
boxes_.push_back(container_box_before_split);
+ BoxIntersectionObserverModule::IntersectionObserverRootVector roots =
+ html_element->GetLayoutIntersectionObserverRoots();
+ BoxIntersectionObserverModule::IntersectionObserverTargetVector targets =
+ html_element->GetLayoutIntersectionObserverTargets();
+ container_box_before_split->AddIntersectionObserverRootsAndTargets(
+ std::move(roots), std::move(targets));
+
AppendPseudoElementToLine(html_element, dom::kBeforePseudoElementType);
// Generate child boxes.
diff --git a/src/cobalt/layout/box_intersection_observer_module.cc b/src/cobalt/layout/box_intersection_observer_module.cc
new file mode 100644
index 0000000..d09d3b6
--- /dev/null
+++ b/src/cobalt/layout/box_intersection_observer_module.cc
@@ -0,0 +1,58 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/layout/box_intersection_observer_module.h"
+
+#include "cobalt/layout/box.h"
+
+namespace cobalt {
+namespace layout {
+
+BoxIntersectionObserverModule::BoxIntersectionObserverModule(Box* box)
+ : box_(box) {}
+
+void BoxIntersectionObserverModule::AddIntersectionObserverRoots(
+ IntersectionObserverRootVector&& roots) {
+ intersection_observer_roots_ = std::move(roots);
+}
+
+void BoxIntersectionObserverModule::AddIntersectionObserverTargets(
+ IntersectionObserverTargetVector&& targets) {
+ intersection_observer_targets_ = std::move(targets);
+}
+
+bool BoxIntersectionObserverModule::BoxContainsIntersectionObserverRoot(
+ const scoped_refptr<IntersectionObserverRoot>& intersection_observer_root)
+ const {
+ for (auto it = intersection_observer_roots_.begin();
+ it != intersection_observer_roots_.end(); ++it) {
+ if (*it == intersection_observer_root) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void BoxIntersectionObserverModule::UpdateIntersectionObservations() {
+ ContainerBox* container_box = box_->AsContainerBox();
+ if (!container_box) {
+ return;
+ }
+ for (const auto& target : intersection_observer_targets_) {
+ target->UpdateIntersectionObservationsForTarget(container_box);
+ }
+}
+
+} // namespace layout
+} // namespace cobalt
diff --git a/src/cobalt/layout/box_intersection_observer_module.h b/src/cobalt/layout/box_intersection_observer_module.h
new file mode 100644
index 0000000..f8668fa
--- /dev/null
+++ b/src/cobalt/layout/box_intersection_observer_module.h
@@ -0,0 +1,58 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef COBALT_LAYOUT_BOX_INTERSECTION_OBSERVER_MODULE_H_
+#define COBALT_LAYOUT_BOX_INTERSECTION_OBSERVER_MODULE_H_
+
+#include <vector>
+
+#include "cobalt/layout/intersection_observer_root.h"
+#include "cobalt/layout/intersection_observer_target.h"
+
+namespace cobalt {
+namespace layout {
+
+class Box;
+
+// This helper class groups the methods and data related to the intersection
+// root and target elements produced by a particular box.
+class BoxIntersectionObserverModule {
+ public:
+ typedef std::vector<scoped_refptr<IntersectionObserverRoot>>
+ IntersectionObserverRootVector;
+ typedef std::vector<scoped_refptr<IntersectionObserverTarget>>
+ IntersectionObserverTargetVector;
+
+ explicit BoxIntersectionObserverModule(Box* box);
+ ~BoxIntersectionObserverModule() {}
+
+ void AddIntersectionObserverRoots(IntersectionObserverRootVector&& roots);
+ void AddIntersectionObserverTargets(
+ IntersectionObserverTargetVector&& targets);
+ bool BoxContainsIntersectionObserverRoot(
+ const scoped_refptr<IntersectionObserverRoot>& intersection_observer_root)
+ const;
+ void UpdateIntersectionObservations();
+
+ private:
+ Box* box_;
+
+ IntersectionObserverRootVector intersection_observer_roots_;
+ IntersectionObserverTargetVector intersection_observer_targets_;
+};
+
+} // namespace layout
+} // namespace cobalt
+
+#endif // COBALT_LAYOUT_BOX_INTERSECTION_OBSERVER_MODULE_H_
diff --git a/src/cobalt/layout/intersection_observer_root.h b/src/cobalt/layout/intersection_observer_root.h
new file mode 100644
index 0000000..b7b6447
--- /dev/null
+++ b/src/cobalt/layout/intersection_observer_root.h
@@ -0,0 +1,59 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef COBALT_LAYOUT_INTERSECTION_OBSERVER_ROOT_H_
+#define COBALT_LAYOUT_INTERSECTION_OBSERVER_ROOT_H_
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "cobalt/cssom/property_list_value.h"
+
+namespace cobalt {
+namespace layout {
+
+class Box;
+
+// An IntersectionObserverRoot holds information associated with the W3
+// IntersectionObserver object, such as rootMargin and thresholds.
+// IntersectionObserverTarget objects reference these objects, instead of the
+// other way around.
+class IntersectionObserverRoot
+ : public base::RefCountedThreadSafe<IntersectionObserverRoot> {
+ public:
+ IntersectionObserverRoot(
+ const scoped_refptr<cssom::PropertyListValue>& root_margin_property_value,
+ std::vector<double> thresholds_vector)
+ : root_margin_property_value_(root_margin_property_value),
+ thresholds_vector_(thresholds_vector) {}
+
+ ~IntersectionObserverRoot() {}
+
+ const scoped_refptr<cssom::PropertyListValue>& root_margin_property_value()
+ const {
+ return root_margin_property_value_;
+ }
+
+ std::vector<double> thresholds_vector() const { return thresholds_vector_; }
+
+ private:
+ // Properties associated with the IntersectionObserver object.
+ scoped_refptr<cssom::PropertyListValue> root_margin_property_value_;
+ std::vector<double> thresholds_vector_;
+};
+
+} // namespace layout
+} // namespace cobalt
+
+#endif // COBALT_LAYOUT_INTERSECTION_OBSERVER_ROOT_H_
diff --git a/src/cobalt/layout/intersection_observer_target.cc b/src/cobalt/layout/intersection_observer_target.cc
new file mode 100644
index 0000000..19fd041
--- /dev/null
+++ b/src/cobalt/layout/intersection_observer_target.cc
@@ -0,0 +1,276 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/layout/intersection_observer_target.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "cobalt/cssom/computed_style_utils.h"
+#include "cobalt/cssom/keyword_value.h"
+#include "cobalt/layout/box.h"
+#include "cobalt/layout/container_box.h"
+#include "cobalt/layout/intersection_observer_root.h"
+#include "cobalt/layout/used_style.h"
+
+namespace cobalt {
+namespace layout {
+
+void IntersectionObserverTarget::UpdateIntersectionObservationsForTarget(
+ ContainerBox* target_box) {
+ // Walk up the containing block chain looking for the box referencing the
+ // IntersectionObserverRoot corresponding to this IntersectionObserverTarget.
+ // Skip further processing for the target if it is not a descendant of the
+ // root in the containing block chain.
+ const ContainerBox* root_box = target_box->GetContainingBlock();
+ while (!root_box->ContainsIntersectionObserverRoot(
+ intersection_observer_root_)) {
+ if (!root_box->parent()) {
+ return;
+ }
+ root_box = root_box->GetContainingBlock();
+ }
+
+ // Let targetRect be target's bounding border box.
+ RectLayoutUnit target_transformed_border_box(
+ target_box->GetTransformedBorderBoxFromRoot());
+ math::RectF target_rect =
+ math::RectF(target_transformed_border_box.x().toFloat(),
+ target_transformed_border_box.y().toFloat(),
+ target_transformed_border_box.width().toFloat(),
+ target_transformed_border_box.height().toFloat());
+
+ // Let intersectionRect be the result of running the compute the intersection
+ // algorithm on target.
+ math::RectF root_bounds = GetRootBounds(
+ root_box, intersection_observer_root_->root_margin_property_value());
+ math::RectF intersection_rect = ComputeIntersectionBetweenTargetAndRoot(
+ root_box, root_bounds, target_rect, target_box);
+
+ // Let targetArea be targetRect's area.
+ float target_area = target_rect.size().GetArea();
+
+ // Let intersectionArea be intersectionRect's area.
+ float intersection_area = intersection_rect.size().GetArea();
+
+ // Let isIntersecting be true if targetRect and rootBounds intersect or are
+ // edge-adjacent, even if the intersection has zero area (because rootBounds
+ // or targetRect have zero area); otherwise, let isIntersecting be false.
+ bool is_intersecting =
+ intersection_rect.width() != 0 || intersection_rect.height() != 0;
+
+ // If targetArea is non-zero, let intersectionRatio be intersectionArea
+ // divided by targetArea. Otherwise, let intersectionRatio be 1 if
+ // isIntersecting is true, or 0 if isIntersecting is false.
+ float intersection_ratio = is_intersecting ? 1.0f : 0.0f;
+ if (target_area != 0) {
+ intersection_ratio = intersection_area / target_area;
+ }
+
+ // Let thresholdIndex be the index of the first entry in observer.thresholds
+ // whose value is greater than intersectionRatio, or the length of
+ // observer.thresholds if intersectionRatio is greater than or equal to the
+ // last entry in observer.thresholds.
+ const std::vector<double>& thresholds =
+ intersection_observer_root_->thresholds_vector();
+ size_t threshold_index;
+ for (threshold_index = 0; threshold_index < thresholds.size();
+ ++threshold_index) {
+ if (thresholds.at(threshold_index) > intersection_ratio) {
+ break;
+ }
+ }
+
+ // If thresholdIndex does not equal previousThresholdIndex or if
+ // isIntersecting does not equal previousIsIntersecting, queue an
+ // IntersectionObserverEntry, passing in observer, time, rootBounds,
+ // boundingClientRect, intersectionRect, isIntersecting, and target.
+ if (static_cast<int32>(threshold_index) != previous_threshold_index_ ||
+ is_intersecting != previous_is_intersecting_) {
+ on_intersection_callback_.Run(root_bounds, target_rect, intersection_rect,
+ is_intersecting, intersection_ratio);
+ }
+
+ // Update the previousThresholdIndex and previousIsIntersecting properties.
+ previous_threshold_index_ = static_cast<int32>(threshold_index);
+ previous_is_intersecting_ = is_intersecting;
+}
+
+bool IntersectionObserverTarget::IsInContainingBlockChain(
+ const ContainerBox* potential_containing_block,
+ const ContainerBox* target_box) {
+ const ContainerBox* containing_block = target_box->GetContainingBlock();
+ while (containing_block != potential_containing_block) {
+ if (!containing_block->parent()) {
+ return false;
+ }
+ containing_block = containing_block->GetContainingBlock();
+ }
+ return true;
+}
+
+math::RectF IntersectionObserverTarget::GetRootBounds(
+ const ContainerBox* root_box,
+ scoped_refptr<cssom::PropertyListValue> root_margin_property_value) {
+ math::RectF root_bounds_without_margins;
+ if (IsOverflowCropped(root_box->computed_style())) {
+ // If the intersection root has an overflow clip, it's the element's content
+ // area.
+ Vector2dLayoutUnit content_edge_offset =
+ root_box->GetContentBoxOffsetFromRoot(false /*transform_forms_root*/);
+ root_bounds_without_margins = math::RectF(
+ content_edge_offset.x().toFloat(), content_edge_offset.y().toFloat(),
+ root_box->width().toFloat(), root_box->height().toFloat());
+ } else {
+ // Otherwise, it's the result of running the getBoundingClientRect()
+ // algorithm on the intersection root.
+ RectLayoutUnit root_transformed_border_box(
+ root_box->GetTransformedBorderBoxFromRoot());
+ root_bounds_without_margins =
+ math::RectF(root_transformed_border_box.x().toFloat(),
+ root_transformed_border_box.y().toFloat(),
+ root_transformed_border_box.width().toFloat(),
+ root_transformed_border_box.height().toFloat());
+ }
+ int32 top_margin = GetUsedLengthOfRootMarginPropertyValue(
+ root_margin_property_value->value()[0],
+ LayoutUnit(root_bounds_without_margins.height()));
+ int32 right_margin = GetUsedLengthOfRootMarginPropertyValue(
+ root_margin_property_value->value()[1],
+ LayoutUnit(root_bounds_without_margins.width()));
+ int32 bottom_margin = GetUsedLengthOfRootMarginPropertyValue(
+ root_margin_property_value->value()[2],
+ LayoutUnit(root_bounds_without_margins.height()));
+ int32 left_margin = GetUsedLengthOfRootMarginPropertyValue(
+ root_margin_property_value->value()[3],
+ LayoutUnit(root_bounds_without_margins.width()));
+
+ // Remember to grow or shrink the root intersection rectangle bounds based
+ // on the root margin property.
+ math::RectF root_bounds = math::RectF(
+ root_bounds_without_margins.x() - left_margin,
+ root_bounds_without_margins.y() - top_margin,
+ root_bounds_without_margins.width() + left_margin + right_margin,
+ root_bounds_without_margins.height() + top_margin + bottom_margin);
+ return root_bounds;
+}
+
+int32 IntersectionObserverTarget::GetUsedLengthOfRootMarginPropertyValue(
+ const scoped_refptr<cssom::PropertyValue>& length_property_value,
+ LayoutUnit percentage_base) {
+ UsedLengthValueProvider used_length_provider(percentage_base);
+ length_property_value->Accept(&used_length_provider);
+ // Not explicitly stated in web spec, but has been observed that Chrome
+ // truncates root margin decimal values.
+ return static_cast<int32>(
+ used_length_provider.used_length().value_or(LayoutUnit(0.0f)).toFloat());
+}
+
+math::RectF IntersectionObserverTarget::ComputeIntersectionBetweenTargetAndRoot(
+ const ContainerBox* root_box, const math::RectF& root_bounds,
+ const math::RectF& target_rect, const ContainerBox* target_box) {
+ // Let intersectionRect be target's bounding border box.
+ math::RectF intersection_rect = target_rect;
+
+ // Let container be the containing block of the target.
+ math::Vector2dF total_offset_from_containing_block =
+ target_box->GetBorderBoxOffsetFromContainingBlock();
+ const ContainerBox* prev_container = target_box;
+ const ContainerBox* container = prev_container->GetContainingBlock();
+
+ // While container is not the intersection root:
+ while (container != root_box) {
+ // Map intersectionRect to the coordinate space of container.
+ intersection_rect.set_x(total_offset_from_containing_block.x());
+ intersection_rect.set_y(total_offset_from_containing_block.y());
+
+ // If container has overflow clipping or a css clip-path property, update
+ // intersectionRect by applying container's clip. (Note: The containing
+ // block of an element with 'position: absolute' is formed by the padding
+ // edge of the ancestor. https://www.w3.org/TR/CSS2/visudet.html)
+ if (IsOverflowCropped(container->computed_style())) {
+ Vector2dLayoutUnit container_clip_dimensions =
+ prev_container->computed_style()->position() ==
+ cssom::KeywordValue::GetAbsolute()
+ ? Vector2dLayoutUnit(container->GetPaddingBoxWidth(),
+ container->GetPaddingBoxHeight())
+ : Vector2dLayoutUnit(container->width(), container->height());
+ math::RectF container_clip(0.0f, 0.0f,
+ container_clip_dimensions.x().toFloat(),
+ container_clip_dimensions.y().toFloat());
+ intersection_rect =
+ IntersectIntersectionObserverRects(intersection_rect, container_clip);
+ }
+
+ // If container is the root element of a nested browsing context, update
+ // container to be the browsing context container of container, and update
+ // intersectionRect by clipping to the viewport of the nested browsing
+ // context. Otherwise, update container to be the containing block of
+ // container. (Note: The containing block of an element with 'position:
+ // absolute' is formed by the padding edge of the ancestor.
+ // https://www.w3.org/TR/CSS2/visudet.html)
+ math::Vector2dF next_offset_from_containing_block =
+ prev_container->computed_style()->position() ==
+ cssom::KeywordValue::GetAbsolute()
+ ? container->GetPaddingBoxOffsetFromContainingBlock()
+ : container->GetContentBoxOffsetFromContainingBlockContentBox(
+ container->GetContainingBlock());
+ total_offset_from_containing_block += next_offset_from_containing_block;
+
+ prev_container = container;
+ container = prev_container->GetContainingBlock();
+ }
+
+ // Map intersectionRect to the coordinate space of the viewport of the
+ // Document containing the target.
+ // (Note: The containing block of an element with 'position: absolute'
+ // is formed by the padding edge of the ancestor.
+ // https://www.w3.org/TR/CSS2/visudet.html)
+ math::Vector2dF containing_block_offset_from_origin =
+ prev_container->computed_style()->position() ==
+ cssom::KeywordValue::GetAbsolute() &&
+ !IsOverflowCropped(container->computed_style())
+ ? container->GetPaddingBoxOffsetFromRoot(
+ false /*transform_forms_root*/)
+ : container->GetContentBoxOffsetFromRoot(
+ false /*transform_forms_root*/);
+
+ intersection_rect.set_x(total_offset_from_containing_block.x() +
+ containing_block_offset_from_origin.x());
+ intersection_rect.set_y(total_offset_from_containing_block.y() +
+ containing_block_offset_from_origin.y());
+
+ // Update intersectionRect by intersecting it with the root intersection
+ // rectangle, which is already in this coordinate space.
+ intersection_rect =
+ IntersectIntersectionObserverRects(intersection_rect, root_bounds);
+ return intersection_rect;
+}
+
+math::RectF IntersectionObserverTarget::IntersectIntersectionObserverRects(
+ const math::RectF& a, const math::RectF& b) {
+ float rx = std::max(a.x(), b.x());
+ float ry = std::max(a.y(), b.y());
+ float rr = std::min(a.right(), b.right());
+ float rb = std::min(a.bottom(), b.bottom());
+
+ if (rx > rr || ry > rb) {
+ return math::RectF(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+
+ return math::RectF(rx, ry, rr - rx, rb - ry);
+}
+
+} // namespace layout
+} // namespace cobalt
diff --git a/src/cobalt/layout/intersection_observer_target.h b/src/cobalt/layout/intersection_observer_target.h
new file mode 100644
index 0000000..a40d41d
--- /dev/null
+++ b/src/cobalt/layout/intersection_observer_target.h
@@ -0,0 +1,118 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef COBALT_LAYOUT_INTERSECTION_OBSERVER_TARGET_H_
+#define COBALT_LAYOUT_INTERSECTION_OBSERVER_TARGET_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "cobalt/cssom/property_list_value.h"
+#include "cobalt/layout/layout_unit.h"
+#include "cobalt/math/rect_f.h"
+
+namespace cobalt {
+namespace layout {
+
+class Box;
+class ContainerBox;
+class IntersectionObserverRoot;
+
+// A IntersectionObserverTarget roughly maps to |target| in a call to observe()
+// (https://www.w3.org/TR/intersection-observer/#dom-intersectionobserver-observe).
+// In lieu of having IntersectionObserverRegistration records, these objects can
+// keep track of the |previousThresholdIndex| and |previousIsIntersecting|
+// properties that determine whether IntersectionObserver objects need to be
+// notified of changes
+// (https://www.w3.org/TR/intersection-observer/#intersectionobserverregistration).
+// An IntersectionObserverTarget references the IntersectionObserverRoot that it
+// it associated with, not the other way around.
+class IntersectionObserverTarget
+ : public base::RefCountedThreadSafe<IntersectionObserverTarget> {
+ public:
+ // Callback that runs when an intersection change is observed, that goes back
+ // into DOM logic to notify the intersection observers.
+ typedef base::Callback<void(math::RectF root_bounds, math::RectF target_rect,
+ math::RectF intersection_rect,
+ bool is_intersecting, float intersection_ratio)>
+ OnIntersectionCallback;
+
+ IntersectionObserverTarget(
+ const OnIntersectionCallback& on_intersection_callback,
+ scoped_refptr<IntersectionObserverRoot> intersection_observer_root)
+ : on_intersection_callback_(on_intersection_callback),
+ intersection_observer_root_(intersection_observer_root),
+ previous_threshold_index_(-1),
+ previous_is_intersecting_(false) {}
+
+ ~IntersectionObserverTarget() {}
+
+ // The Intersection Observer spec describes a sequence of steps to update the
+ // target element of an observer in step 2.2 of the "Run the Update
+ // Intersection Observation Steps" algorithm.
+ // This function follows the algorithm in the web spec, with a few notable
+ // modifications: (1) All computations occur with respect to objects in the
+ // box tree, not the dom tree. (2) This class already keeps track of the
+ // previousThresholdIndex and previousIsIntersecting fields, so no
+ // intersection observer registration objects are used to determine whether
+ // IntersectionObserver objects need to be notified of a change.
+ // https://www.w3.org/TR/intersection-observer/#update-intersection-observations-algo
+ void UpdateIntersectionObservationsForTarget(ContainerBox* target_box);
+
+ scoped_refptr<IntersectionObserverRoot> intersection_observer_root() {
+ return intersection_observer_root_;
+ }
+
+ private:
+ // Walk up the containing block chain, as described in
+ // http://www.w3.org/TR/CSS2/visudet.html#containing-block-details
+ bool IsInContainingBlockChain(const ContainerBox* potential_containing_block,
+ const ContainerBox* target_box);
+
+ int32 GetUsedLengthOfRootMarginPropertyValue(
+ const scoped_refptr<cssom::PropertyValue>& length_property_value,
+ LayoutUnit percentage_base);
+
+ // Rules for determining the root intersection rectangle bounds.
+ // https://www.w3.org/TR/intersection-observer/#intersectionobserver-root-intersection-rectangle
+ math::RectF GetRootBounds(
+ const ContainerBox* root_box,
+ scoped_refptr<cssom::PropertyListValue> root_margin_property_value);
+
+ // Compute the intersection between a target and the observer's intersection
+ // root.
+ // https://www.w3.org/TR/intersection-observer/#calculate-intersection-rect-algo
+ math::RectF ComputeIntersectionBetweenTargetAndRoot(
+ const ContainerBox* root_box, const math::RectF& root_bounds,
+ const math::RectF& target_rect, const ContainerBox* target_box);
+
+ // Similar to the IntersectRects function in math::RectF, but handles edge
+ // adjacent intersections as valid intersections (instead of returning a
+ // rectangle with zero dimensions)
+ math::RectF IntersectIntersectionObserverRects(const math::RectF& a,
+ const math::RectF& b);
+
+ OnIntersectionCallback on_intersection_callback_;
+
+ scoped_refptr<IntersectionObserverRoot> intersection_observer_root_;
+
+ int32 previous_threshold_index_;
+
+ bool previous_is_intersecting_;
+};
+
+} // namespace layout
+} // namespace cobalt
+
+#endif // COBALT_LAYOUT_INTERSECTION_OBSERVER_TARGET_H_
diff --git a/src/cobalt/layout/layout.cc b/src/cobalt/layout/layout.cc
index bcaaebf..b298940 100644
--- a/src/cobalt/layout/layout.cc
+++ b/src/cobalt/layout/layout.cc
@@ -93,6 +93,18 @@
LayoutStatTracker::kStopWatchTypeBoxGeneration,
base::StopWatch::kAutoStartOn, layout_stat_tracker);
+ // If the implicit root is a root for any observers, the initial containing
+ // block should reference the corresponding IntersectionObserverRoots.
+ dom::HTMLElement* html_element =
+ document->document_element()->AsHTMLElement();
+ BoxIntersectionObserverModule::IntersectionObserverRootVector roots =
+ html_element->GetLayoutIntersectionObserverRoots();
+ BoxIntersectionObserverModule::IntersectionObserverTargetVector targets =
+ html_element->GetLayoutIntersectionObserverTargets();
+ (*initial_containing_block)
+ ->AddIntersectionObserverRootsAndTargets(std::move(roots),
+ std::move(targets));
+
ScopedParagraph scoped_paragraph(
new Paragraph(locale, (*initial_containing_block)->base_direction(),
Paragraph::DirectionalEmbeddingStack(),
diff --git a/src/cobalt/layout/layout.gyp b/src/cobalt/layout/layout.gyp
index 30b1717..884553b 100644
--- a/src/cobalt/layout/layout.gyp
+++ b/src/cobalt/layout/layout.gyp
@@ -38,6 +38,8 @@
'box.h',
'box_generator.cc',
'box_generator.h',
+ 'box_intersection_observer_module.cc',
+ 'box_intersection_observer_module.h',
'container_box.cc',
'container_box.h',
'flex_container_box.cc',
@@ -61,6 +63,9 @@
'inline_level_replaced_box.h',
'insets_layout_unit.cc',
'insets_layout_unit.h',
+ 'intersection_observer_root.h',
+ 'intersection_observer_target.cc',
+ 'intersection_observer_target.h',
'layout.cc',
'layout.h',
'layout_unit.h',
diff --git a/src/cobalt/layout/layout_boxes.cc b/src/cobalt/layout/layout_boxes.cc
index b459474..da333da 100644
--- a/src/cobalt/layout/layout_boxes.cc
+++ b/src/cobalt/layout/layout_boxes.cc
@@ -89,11 +89,6 @@
return GetBoundingBorderRectangle().height();
}
-math::Vector2dF LayoutBoxes::GetBorderEdgeOffsetFromContainingBlock() const {
- DCHECK(!boxes_.empty());
- return boxes_.front()->GetBorderBoxOffsetFromContainingBlock();
-}
-
float LayoutBoxes::GetBorderLeftWidth() const {
DCHECK(!boxes_.empty());
return boxes_.front()->border_left_width().toFloat();
@@ -130,33 +125,6 @@
return boxes_.front()->GetPaddingBoxHeight().toFloat();
}
-math::Vector2dF LayoutBoxes::GetPaddingEdgeOffsetFromContainingBlock() const {
- DCHECK(!boxes_.empty());
- return boxes_.front()->GetPaddingBoxOffsetFromContainingBlock();
-}
-
-math::Vector2dF LayoutBoxes::GetContentEdgeOffset() const {
- DCHECK(!boxes_.empty());
- return boxes_.front()->GetContentBoxOffsetFromRoot(
- false /*transform_forms_root*/);
-}
-
-float LayoutBoxes::GetContentEdgeWidth() const {
- DCHECK(!boxes_.empty());
- return boxes_.front()->width().toFloat();
-}
-
-float LayoutBoxes::GetContentEdgeHeight() const {
- DCHECK(!boxes_.empty());
- return boxes_.front()->height().toFloat();
-}
-
-math::Vector2dF LayoutBoxes::GetContentEdgeOffsetFromContainingBlock() const {
- DCHECK(!boxes_.empty());
- return boxes_.front()->GetContentBoxOffsetFromContainingBlockContentBox(
- boxes_.front()->GetContainingBlock());
-}
-
math::RectF LayoutBoxes::GetScrollArea(dom::Directionality dir) const {
// https://www.w3.org/TR/cssom-view-1/#scrolling-area
// For rightward and downward:
diff --git a/src/cobalt/layout/layout_boxes.h b/src/cobalt/layout/layout_boxes.h
index 81114a1..0e838c0 100644
--- a/src/cobalt/layout/layout_boxes.h
+++ b/src/cobalt/layout/layout_boxes.h
@@ -45,7 +45,6 @@
float GetBorderEdgeTop() const override;
float GetBorderEdgeWidth() const override;
float GetBorderEdgeHeight() const override;
- math::Vector2dF GetBorderEdgeOffsetFromContainingBlock() const override;
float GetBorderLeftWidth() const override;
float GetBorderTopWidth() const override;
@@ -56,12 +55,6 @@
math::Vector2dF GetPaddingEdgeOffset() const override;
float GetPaddingEdgeWidth() const override;
float GetPaddingEdgeHeight() const override;
- math::Vector2dF GetPaddingEdgeOffsetFromContainingBlock() const override;
-
- math::Vector2dF GetContentEdgeOffset() const override;
- float GetContentEdgeWidth() const override;
- float GetContentEdgeHeight() const override;
- math::Vector2dF GetContentEdgeOffsetFromContainingBlock() const override;
math::RectF GetScrollArea(dom::Directionality dir) const override;
diff --git a/src/cobalt/layout/layout_manager.cc b/src/cobalt/layout/layout_manager.cc
index c571f16..a913178 100644
--- a/src/cobalt/layout/layout_manager.cc
+++ b/src/cobalt/layout/layout_manager.cc
@@ -428,11 +428,6 @@
is_render_tree_pending_ = false;
}
- // Run the Update Intersection Observation Steps
- // https://www.w3.org/TR/intersection-observer/#update-intersection-observations-algo
- document->intersection_observer_task_manager()
- ->UpdateIntersectionObservations();
-
TRACE_EVENT_END0("cobalt::layout", kBenchmarkStatLayout);
}
diff --git a/src/cobalt/layout/used_style.cc b/src/cobalt/layout/used_style.cc
index a38110e..7a811f7 100644
--- a/src/cobalt/layout/used_style.cc
+++ b/src/cobalt/layout/used_style.cc
@@ -23,7 +23,6 @@
#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/cssom/absolute_url_value.h"
-#include "cobalt/cssom/calc_value.h"
#include "cobalt/cssom/font_style_value.h"
#include "cobalt/cssom/font_weight_value.h"
#include "cobalt/cssom/keyword_value.h"
@@ -38,7 +37,6 @@
#include "cobalt/cssom/string_value.h"
#include "cobalt/cssom/transform_function_visitor.h"
#include "cobalt/cssom/translate_function.h"
-#include "cobalt/cssom/used_style.h"
#include "cobalt/loader/mesh/mesh_cache.h"
#include "cobalt/math/transform_2d.h"
#include "cobalt/render_tree/animations/animate_node.h"
@@ -53,8 +51,6 @@
namespace {
-typedef cssom::UsedLengthValueProvider<LayoutUnit> UsedLengthValueProvider;
-
struct BackgroundImageTransformData {
BackgroundImageTransformData(
const math::SizeF& image_node_size,
diff --git a/src/cobalt/layout/used_style.h b/src/cobalt/layout/used_style.h
index 07c543e..6aede9f 100644
--- a/src/cobalt/layout/used_style.h
+++ b/src/cobalt/layout/used_style.h
@@ -15,6 +15,7 @@
#ifndef COBALT_LAYOUT_USED_STYLE_H_
#define COBALT_LAYOUT_USED_STYLE_H_
+#include "cobalt/cssom/calc_value.h"
#include "cobalt/cssom/css_computed_style_data.h"
#include "cobalt/cssom/keyword_value.h"
#include "cobalt/cssom/linear_gradient_value.h"
@@ -282,6 +283,50 @@
DISALLOW_COPY_AND_ASSIGN(UsedBorderRadiusProvider);
};
+class UsedLengthValueProvider : public cssom::NotReachedPropertyValueVisitor {
+ public:
+ explicit UsedLengthValueProvider(LayoutUnit percentage_base,
+ bool calc_permitted = false)
+ : percentage_base_(percentage_base), calc_permitted_(calc_permitted) {}
+
+ void VisitLength(cssom::LengthValue* length) override {
+ depends_on_containing_block_ = false;
+
+ DCHECK_EQ(cssom::kPixelsUnit, length->unit());
+ used_length_ = LayoutUnit(length->value());
+ }
+
+ void VisitPercentage(cssom::PercentageValue* percentage) override {
+ depends_on_containing_block_ = true;
+ used_length_ = percentage->value() * percentage_base_;
+ }
+
+ void VisitCalc(cssom::CalcValue* calc) override {
+ if (!calc_permitted_) {
+ NOTREACHED();
+ }
+ depends_on_containing_block_ = true;
+ used_length_ = LayoutUnit(calc->length_value()->value()) +
+ calc->percentage_value()->value() * percentage_base_;
+ }
+
+ bool depends_on_containing_block() const {
+ return depends_on_containing_block_;
+ }
+ const base::Optional<LayoutUnit>& used_length() const { return used_length_; }
+
+ protected:
+ bool depends_on_containing_block_;
+
+ private:
+ const LayoutUnit percentage_base_;
+ const bool calc_permitted_;
+
+ base::Optional<LayoutUnit> used_length_;
+
+ DISALLOW_COPY_AND_ASSIGN(UsedLengthValueProvider);
+};
+
class UsedLineHeightProvider : public cssom::NotReachedPropertyValueVisitor {
public:
explicit UsedLineHeightProvider(
diff --git a/src/cobalt/layout_tests/testdata/css3-transitions/3-transition-not-started-on-reattach-expected.png b/src/cobalt/layout_tests/testdata/css3-transitions/3-transition-not-started-on-reattach-expected.png
new file mode 100644
index 0000000..e7821e6
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-transitions/3-transition-not-started-on-reattach-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-transitions/3-transition-not-started-on-reattach.html b/src/cobalt/layout_tests/testdata/css3-transitions/3-transition-not-started-on-reattach.html
new file mode 100644
index 0000000..df8f7c0
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-transitions/3-transition-not-started-on-reattach.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+<!--
+ | Verify that the transition is not started when an element is removed then
+ | reattached to the DOM.
+ -->
+<head>
+ <style>
+ body {
+ background-color: #000000;
+ }
+
+ div {
+ width: 100px;
+ height: 100px;
+ background-color: #FF0000;
+ transition: background-color 5s;
+ }
+ </style>
+ <script>
+ if (window.testRunner) {
+ window.testRunner.waitUntilDone();
+ }
+
+ window.onload = function() {
+ var frame = 0;
+ var e = document.getElementById("animated");
+
+ function requestAnimationFrame(callback) {
+ window.requestAnimationFrame(callback);
+ if (window.testRunner) {
+ window.testRunner.DoNonMeasuredLayout();
+ }
+ }
+
+ function frameCallback() {
+ switch(++frame) {
+ case 1:
+ case 2:
+ requestAnimationFrame(frameCallback);
+ break;
+ case 3:
+ document.body.removeChild(e);
+ requestAnimationFrame(frameCallback);
+ break;
+ case 4:
+ requestAnimationFrame(frameCallback);
+ break;
+ case 5:
+ // Should not trigger a transition; color should change immediately.
+ e.style.backgroundColor = "#0000FF";
+ document.body.appendChild(e);
+ requestAnimationFrame(frameCallback);
+ break;
+ case 6:
+ requestAnimationFrame(frameCallback);
+ break;
+ case 7:
+ if (window.testRunner) {
+ window.testRunner.notifyDone();
+ }
+ break;
+ }
+ }
+
+ // Trigger initial transition.
+ e.style.backgroundColor = "#00FF00";
+ frameCallback();
+ }
+ </script>
+</head>
+<body>
+ <div id="animated"></div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-transitions/layout_tests.txt b/src/cobalt/layout_tests/testdata/css3-transitions/layout_tests.txt
index 3aa4d83..9313518 100644
--- a/src/cobalt/layout_tests/testdata/css3-transitions/layout_tests.txt
+++ b/src/cobalt/layout_tests/testdata/css3-transitions/layout_tests.txt
@@ -6,6 +6,7 @@
2-transition-start-during-display-none-does-not-transition
2-transition-start-during-display-none-does-not-transition-from-ancestor
2-transition-started-on-display-none-pseudoelement-does-not-dcheck
+3-transition-not-started-on-reattach
5-multiple-transitions-should-fire-in-correct-order
5-simple-transition
5-simple-transition-for-pseudoelement
diff --git a/src/cobalt/layout_tests/testdata/intersection-observer/layout_tests.txt b/src/cobalt/layout_tests/testdata/intersection-observer/layout_tests.txt
index 1c4329b..8962d98 100644
--- a/src/cobalt/layout_tests/testdata/intersection-observer/layout_tests.txt
+++ b/src/cobalt/layout_tests/testdata/intersection-observer/layout_tests.txt
@@ -2,6 +2,7 @@
element-in-containing-block-chain-has-overflow-clip-without-padding-or-border
multiple-observers-with-different-roots-and-targets
no-intersection-when-root-is-not-in-containing-block-chain-of-target
+observers-should-update-when-elements-move
previous-threshold-index-and-is-intersecting-fields-should-be-updated
root-has-nonzero-padding-and-border
root-has-nonzero-padding-and-border-and-overflow-clip
@@ -11,3 +12,4 @@
target-has-nonzero-padding-and-border
target-with-nonzero-area-is-edge-adjacent-to-root
target-with-zero-area-is-edge-adjacent-to-root
+unobserved-targets-do-not-get-included-in-next-update
diff --git a/src/cobalt/layout_tests/testdata/intersection-observer/observers-should-update-when-elements-move-expected.png b/src/cobalt/layout_tests/testdata/intersection-observer/observers-should-update-when-elements-move-expected.png
new file mode 100644
index 0000000..7b242a2
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/intersection-observer/observers-should-update-when-elements-move-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/intersection-observer/observers-should-update-when-elements-move.html b/src/cobalt/layout_tests/testdata/intersection-observer/observers-should-update-when-elements-move.html
new file mode 100644
index 0000000..eb74022
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/intersection-observer/observers-should-update-when-elements-move.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<!--
+ | This test checks that the observer objects get updated when the elements
+ | themselves move around.
+ | The color of the target element is blue if the intersection ratio is above
+ | the threshold, and green if it is below. In this test, the intersection ratio
+ | crosses the threshold when the target element moves; the target element
+ | should initially be blue but end up green.
+ | https://www.w3.org/TR/intersection-observer/
+ -->
+<html>
+<head>
+ <style>
+ div {
+ position: absolute;
+ }
+ #root {
+ margin: 100px;
+ background-color: red;
+ width: 250px;
+ height: 150px;
+ }
+ #target {
+ width: 150px;
+ height: 50px;
+ top: 50px;
+ left: 50px;
+ }
+ </style>
+</head>
+<body>
+ <div id="root">
+ <div id="target"></div>
+ </div>
+
+ <script>
+ if (window.testRunner) {
+ window.testRunner.waitUntilDone();
+ }
+
+ window.addEventListener("load", function() {
+ var rootElement = document.querySelector('#root');
+ var targetElement = document.querySelector('#target');
+
+ function handleIntersect(entries, observer) {
+ entries.forEach(function(entry) {
+ if (entry.intersectionRatio > 0.5) {
+ entry.target.style.backgroundColor = "blue";
+ } else {
+ entry.target.style.backgroundColor = "green";
+ }
+ });
+ }
+
+ var options = {
+ root: rootElement,
+ rootMargin: "0px",
+ threshold: 0.5
+ };
+
+ var observer = new IntersectionObserver(handleIntersect, options);
+ observer.observe(targetElement);
+
+ if (window.testRunner) {
+ window.testRunner.DoNonMeasuredLayout();
+ }
+
+ // Move the target element so that the intersection ratio now crosses
+ // the threshold value. An intersection observer update should be
+ // triggered and the callback should run.
+ targetElement.style.top = "-30px";
+
+ if (window.testRunner) {
+ window.testRunner.DoNonMeasuredLayout();
+ window.setTimeout(function() { window.testRunner.notifyDone(); }, 0);
+ }
+ });
+ </script>
+
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/intersection-observer/root-has-nonzero-padding-and-border-and-overflow-clip.html b/src/cobalt/layout_tests/testdata/intersection-observer/root-has-nonzero-padding-and-border-and-overflow-clip.html
index d3362a4..2966803 100644
--- a/src/cobalt/layout_tests/testdata/intersection-observer/root-has-nonzero-padding-and-border-and-overflow-clip.html
+++ b/src/cobalt/layout_tests/testdata/intersection-observer/root-has-nonzero-padding-and-border-and-overflow-clip.html
@@ -28,7 +28,7 @@
position: absolute;
}
#target {
- background-color: rgba(0, 128, 0, 255);
+ background-color: rgba(0, 128, 0, 0);
width: 200px;
height: 200px;
}
diff --git a/src/cobalt/layout_tests/testdata/intersection-observer/root-has-nonzero-root-margin.html b/src/cobalt/layout_tests/testdata/intersection-observer/root-has-nonzero-root-margin.html
index 1617161..12cd034 100644
--- a/src/cobalt/layout_tests/testdata/intersection-observer/root-has-nonzero-root-margin.html
+++ b/src/cobalt/layout_tests/testdata/intersection-observer/root-has-nonzero-root-margin.html
@@ -18,7 +18,7 @@
height: 150px;
}
#target {
- background-color: rgba(0, 128, 0, 255);
+ background-color: rgba(0, 128, 0, 0);
width: 150px;
height: 250px;
margin: 50px 150px;
diff --git a/src/cobalt/layout_tests/testdata/intersection-observer/unobserved-targets-do-not-get-included-in-next-update-expected.png b/src/cobalt/layout_tests/testdata/intersection-observer/unobserved-targets-do-not-get-included-in-next-update-expected.png
new file mode 100644
index 0000000..1015b8b
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/intersection-observer/unobserved-targets-do-not-get-included-in-next-update-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/intersection-observer/unobserved-targets-do-not-get-included-in-next-update.html b/src/cobalt/layout_tests/testdata/intersection-observer/unobserved-targets-do-not-get-included-in-next-update.html
new file mode 100644
index 0000000..e23d332
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/intersection-observer/unobserved-targets-do-not-get-included-in-next-update.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<!--
+ | This test checks that the observers no longer check the intersections
+ | for targets that have been unobserved.
+ | Observed targets become green if they intersect with the root (i.e. are
+ | visible on the screen). Unobserved targets do not change color.
+ | https://www.w3.org/TR/intersection-observer/
+ -->
+<html>
+<head>
+ <style>
+ div {
+ background-color: yellow;
+ width: 50px;
+ height: 100px;
+ margin: 25px;
+ display: inline-block;
+ }
+ </style>
+</head>
+<body>
+ <div id="firsttarget"></div>
+ <div id="secondtarget"></div>
+ <div id="thirdtarget"></div>
+ <div id="fourthtarget"></div>
+ <div id="fifthtarget"></div>
+
+ <script>
+ if (window.testRunner) {
+ window.testRunner.waitUntilDone();
+ }
+
+ window.addEventListener("load", function() {
+
+ function handleIntersect(entries, observer) {
+ entries.forEach(function(entry) {
+ if (entry.isIntersecting) {
+ entry.target.style.backgroundColor = "green";
+ }
+ });
+ }
+
+ function createObserverAndUnobserveTargets() {
+ var firstTargetElement = document.querySelector('#firsttarget');
+ var secondTargetElement = document.querySelector('#secondtarget');
+ var thirdTargetElement = document.querySelector('#thirdtarget');
+ var fourthTargetElement = document.querySelector('#fourthtarget');
+ var fifthTargetElement = document.querySelector('#fifthtarget');
+
+ var options = {
+ root: null,
+ rootMargin: "0px",
+ threshold: 0.0
+ };
+
+ // Create observer and observe elements.
+ var observer = new IntersectionObserver(handleIntersect, options);
+ observer.observe(firstTargetElement);
+ observer.observe(secondTargetElement);
+ observer.observe(thirdTargetElement);
+ observer.observe(fourthTargetElement);
+ observer.observe(fifthTargetElement);
+
+ // Unobserve some of these targets. When the observer checks for
+ // intersections, these elements should not be included.
+ observer.unobserve(secondTargetElement);
+ observer.unobserve(fourthTargetElement);
+ observer.unobserve(fifthTargetElement);
+ }
+
+ createObserverAndUnobserveTargets();
+
+ if (window.testRunner) {
+ window.testRunner.DoNonMeasuredLayout();
+ window.setTimeout(function() { window.testRunner.notifyDone(); }, 0);
+ }
+ });
+ </script>
+
+</body>
+</html>
diff --git a/src/cobalt/network/url_request_context.cc b/src/cobalt/network/url_request_context.cc
index 5c20925..850eade 100644
--- a/src/cobalt/network/url_request_context.cc
+++ b/src/cobalt/network/url_request_context.cc
@@ -153,9 +153,6 @@
storage_.set_job_factory(
std::unique_ptr<net::URLRequestJobFactory>(job_factory));
- if (!net::GetGlobalCertNetFetcher()) {
- net::SetGlobalCertNetFetcher(net::CreateCertNetFetcher(this));
- }
}
URLRequestContext::~URLRequestContext() {}
diff --git a/src/cobalt/site/docs/development/setup-raspi.md b/src/cobalt/site/docs/development/setup-raspi.md
index da7cc94..50faeb9 100644
--- a/src/cobalt/site/docs/development/setup-raspi.md
+++ b/src/cobalt/site/docs/development/setup-raspi.md
@@ -23,6 +23,18 @@
Raspbian.
</aside>
+Cobalt assumes the Raspberry Pi is configured to use non-default thread
+schedulers and priorities. Ensure that **/etc/security/limits.conf** sets
+**rtprio** and **nice** limits for the user. For example, if the user is **pi**,
+then limits.conf should have the following lines:
+
+```
+@pi hard rtprio 99
+@pi soft rtprio 99
+@pi hard nice -20
+@pi soft nice -20
+```
+
The following commands update the package configuration on your Raspberry Pi
so that Cobalt can run properly:
@@ -63,7 +75,7 @@
1. Run `mkdir -p $RASPI_HOME/sysroot`
1. Run:
- ```
+ ```
rsync -avzh --safe-links \
--delete-after pi@$RASPI_ADDR:/{opt,lib,usr} \
--exclude="lib/firmware" --exclude="lib/modules" \
diff --git a/src/cobalt/speech/google_speech_service.cc b/src/cobalt/speech/google_speech_service.cc
index f3dec39..550b541 100644
--- a/src/cobalt/speech/google_speech_service.cc
+++ b/src/cobalt/speech/google_speech_service.cc
@@ -35,7 +35,6 @@
#include "cobalt/base/language.h"
#include "cobalt/loader/fetcher_factory.h"
#include "cobalt/network/network_module.h"
-#include "cobalt/speech/google_streaming_api.pb.h"
#include "cobalt/speech/microphone.h"
#include "cobalt/speech/speech_configuration.h"
#include "cobalt/speech/speech_recognition_error.h"
@@ -85,7 +84,9 @@
}
SpeechRecognitionResultList::SpeechRecognitionResults
-ProcessProtoSuccessResults(const proto::SpeechRecognitionEvent& event) {
+ProcessProtoSuccessResults(proto::SpeechRecognitionEvent event) {
+ // This method handles wrappables and should run on the MainWebModule thread.
+
DCHECK_EQ(event.status(), proto::SpeechRecognitionEvent::STATUS_SUCCESS);
SpeechRecognitionResultList::SpeechRecognitionResults results;
@@ -117,8 +118,9 @@
// TODO: Feed error messages when creating SpeechRecognitionError.
void ProcessAndFireErrorEvent(
- const proto::SpeechRecognitionEvent& event,
- const GoogleSpeechService::EventCallback& event_callback) {
+ proto::SpeechRecognitionEvent event,
+ GoogleSpeechService::EventCallback event_callback) {
+ // This method handles wrappables and should run on the MainWebModule thread.
scoped_refptr<dom::Event> error_event;
switch (event.status()) {
case proto::SpeechRecognitionEvent::STATUS_SUCCESS:
@@ -162,6 +164,12 @@
event_callback.Run(error_event);
}
+void HandleNetworkResponseFailure(
+ const GoogleSpeechService::EventCallback& event_callback) {
+ event_callback.Run(new SpeechRecognitionError(
+ kSpeechRecognitionErrorCodeNetwork, "Network response failure."));
+}
+
bool IsResponseCodeSuccess(int response_code) {
// NetFetcher only considers success to be if the network request
// was successful *and* we get a 2xx response back.
@@ -181,7 +189,11 @@
started_(false),
event_callback_(event_callback),
fetcher_creator_(fetcher_creator),
- thread_("speech_recognizer") {
+ thread_("speech_recognizer"),
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ weak_this_(weak_ptr_factory_.GetWeakPtr())),
+ wrappables_task_runner_(base::MessageLoop::current()->task_runner()) {
thread_.StartWithOptions(
base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
}
@@ -240,14 +252,20 @@
}
if (event.status() == proto::SpeechRecognitionEvent::STATUS_SUCCESS) {
- ProcessAndFireSuccessEvent(ProcessProtoSuccessResults(event));
+ wrappables_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&GoogleSpeechService::ProcessAndFireSuccessEvent,
+ weak_this_, event));
} else {
- ProcessAndFireErrorEvent(event, event_callback_);
+ wrappables_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ProcessAndFireErrorEvent, event, event_callback_));
}
}
} else {
- event_callback_.Run(new SpeechRecognitionError(
- kSpeechRecognitionErrorCodeNetwork, "Network response failure."));
+ wrappables_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&HandleNetworkResponseFailure, event_callback_));
}
}
}
@@ -358,12 +376,19 @@
downstream_fetcher_.reset();
encoder_.reset();
- // Clear the final results.
- final_results_.clear();
+ wrappables_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&GoogleSpeechService::ClearFinalResults, weak_this_));
// Clear any remaining audio data.
chunked_byte_buffer_.Clear();
}
+void GoogleSpeechService::ClearFinalResults() {
+ // This method handles wrappables and should run on the MainWebModule thread.
+ DCHECK(wrappables_task_runner_->BelongsToCurrentThread());
+ final_results_.clear();
+}
+
void GoogleSpeechService::UploadAudioDataInternal(
std::unique_ptr<ShellAudioBus> audio_bus, bool is_last_chunk) {
DCHECK_EQ(thread_.message_loop(), base::MessageLoop::current());
@@ -384,8 +409,11 @@
}
void GoogleSpeechService::ProcessAndFireSuccessEvent(
- const SpeechRecognitionResults& new_results) {
- DCHECK_EQ(thread_.message_loop(), base::MessageLoop::current());
+ proto::SpeechRecognitionEvent event) {
+ // This method handles wrappables and should run on the MainWebModule thread.
+ DCHECK(wrappables_task_runner_->BelongsToCurrentThread());
+
+ SpeechRecognitionResults new_results = ProcessProtoSuccessResults(event);
SpeechRecognitionResults success_results;
size_t total_size = final_results_.size() + new_results.size();
diff --git a/src/cobalt/speech/google_speech_service.h b/src/cobalt/speech/google_speech_service.h
index b6779cb..20179c6 100644
--- a/src/cobalt/speech/google_speech_service.h
+++ b/src/cobalt/speech/google_speech_service.h
@@ -24,6 +24,7 @@
#include "cobalt/media/base/shell_audio_bus.h"
#include "cobalt/network/network_module.h"
#include "cobalt/speech/audio_encoder_flac.h"
+#include "cobalt/speech/google_streaming_api.pb.h"
#include "cobalt/speech/speech_recognition_config.h"
#include "cobalt/speech/speech_recognition_event.h"
#include "content/browser/speech/chunked_byte_buffer.h"
@@ -78,9 +79,12 @@
private:
void StartInternal(const SpeechRecognitionConfig& config, int sample_rate);
void StopInternal();
+ // This method handles wrappables and should run on the MainWebModule thread.
+ void ClearFinalResults();
void UploadAudioDataInternal(std::unique_ptr<ShellAudioBus> audio_bus,
bool is_last_chunk);
- void ProcessAndFireSuccessEvent(const SpeechRecognitionResults& new_results);
+ // This method handles wrappables, and so it must run on the MainWebModule.
+ void ProcessAndFireSuccessEvent(proto::SpeechRecognitionEvent event);
// This is used for creating fetchers.
network::NetworkModule* network_module_;
@@ -105,6 +109,11 @@
base::Thread thread_;
// Stores fetched response.
CobaltURLFetcherStringWriter* download_data_writer_ = nullptr;
+
+ // Use a task runner to deal with all wrappables.
+ base::WeakPtrFactory<GoogleSpeechService> weak_ptr_factory_;
+ base::WeakPtr<GoogleSpeechService> weak_this_;
+ scoped_refptr<base::SingleThreadTaskRunner> const wrappables_task_runner_;
};
} // namespace speech
diff --git a/src/net/cert/cert_verify_proc.cc b/src/net/cert/cert_verify_proc.cc
index 7f30d04..5b23772 100644
--- a/src/net/cert/cert_verify_proc.cc
+++ b/src/net/cert/cert_verify_proc.cc
@@ -48,10 +48,8 @@
#elif defined(OS_WIN)
#include "base/win/windows_version.h"
#include "net/cert/cert_verify_proc_win.h"
-#elif defined(OS_FUCHSIA)
+#elif defined(OS_FUCHSIA) || defined(STARBOARD)
#include "net/cert/cert_verify_proc_builtin.h"
-#elif defined(STARBOARD)
-#include "net/cert/cert_verify_proc_openssl.h"
#else
#error Implement certificate verification.
#endif
@@ -480,10 +478,8 @@
return new CertVerifyProcMac();
#elif defined(OS_WIN)
return new CertVerifyProcWin();
-#elif defined(OS_FUCHSIA)
+#elif defined(OS_FUCHSIA) || defined(STARBOARD)
return CreateCertVerifyProcBuiltin();
-#elif defined(STARBOARD)
- return new CertVerifyProcOpenSSL();
#else
#error Unsupported platform
#endif
diff --git a/src/net/cert/cert_verify_proc_builtin.cc b/src/net/cert/cert_verify_proc_builtin.cc
index 9345b47..5129c90 100644
--- a/src/net/cert/cert_verify_proc_builtin.cc
+++ b/src/net/cert/cert_verify_proc_builtin.cc
@@ -454,6 +454,8 @@
// |input_cert|.
path_builder.AddCertIssuerSource(intermediates);
+// Cobalt does not need AIA fetching.
+#if !defined(STARBOARD)
// Allow the path builder to discover intermediates through AIA fetching.
std::unique_ptr<CertIssuerSourceAia> aia_cert_issuer_source;
if (net_fetcher) {
@@ -462,6 +464,7 @@
} else {
LOG(ERROR) << "No net_fetcher for performing AIA chasing.";
}
+#endif
path_builder.Run();
}
@@ -481,6 +484,13 @@
// builder should always return some partial path (even if just containing
// the target), then there is a CertErrors to test.
verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
+#if defined(STARBOARD)
+ // Cobalt only trusts root certificates that come with the binary,
+ // If the code reaches this point, it usually means the root certificate
+ // of the chain is not found in the content directory of trusted
+ // certificates.
+ DLOG(ERROR) << "Certificate Authority invalid!";
+#endif
return ERR_CERT_AUTHORITY_INVALID;
}
@@ -597,7 +607,13 @@
}
// Get the global dependencies.
+#if defined(STARBOARD)
+ // cert net fetcher is used for fetching AIA certs which Cobalt should not
+ // need.
+ CertNetFetcher* net_fetcher = nullptr;
+#else
CertNetFetcher* net_fetcher = GetGlobalCertNetFetcher();
+#endif
const EVRootCAMetadata* ev_metadata = EVRootCAMetadata::GetInstance();
// This boolean tracks whether online revocation checking was performed for
diff --git a/src/net/cert/cert_verify_proc_openssl.cc b/src/net/cert/cert_verify_proc_openssl.cc
index a2520e7..e69de29 100644
--- a/src/net/cert/cert_verify_proc_openssl.cc
+++ b/src/net/cert/cert_verify_proc_openssl.cc
@@ -1,378 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/cert/cert_verify_proc_openssl.h"
-
-#include "third_party/boringssl/src/include/openssl/mem.h"
-#include "third_party/boringssl/src/include/openssl/ssl.h"
-#include "third_party/boringssl/src/include/openssl/x509_vfy.h"
-#include "third_party/boringssl/src/include/openssl/x509v3.h"
-
-#include <string>
-#include <vector>
-
-#include "base/base_paths.h"
-#include "base/logging.h"
-#include "base/memory/singleton.h"
-#include "base/path_service.h"
-#include "base/sha1.h"
-#include "crypto/openssl_util.h"
-#include "crypto/sha2.h"
-#include "net/base/net_errors.h"
-#include "net/cert/asn1_util.h"
-#include "net/cert/cert_status_flags.h"
-#include "net/cert/cert_verifier.h"
-#include "net/cert/cert_verify_result.h"
-#include "net/cert/x509_certificate.h"
-#include "net/cert/x509_util.h"
-
-namespace net {
-
-namespace {
-
-// Maps X509_STORE_CTX_get_error() return values to our cert status flags.
-CertStatus MapCertErrorToCertStatus(int err) {
- switch (err) {
- case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
- return CERT_STATUS_COMMON_NAME_INVALID;
- case X509_V_ERR_CERT_NOT_YET_VALID:
- case X509_V_ERR_CERT_HAS_EXPIRED:
- case X509_V_ERR_CRL_NOT_YET_VALID:
- case X509_V_ERR_CRL_HAS_EXPIRED:
- case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
- case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
- case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
- case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
- return CERT_STATUS_DATE_INVALID;
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
- case X509_V_ERR_UNABLE_TO_GET_CRL:
- case X509_V_ERR_INVALID_CA:
- case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
- case X509_V_ERR_INVALID_NON_CA:
- case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
- case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
- return CERT_STATUS_AUTHORITY_INVALID;
-#if 0
-// TODO(bulach): what should we map to these status?
- return CERT_STATUS_NO_REVOCATION_MECHANISM;
- return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
-#endif
- case X509_V_ERR_CERT_REVOKED:
- return CERT_STATUS_REVOKED;
- // All these status are mapped to CERT_STATUS_INVALID.
- case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
- case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
- case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
- case X509_V_ERR_CERT_SIGNATURE_FAILURE:
- case X509_V_ERR_CRL_SIGNATURE_FAILURE:
- case X509_V_ERR_OUT_OF_MEM:
- case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
- case X509_V_ERR_CERT_CHAIN_TOO_LONG:
- case X509_V_ERR_PATH_LENGTH_EXCEEDED:
- case X509_V_ERR_INVALID_PURPOSE:
- case X509_V_ERR_CERT_UNTRUSTED:
- case X509_V_ERR_CERT_REJECTED:
- case X509_V_ERR_AKID_SKID_MISMATCH:
- case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
- case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
- case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
- case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN:
- case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION:
- case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED:
- case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE:
- case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED:
- case X509_V_ERR_INVALID_EXTENSION:
- case X509_V_ERR_INVALID_POLICY_EXTENSION:
- case X509_V_ERR_NO_EXPLICIT_POLICY:
- case X509_V_ERR_UNNESTED_RESOURCE:
- case X509_V_ERR_APPLICATION_VERIFICATION:
- return CERT_STATUS_INVALID;
- default:
- NOTREACHED() << "Invalid X509 err " << err;
- return CERT_STATUS_INVALID;
- }
-}
-
-template <typename T, void (*destructor)(T*)>
-class ScopedOpenSSL {
- public:
- ScopedOpenSSL() : ptr_(NULL) {}
- explicit ScopedOpenSSL(T* ptr) : ptr_(ptr) {}
- ~ScopedOpenSSL() { reset(NULL); }
-
- T* get() const { return ptr_; }
- void reset(T* ptr) {
- if (ptr != ptr_) {
- if (ptr_)
- (*destructor)(ptr_);
- ptr_ = ptr;
- }
- }
-
- private:
- T* ptr_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedOpenSSL);
-};
-
-// x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised
-// contents of |x509|.
-static bssl::UniquePtr<CRYPTO_BUFFER> x509_to_buffer(X509* x509) {
- uint8_t* buf = NULL;
- int cert_len = i2d_X509(x509, &buf);
- if (cert_len <= 0) {
- return 0;
- }
-
- bssl::UniquePtr<CRYPTO_BUFFER> buffer(CRYPTO_BUFFER_new(buf, cert_len, NULL));
- OPENSSL_free(buf);
-
- return buffer;
-}
-
-struct DERCache {
- unsigned char* data;
- int data_length;
-};
-
-void DERCache_free(void* parent,
- void* ptr,
- CRYPTO_EX_DATA* ad,
- int idx,
- long argl,
- void* argp) {
- DERCache* der_cache = static_cast<DERCache*>(ptr);
- if (!der_cache)
- return;
- if (der_cache->data)
- OPENSSL_free(der_cache->data);
- OPENSSL_free(der_cache);
-}
-
-class X509InitSingleton {
- public:
- static X509InitSingleton* GetInstance() {
- // We allow the X509 store to leak, because it is used from a non-joinable
- // worker that is not stopped on shutdown, hence may still be using
- // OpenSSL library after the AtExit runner has completed.
- return base::Singleton<X509InitSingleton, base::LeakySingletonTraits<
- X509InitSingleton>>::get();
- }
- int der_cache_ex_index() const { return der_cache_ex_index_; }
- X509_STORE* store() const { return store_.get(); }
-
- X509InitSingleton() {
- crypto::EnsureOpenSSLInit();
- der_cache_ex_index_ = X509_get_ex_new_index(0, 0, 0, 0, DERCache_free);
- DCHECK_NE(der_cache_ex_index_, -1);
- ResetCertStore();
- }
-
- void ResetCertStore() {
- store_.reset(X509_STORE_new());
- DCHECK(store_.get());
- // Configure the SSL certs dir. We don't implement getenv() or hardcode
- // the SSL_CERTS_DIR, which are the default methods OpenSSL uses to find
- // the certs path.
- base::FilePath cert_path;
- base::PathService::Get(base::DIR_EXE, &cert_path);
- cert_path = cert_path.Append("ssl").Append("certs");
- X509_STORE_load_locations(store_.get(), NULL, cert_path.value().c_str());
- }
-
- private:
- int der_cache_ex_index_;
- ScopedOpenSSL<X509_STORE, X509_STORE_free> store_;
-
- DISALLOW_COPY_AND_ASSIGN(X509InitSingleton);
-};
-
-// Takes ownership of |data| (which must have been allocated by OpenSSL).
-DERCache* SetDERCache(X509* cert,
- int x509_der_cache_index,
- unsigned char* data,
- int data_length) {
- DERCache* internal_cache =
- static_cast<DERCache*>(OPENSSL_malloc(sizeof(*internal_cache)));
- if (!internal_cache) {
- // We took ownership of |data|, so we must free if we can't add it to
- // |cert|.
- OPENSSL_free(data);
- return NULL;
- }
- internal_cache->data = data;
- internal_cache->data_length = data_length;
- X509_set_ex_data(cert, x509_der_cache_index, internal_cache);
- return internal_cache;
-}
-
-// Returns true if |der_cache| points to valid data, false otherwise.
-// (note: the DER-encoded data in |der_cache| is owned by |cert|, callers should
-// not free it).
-bool GetDERAndCacheIfNeeded(X509* cert, DERCache* der_cache) {
- int x509_der_cache_index =
- X509InitSingleton::GetInstance()->der_cache_ex_index();
-
- // Re-encoding the DER data via i2d_X509 is an expensive operation, but it's
- // necessary for comparing two certificates. We re-encode at most once per
- // certificate and cache the data within the X509 cert using X509_set_ex_data.
- DERCache* internal_cache =
- static_cast<DERCache*>(X509_get_ex_data(cert, x509_der_cache_index));
- if (!internal_cache) {
- unsigned char* data = NULL;
- int data_length = i2d_X509(cert, &data);
- if (data_length <= 0 || !data)
- return false;
- internal_cache = SetDERCache(cert, x509_der_cache_index, data, data_length);
- if (!internal_cache)
- return false;
- }
- *der_cache = *internal_cache;
- return true;
-}
-
-// sk_X509_free is a function-style macro, so can't be used as a template
-// param directly.
-void sk_X509_free_fn(STACK_OF(X509) * st) {
- sk_X509_pop_free(st, X509_free);
-}
-
-void GetCertChainInfo(X509_STORE_CTX* store_ctx,
- CertVerifyResult* verify_result) {
- STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(store_ctx);
- bssl::UniquePtr<CRYPTO_BUFFER> verified_cert = NULL;
- std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> verified_chain;
- for (int i = 0; i < sk_X509_num(chain); ++i) {
- X509* cert = sk_X509_value(chain, i);
- auto DER_buffer = x509_to_buffer(cert);
- auto x509_cert =
- x509_util::CreateCryptoBuffer(CRYPTO_BUFFER_data(DER_buffer.get()),
- CRYPTO_BUFFER_len(DER_buffer.get()));
- if (i == 0) {
- verified_cert = std::move(x509_cert);
- } else {
- verified_chain.push_back(std::move(x509_cert));
- }
-
- // Only check the algorithm status for certificates that are not in the
- // trust store.
- if (i < store_ctx->last_untrusted) {
- int sig_alg = OBJ_obj2nid(cert->sig_alg->algorithm);
- if (sig_alg == NID_md2WithRSAEncryption) {
- verify_result->has_md2 = true;
- } else if (sig_alg == NID_md4WithRSAEncryption) {
- verify_result->has_md4 = true;
- } else if (sig_alg == NID_md5WithRSAEncryption) {
- verify_result->has_md5 = true;
- } else if (sig_alg == NID_sha1WithRSAEncryption) {
- verify_result->has_sha1 = true;
- }
- }
- }
-
- if (verified_cert) {
- verify_result->verified_cert = X509Certificate::CreateFromBuffer(
- std::move(verified_cert), std::move(verified_chain));
- }
-}
-
-void AppendPublicKeyHashes(X509_STORE_CTX* store_ctx, HashValueVector* hashes) {
- STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(store_ctx);
- for (int i = 0; i < sk_X509_num(chain); ++i) {
- X509* cert = sk_X509_value(chain, i);
-
- DERCache der_cache;
- if (!GetDERAndCacheIfNeeded(cert, &der_cache))
- continue;
- std::string der_data;
- der_data.assign(reinterpret_cast<const char*>(der_cache.data),
- der_cache.data_length);
-
- base::StringPiece der_bytes(der_data);
- base::StringPiece spki_bytes;
- if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes))
- continue;
-
- HashValue sha256(HASH_VALUE_SHA256);
- crypto::SHA256HashString(spki_bytes, sha256.data(), crypto::kSHA256Length);
- hashes->push_back(sha256);
- }
-}
-
-} // namespace
-
-CertVerifyProcOpenSSL::CertVerifyProcOpenSSL() {}
-
-CertVerifyProcOpenSSL::~CertVerifyProcOpenSSL() {}
-
-int CertVerifyProcOpenSSL::VerifyInternal(
- X509Certificate* cert,
- const std::string& hostname,
- const std::string& /*ocsp_response*/,
- int flags,
- CRLSet* crl_set,
- const CertificateList& /*additional_trust_anchors*/,
- CertVerifyResult* verify_result) {
- crypto::EnsureOpenSSLInit();
-
- if (!cert->VerifyNameMatch(hostname))
- verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
-
- ScopedOpenSSL<X509_STORE_CTX, X509_STORE_CTX_free> ctx(X509_STORE_CTX_new());
-
- ScopedOpenSSL<STACK_OF(X509), sk_X509_free_fn> intermediates(
- sk_X509_new_null());
- if (!intermediates.get()) {
- return ERR_OUT_OF_MEMORY;
- }
-
- const auto& cert_current_intermediates = cert->intermediate_buffers();
- for (auto it = cert_current_intermediates.begin();
- it != cert_current_intermediates.end(); ++it) {
- X509* x509_intermediate = X509_parse_from_buffer(it->get());
- if (!sk_X509_push(intermediates.get(), x509_intermediate)) {
- return ERR_OUT_OF_MEMORY;
- }
- }
-
- ScopedOpenSSL<X509, X509_free> cert_in_x509;
- cert_in_x509.reset(X509_parse_from_buffer(cert->cert_buffer()));
- if (X509_STORE_CTX_init(ctx.get(), X509InitSingleton::GetInstance()->store(),
- cert_in_x509.get(), intermediates.get()) != 1) {
- NOTREACHED();
- return ERR_FAILED;
- }
-
- if (X509_verify_cert(ctx.get()) != 1) {
- int x509_error = X509_STORE_CTX_get_error(ctx.get());
- // TODO[johnx]: replace this with net's map function.
- CertStatus cert_status = MapCertErrorToCertStatus(x509_error);
- LOG(ERROR) << "X509 Verification error "
- << X509_verify_cert_error_string(x509_error) << " : "
- << x509_error << " : "
- << X509_STORE_CTX_get_error_depth(ctx.get()) << " : "
- << cert_status;
- verify_result->cert_status |= cert_status;
- }
-
- GetCertChainInfo(ctx.get(), verify_result);
- AppendPublicKeyHashes(ctx.get(), &verify_result->public_key_hashes);
-
- if (IsCertStatusError(verify_result->cert_status)) {
- return MapCertStatusToNetError(verify_result->cert_status);
- }
-
- // Currently we only ues OpenSSL's default root CA paths, so treat all
- // correctly verified certs as being from a known root.
- // TODO(joth): if the motivations described in
- // http://src.chromium.org/viewvc/chrome?view=rev&revision=80778 become an
- // issue on OpenSSL builds, we will need to embed a hardcoded list of well
- // known root CAs, as per the _mac and _win versions.
- verify_result->is_issued_by_known_root = true;
-
- return OK;
-}
-
-} // namespace net
diff --git a/src/net/cert/cert_verify_proc_openssl.h b/src/net/cert/cert_verify_proc_openssl.h
deleted file mode 100644
index 0524db1..0000000
--- a/src/net/cert/cert_verify_proc_openssl.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_BASE_CERT_VERIFY_PROC_OPENSSL_H_
-#define NET_BASE_CERT_VERIFY_PROC_OPENSSL_H_
-
-#include "net/cert/cert_verify_proc.h"
-
-// Note: CertVerifyProcOpenSSL was copied from the old Chromium(m27) to support
-// verifying certs with openSSL which has been used by Cobalt since day 1.
-// This Method has somehow been deprecated by new Chromium(m70).
-// TODO[johnx]: Switch to Chromium's new CertVerifyProcBuiltin soon after the
-// rebase.
-
-namespace net {
-
-// Performs certificate path construction and validation using OpenSSL.
-class CertVerifyProcOpenSSL : public CertVerifyProc {
- public:
- CertVerifyProcOpenSSL();
-
- protected:
- virtual ~CertVerifyProcOpenSSL();
-
- private:
- virtual int VerifyInternal(X509Certificate* cert,
- const std::string& hostname,
- const std::string& ocsp_response,
- int flags,
- CRLSet* crl_set,
- const CertificateList& additional_trust_anchors,
- CertVerifyResult* verify_result) override;
- virtual bool SupportsAdditionalTrustAnchors() const override { return false; }
-};
-
-} // namespace net
-
-#endif // NET_BASE_CERT_VERIFY_PROC_OPENSSL_H_
diff --git a/src/net/cert/internal/system_trust_store.cc b/src/net/cert/internal/system_trust_store.cc
index c5bb003..d0dbf8a 100644
--- a/src/net/cert/internal/system_trust_store.cc
+++ b/src/net/cert/internal/system_trust_store.cc
@@ -36,6 +36,8 @@
#include "net/cert/x509_util_mac.h"
#elif defined(OS_FUCHSIA)
#include "third_party/boringssl/src/include/openssl/pool.h"
+#elif defined(STARBOARD)
+#include "net/cert/internal/trust_store_in_memory_starboard.h"
#endif
namespace net {
@@ -218,21 +220,43 @@
#elif defined(STARBOARD)
-// Starboard does not currently provide support for system trust store access,
-// so we indicate that it should not be used.
+namespace {
+
+class StarboardSystemCerts {
+ public:
+ StarboardSystemCerts() {}
+
+ TrustStoreInMemoryStarboard* system_trust_store() {
+ return &system_trust_store_;
+ }
+
+ private:
+ TrustStoreInMemoryStarboard system_trust_store_;
+};
+
+base::LazyInstance<StarboardSystemCerts>::Leaky g_root_certs_starboard =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+// Starboard does not use system certificate stores but Cobalt ships with a
+// set of trusted CA certificates that can be used for validations.
class SystemTrustStoreStarboard : public BaseSystemTrustStore {
public:
SystemTrustStoreStarboard() {
+ trust_store_.AddTrustStore(
+ g_root_certs_starboard.Get().system_trust_store());
if (TestRootCerts::HasInstance()) {
trust_store_.AddTrustStore(
TestRootCerts::GetInstance()->test_trust_store());
}
}
- bool UsesSystemTrustStore() const override { return false; }
+ bool UsesSystemTrustStore() const override { return true; }
bool IsKnownRoot(const ParsedCertificate* trust_anchor) const override {
- return false;
+ return g_root_certs_starboard.Get().system_trust_store()->Contains(
+ trust_anchor);
}
};
diff --git a/src/net/cert/internal/trust_store_in_memory_starboard.cc b/src/net/cert/internal/trust_store_in_memory_starboard.cc
new file mode 100644
index 0000000..3d53b20
--- /dev/null
+++ b/src/net/cert/internal/trust_store_in_memory_starboard.cc
@@ -0,0 +1,178 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "net/cert/internal/trust_store_in_memory_starboard.h"
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/time/time.h"
+#include "net/cert/internal/cert_errors.h"
+#include "net/cert/pem_tokenizer.h"
+#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
+#include "starboard/directory.h"
+#include "starboard/file.h"
+#include "starboard/string.h"
+#include "third_party/boringssl/src/include/openssl/digest.h"
+#include "third_party/boringssl/src/include/openssl/sha.h"
+#include "third_party/boringssl/src/include/openssl/x509.h"
+
+namespace net {
+
+namespace {
+// PEM encoded DER cert is usually around or less than 2000 bytes long.
+const short kCertBufferSize = 8 * 1024;
+// Each certificate file name is 8 bit hash + ".0" suffix.
+const short kCertFileNameLength = 10;
+const char kCertificateHeader[] = "CERTIFICATE";
+const char kSSLDirName[] = "ssl";
+const char kCertsDirName[] = "certs";
+
+// Essentially an X509_NAME_hash without using X509_NAME. We did not use the
+// boringSSL function directly because net does not store certs with X509
+// struct anymore and converting binary certs to X509_NAME is slightly
+// expensive.
+unsigned long CertNameHash(const void* data, size_t length) {
+ unsigned long ret = 0;
+ unsigned char md[SHA_DIGEST_LENGTH];
+ if (!EVP_Digest(data, length, md, NULL, EVP_sha1(), NULL))
+ return 0;
+
+ ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) |
+ ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L)) &
+ 0xffffffffL;
+ return ret;
+}
+
+base::FilePath GetCertificateDirPath() {
+ base::FilePath cert_path;
+ base::PathService::Get(base::DIR_EXE, &cert_path);
+ cert_path = cert_path.Append(kSSLDirName).Append(kCertsDirName);
+ return std::move(cert_path);
+}
+
+std::unordered_set<std::string> GetCertNamesOnDisk() {
+ auto sb_certs_directory =
+ SbDirectoryOpen(GetCertificateDirPath().value().c_str(), nullptr);
+ if (!SbDirectoryIsValid(sb_certs_directory)) {
+// Unit tests, for example, do not use production certificates.
+#if defined(STARBOARD_BUILD_TYPE_QA) || defined(STARBOARD_BUILD_TYPE_GOLD)
+ SB_CHECK(false);
+#else
+ DLOG(WARNING) << "ssl/certs directory is not valid, no root certificates"
+ " will be loaded";
+#endif
+ return std::unordered_set<std::string>();
+ }
+ SbDirectoryEntry dir_entry;
+ std::unordered_set<std::string> trusted_certs_on_disk;
+
+ while (SbDirectoryGetNext(sb_certs_directory, &dir_entry)) {
+ if (SbStringGetLength(dir_entry.name) != kCertFileNameLength) {
+ continue;
+ }
+ trusted_certs_on_disk.emplace(dir_entry.name);
+ }
+ SbDirectoryClose(sb_certs_directory);
+ return std::move(trusted_certs_on_disk);
+}
+} // namespace
+
+scoped_refptr<ParsedCertificate> TrustStoreInMemoryStarboard::TryLoadCert(
+ const base::StringPiece& cert_name) const {
+ auto hash = CertNameHash(cert_name.data(), cert_name.length());
+ char cert_file_name[256];
+ SbStringFormatF(cert_file_name, 256, "%08lx.%d", hash, 0);
+
+ if (trusted_cert_names_on_disk_.find(cert_file_name) ==
+ trusted_cert_names_on_disk_.end()) {
+ // The requested certificate is not found.
+ return nullptr;
+ }
+
+ SbFileError out_error;
+ char cert_buffer[kCertBufferSize];
+ base::FilePath cert_path = GetCertificateDirPath().Append(cert_file_name);
+ SbFile sb_cert_file =
+ SbFileOpen(cert_path.value().c_str(), kSbFileOpenOnly | kSbFileRead,
+ nullptr, &out_error);
+ // The file was in certs directory when we iterated the directory at startup,
+ // opening it should not fail.
+ if (!SbFileIsValid(sb_cert_file)) {
+ NOTREACHED() << "ssl/certs/" << cert_path << " failed to open.";
+ return nullptr;
+ }
+ int cert_size = SbFileReadAll(sb_cert_file, cert_buffer, kCertBufferSize);
+ SbFileClose(sb_cert_file);
+ PEMTokenizer pem_tokenizer(base::StringPiece(cert_buffer, cert_size),
+ {kCertificateHeader});
+ pem_tokenizer.GetNext();
+ std::string decoded(pem_tokenizer.data());
+ DCHECK(!pem_tokenizer.GetNext());
+ bssl::UniquePtr<CRYPTO_BUFFER> crypto_buffer =
+ X509Certificate::CreateCertBufferFromBytes(decoded.data(),
+ decoded.length());
+ DCHECK(crypto_buffer);
+ CertErrors errors;
+ auto parsed = ParsedCertificate::Create(
+ bssl::UpRef(crypto_buffer.get()),
+ x509_util::DefaultParseCertificateOptions(), &errors);
+ CHECK(parsed) << errors.ToDebugString();
+ return parsed;
+}
+
+TrustStoreInMemoryStarboard::TrustStoreInMemoryStarboard()
+ : trusted_cert_names_on_disk_(std::move(GetCertNamesOnDisk())) {}
+
+TrustStoreInMemoryStarboard::~TrustStoreInMemoryStarboard() = default;
+
+void TrustStoreInMemoryStarboard::SyncGetIssuersOf(
+ const ParsedCertificate* cert,
+ ParsedCertificateList* issuers) {
+ DCHECK(issuers);
+ DCHECK(issuers->empty());
+ starboard::ScopedLock scoped_lock(load_mutex_);
+ // Look up the request certificate first in the trust store in memory.
+ underlying_trust_store_.SyncGetIssuersOf(cert, issuers);
+ if (issuers->empty()) {
+ // If the requested certificate is not found, compute certificate hash name
+ // and see if the certificate is stored on disk.
+ auto parsed_cert = TryLoadCert(cert->normalized_issuer().AsStringPiece());
+ if (parsed_cert.get()) {
+ issuers->push_back(parsed_cert);
+ underlying_trust_store_.AddTrustAnchor(parsed_cert);
+ }
+ }
+}
+
+void TrustStoreInMemoryStarboard::GetTrust(
+ const scoped_refptr<ParsedCertificate>& cert,
+ CertificateTrust* trust) const {
+ DCHECK(trust);
+ starboard::ScopedLock scoped_lock(load_mutex_);
+ // Loop up the request certificate first in the trust store in memory.
+ underlying_trust_store_.GetTrust(cert, trust);
+ if (trust->HasUnspecifiedTrust()) {
+ // If the requested certificate is not found, compute certificate hash name
+ // and see if the certificate is stored on disk.
+ auto parsed_cert = TryLoadCert(cert->normalized_subject().AsStringPiece());
+ if (parsed_cert.get()) {
+ *trust = CertificateTrust::ForTrustAnchor();
+ const_cast<TrustStoreInMemoryStarboard*>(this)
+ ->underlying_trust_store_.AddTrustAnchor(parsed_cert);
+ }
+ }
+}
+
+} // namespace net
diff --git a/src/net/cert/internal/trust_store_in_memory_starboard.h b/src/net/cert/internal/trust_store_in_memory_starboard.h
new file mode 100644
index 0000000..bed671e
--- /dev/null
+++ b/src/net/cert/internal/trust_store_in_memory_starboard.h
@@ -0,0 +1,68 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef NET_CERT_INTERNAL_TRUST_STORE_IN_MEMORY_STARBOARD_H_
+#define NET_CERT_INTERNAL_TRUST_STORE_IN_MEMORY_STARBOARD_H_
+
+#include <unordered_set>
+
+#include "base/strings/string_piece.h"
+#include "net/cert/internal/trust_store_in_memory.h"
+#include "starboard/common/mutex.h"
+
+namespace net {
+
+// Wrapper around TrustStoreInMemory to lazily load trusted root certificates.
+class NET_EXPORT TrustStoreInMemoryStarboard : public TrustStore {
+ public:
+ TrustStoreInMemoryStarboard();
+ ~TrustStoreInMemoryStarboard() override;
+
+ // TrustStore implementation:
+ void SyncGetIssuersOf(const ParsedCertificate* cert,
+ ParsedCertificateList* issuers) override;
+ void GetTrust(const scoped_refptr<ParsedCertificate>& cert,
+ CertificateTrust* trust) const override;
+
+ // Returns true if the trust store contains the given ParsedCertificate
+ // (matches by DER).
+ bool Contains(const ParsedCertificate* cert) const {
+ starboard::ScopedLock scoped_lock(load_mutex_);
+ return underlying_trust_store_.Contains(cert);
+ }
+
+ private:
+ TrustStoreInMemoryStarboard(const TrustStoreInMemoryStarboard&) = delete;
+ TrustStoreInMemoryStarboard& operator=(const TrustStoreInMemoryStarboard&) =
+ delete;
+
+ TrustStoreInMemory underlying_trust_store_;
+
+ // Given a certificate's canonical name, try to load this cert from trusted
+ // certs on disk if it is found.
+ scoped_refptr<ParsedCertificate> TryLoadCert(
+ const base::StringPiece& cert_name) const;
+
+ // The memory trust store can be accessed by multiple threads, in Chromium,
+ // the synchronization issue is solved by initializing trust store at startup
+ // and passing constant reference to consumers. Cobalt loads certs lazily and
+ // therefore guards the underlying_trust_store_ with mutex.
+ starboard::Mutex load_mutex_;
+
+ const std::unordered_set<std::string> trusted_cert_names_on_disk_;
+};
+
+} // namespace net
+
+#endif // NET_CERT_INTERNAL_TRUST_STORE_IN_MEMORY_STARBOARD_H_
diff --git a/src/net/dns/host_resolver_impl_unittest.cc b/src/net/dns/host_resolver_impl_unittest.cc
index f8afb04..0bdd7b2 100644
--- a/src/net/dns/host_resolver_impl_unittest.cc
+++ b/src/net/dns/host_resolver_impl_unittest.cc
@@ -2625,7 +2625,11 @@
// https://crbug.com/115051 is fixed.
// Test the retry attempts simulating host resolver proc that takes too long.
+#if defined(STARBOARD)
+TEST_F(HostResolverImplTest, FLAKY_MultipleAttempts) {
+#else
TEST_F(HostResolverImplTest, MultipleAttempts) {
+#endif
// Total number of attempts would be 3 and we want the 3rd attempt to resolve
// the host. First and second attempt will be forced to wait until they get
// word that a resolution has completed. The 3rd resolution attempt will try
@@ -2636,7 +2640,13 @@
// Add a little bit of extra fudge to the delay to allow reasonable
// flexibility for time > vs >= etc. We don't need to fail the test if we
// retry at t=6001 instead of t=6000.
+#if defined(STARBOARD)
+ // The 1 millisecond delay is not enough on some of Cobalt's Linux platforms
+ // to ensure all delayed tasks are executed.
+ base::TimeDelta kSleepFudgeFactor = base::TimeDelta::FromMilliseconds(30);
+#else
base::TimeDelta kSleepFudgeFactor = base::TimeDelta::FromMilliseconds(1);
+#endif
scoped_refptr<LookupAttemptHostResolverProc> resolver_proc(
new LookupAttemptHostResolverProc(
diff --git a/src/net/net.gyp b/src/net/net.gyp
index e87dbc9..f9d74c7 100644
--- a/src/net/net.gyp
+++ b/src/net/net.gyp
@@ -183,6 +183,8 @@
'cert/internal/trust_store_collection.h',
'cert/internal/trust_store_in_memory.cc',
'cert/internal/trust_store_in_memory.h',
+ 'cert/internal/trust_store_in_memory_starboard.cc',
+ 'cert/internal/trust_store_in_memory_starboard.h',
'cert/internal/verify_certificate_chain.cc',
'cert/internal/verify_certificate_chain.h',
'cert/internal/verify_name_match.cc',
@@ -431,10 +433,8 @@
'cert/cert_verify_proc.h',
# TODO[johnx]: Investigate why net deprecated openssl verifier and
# if justified switch back to builtin verifier.
- # 'cert/cert_verify_proc_builtin.cc',
- # 'cert/cert_verify_proc_builtin.h',
- 'cert/cert_verify_proc_openssl.cc',
- 'cert/cert_verify_proc_openssl.h',
+ 'cert/cert_verify_proc_builtin.cc',
+ 'cert/cert_verify_proc_builtin.h',
'cert/ct_log_response_parser.cc',
'cert/ct_log_response_parser.h',
'cert/ct_log_verifier.cc',
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java
index 494f57b..733cf2b 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/AudioTrackBridge.java
@@ -35,6 +35,23 @@
private AudioTimestamp audioTimestamp = new AudioTimestamp();
private long maxFramePositionSoFar = 0;
+ private int GetFrameSize(int sampleType, int channelCount) {
+ switch (sampleType) {
+ case AudioFormat.ENCODING_PCM_16BIT:
+ {
+ return 2 * channelCount;
+ }
+ case AudioFormat.ENCODING_PCM_FLOAT:
+ {
+ return 4 * channelCount;
+ }
+ default:
+ {
+ throw new RuntimeException("Unsupported sample type: " + sampleType);
+ }
+ }
+ }
+
public AudioTrackBridge(int sampleType, int sampleRate, int channelCount, int framesPerChannel) {
int channelConfig;
switch (channelCount) {
@@ -63,13 +80,12 @@
.setChannelMask(channelConfig)
.build();
- int minBufferSizeBytes = AudioTrack.getMinBufferSize(sampleRate, channelConfig, sampleType);
- int audioTrackBufferSize = minBufferSizeBytes;
- // Use framesPerChannel to determine the buffer size. To use a large buffer on a small
- // framesPerChannel may lead to audio playback not able to start.
- while (audioTrackBufferSize < framesPerChannel) {
- audioTrackBufferSize *= 2;
- }
+ // Try to create AudioTrack with the same size buffer as in renderer. But AudioTrack would not
+ // start playing until the buffer is fully filled once. A large buffer may cause
+ // AudioTrack not able to start. And we now pass no more than 1s of audio data to
+ // starboard player, limit the buffer size to store at most 0.5s of audio data.
+ int audioTrackBufferSize =
+ Math.min(framesPerChannel, sampleRate / 2) * GetFrameSize(sampleType, channelCount);
while (audioTrackBufferSize > 0) {
try {
if (Build.VERSION.SDK_INT >= 26) {
@@ -105,7 +121,8 @@
TAG,
String.format(
"AudioTrack created with buffer size %d. The minimum buffer size is %d.",
- audioTrackBufferSize, minBufferSizeBytes));
+ audioTrackBufferSize,
+ AudioTrack.getMinBufferSize(sampleRate, channelConfig, sampleType)));
}
public Boolean isAudioTrackValid() {
diff --git a/src/starboard/android/apk/build.id b/src/starboard/android/apk/build.id
new file mode 100644
index 0000000..80c1e89
--- /dev/null
+++ b/src/starboard/android/apk/build.id
@@ -0,0 +1 @@
+217501
\ No newline at end of file
diff --git a/src/starboard/android/shared/audio_track_audio_sink_type.cc b/src/starboard/android/shared/audio_track_audio_sink_type.cc
index a6584f2..24f1c5f 100644
--- a/src/starboard/android/shared/audio_track_audio_sink_type.cc
+++ b/src/starboard/android/shared/audio_track_audio_sink_type.cc
@@ -36,6 +36,11 @@
const jint kNoOffset = 0;
+const size_t kSilenceFramesPerAppend = 1024;
+// 6 (max channels) * 4 (max sample size) * kSilenceFramesPerAppend, the number
+// is to ensure we always have at least 1024 frames silence to write.
+const uint8_t kSilenceBuffer[24 * kSilenceFramesPerAppend] = {0};
+
// Helper function to compute the size of the two valid starboard audio sample
// types.
size_t GetSampleSize(SbMediaAudioSampleType sample_type) {
@@ -99,6 +104,8 @@
static void* ThreadEntryPoint(void* context);
void AudioThreadFunc();
+ int WriteData(JniEnvExt* env, const void* buffer, int size);
+
Type* type_;
int channels_;
int sampling_frequency_hz_;
@@ -292,48 +299,26 @@
std::min(expected_written_frames, kMaxFramesPerRequest);
if (expected_written_frames == 0) {
// It is possible that all the frames in buffer are written to the
- // soundcard, but those are not being consumed.
+ // soundcard, but those are not being consumed. If eos is reached,
+ // write silence to make sure audio track start working and avoid
+ // underflow. Android audio track would not start working before
+ // its buffer is fully filled once.
+ if (is_eos_reached) {
+ // Currently AudioDevice and AudioRenderer will write tail silence.
+ // It should be reached only in tests.
+ WriteData(env, kSilenceBuffer, kSilenceFramesPerAppend);
+ }
SbThreadSleep(10 * kSbTimeMillisecond);
continue;
}
SB_DCHECK(expected_written_frames > 0);
- bool written_fully = false;
-
- if (sample_type_ == kSbMediaAudioSampleTypeFloat32) {
- int expected_written_size = expected_written_frames * channels_;
- env->SetFloatArrayRegion(
- static_cast<jfloatArray>(j_audio_data_), kNoOffset,
- expected_written_size,
- static_cast<const float*>(IncrementPointerByBytes(
- frame_buffer_,
- start_position * channels_ * GetSampleSize(sample_type_))));
- int written =
- env->CallIntMethodOrAbort(j_audio_track_bridge_, "write", "([FI)I",
- j_audio_data_, expected_written_size);
- SB_DCHECK(written >= 0);
- SB_DCHECK(written % channels_ == 0);
- written_frames_ += written / channels_;
- written_fully = (written == expected_written_frames);
- } else if (sample_type_ == kSbMediaAudioSampleTypeInt16Deprecated) {
- int expected_written_size =
- expected_written_frames * channels_ * GetSampleSize(sample_type_);
- env->SetByteArrayRegion(
- static_cast<jbyteArray>(j_audio_data_), kNoOffset,
- expected_written_size,
- static_cast<const jbyte*>(IncrementPointerByBytes(
- frame_buffer_,
- start_position * channels_ * GetSampleSize(sample_type_))));
- int written =
- env->CallIntMethodOrAbort(j_audio_track_bridge_, "write", "([BI)I",
- j_audio_data_, expected_written_size);
- SB_DCHECK(written >= 0);
- SB_DCHECK(written % (channels_ * GetSampleSize(sample_type_)) == 0);
- written_frames_ += written / (channels_ * GetSampleSize(sample_type_));
- written_fully = (written == expected_written_frames);
- } else {
- SB_NOTREACHED();
- }
-
+ int written_frames = WriteData(
+ env,
+ IncrementPointerByBytes(frame_buffer_, start_position * channels_ *
+ GetSampleSize(sample_type_)),
+ expected_written_frames);
+ written_frames_ += written_frames;
+ bool written_fully = (written_frames == expected_written_frames);
auto unplayed_frames_in_time =
written_frames_ * kSbTimeSecond / sampling_frequency_hz_ -
(SbTimeGetMonotonicNow() - frames_consumed_at);
@@ -346,7 +331,7 @@
SbThreadSleep(40 * kSbTimeMillisecond);
} else if (!written_fully) {
// Only sleep if the buffer is nearly full and the last write is partial.
- SbThreadSleep(1 * kSbTimeMillisecond);
+ SbThreadSleep(10 * kSbTimeMillisecond);
}
}
@@ -358,6 +343,38 @@
env->CallVoidMethodOrAbort(j_audio_track_bridge_, "flush", "()V");
}
+int AudioTrackAudioSink::WriteData(JniEnvExt* env,
+ const void* buffer,
+ int expected_written_frames) {
+ if (sample_type_ == kSbMediaAudioSampleTypeFloat32) {
+ int expected_written_size = expected_written_frames * channels_;
+ env->SetFloatArrayRegion(static_cast<jfloatArray>(j_audio_data_), kNoOffset,
+ expected_written_size,
+ static_cast<const float*>(buffer));
+ int written =
+ env->CallIntMethodOrAbort(j_audio_track_bridge_, "write", "([FI)I",
+ j_audio_data_, expected_written_size);
+ SB_DCHECK(written >= 0);
+ SB_DCHECK(written % channels_ == 0);
+ return written / channels_;
+ }
+ if (sample_type_ == kSbMediaAudioSampleTypeInt16Deprecated) {
+ int expected_written_size =
+ expected_written_frames * channels_ * GetSampleSize(sample_type_);
+ env->SetByteArrayRegion(static_cast<jbyteArray>(j_audio_data_), kNoOffset,
+ expected_written_size,
+ static_cast<const jbyte*>(buffer));
+ int written =
+ env->CallIntMethodOrAbort(j_audio_track_bridge_, "write", "([BI)I",
+ j_audio_data_, expected_written_size);
+ SB_DCHECK(written >= 0);
+ SB_DCHECK(written % (channels_ * GetSampleSize(sample_type_)) == 0);
+ return written / (channels_ * GetSampleSize(sample_type_));
+ }
+ SB_NOTREACHED();
+ return 0;
+}
+
void AudioTrackAudioSink::SetVolume(double volume) {
auto* env = JniEnvExt::Get();
jint status = env->CallIntMethodOrAbort(j_audio_track_bridge_, "setVolume",
diff --git a/src/starboard/android/shared/gyp_configuration.py b/src/starboard/android/shared/gyp_configuration.py
index e6d28d9..d674f72 100644
--- a/src/starboard/android/shared/gyp_configuration.py
+++ b/src/starboard/android/shared/gyp_configuration.py
@@ -298,13 +298,10 @@
'VideoDecoderTests/VideoDecoderTest.SingleInput/1',
'VideoDecoderTests/VideoDecoderTest.SingleInput/2',
'VideoDecoderTests/VideoDecoderTest.SingleInput/3',
-
- # On some platforms, and for some decoders (such as AVC), Android
- # returns MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER for the test's
- # invalid input frame instead of signaling an error, which the test is
- # looking for.
- 'VideoDecoderTests/VideoDecoderTest.SingleInvalidInput/0',
- 'VideoDecoderTests/VideoDecoderTest.SingleInvalidInput/1',
+ 'VideoDecoderTests/VideoDecoderTest.SingleInvalidInput/*',
+ 'VideoDecoderTests/VideoDecoderTest'
+ '.MultipleValidInputsAfterInvalidKeyFrame/*',
+ 'VideoDecoderTests/VideoDecoderTest.MultipleInvalidInput/*',
# Android currently does not support multi-video playback, which
# the following tests depend upon.
diff --git a/src/starboard/android/shared/system_get_property.cc b/src/starboard/android/shared/system_get_property.cc
index d4e6d84..d4412d4 100644
--- a/src/starboard/android/shared/system_get_property.cc
+++ b/src/starboard/android/shared/system_get_property.cc
@@ -93,7 +93,7 @@
switch (property_id) {
case kSbSystemPropertyBrandName:
- return GetAndroidSystemProperty("ro.product.manufacturer", out_value,
+ return GetAndroidSystemProperty("ro.product.brand", out_value,
value_length, kUnknownValue);
case kSbSystemPropertyModelName:
return GetAndroidSystemProperty("ro.product.model", out_value,
@@ -105,8 +105,11 @@
return GetAndroidSystemProperty("ro.board.platform", out_value,
value_length, kUnknownValue);
case kSbSystemPropertyModelYear:
+ return false;
case kSbSystemPropertyOriginalDesignManufacturerName:
- return false;
+ return GetAndroidSystemProperty("ro.product.manufacturer", out_value,
+ value_length, kUnknownValue);
+
case kSbSystemPropertyFriendlyName:
return CopyStringAndTestIfSuccess(out_value, value_length, kFriendlyName);
diff --git a/src/starboard/common/common.gyp b/src/starboard/common/common.gyp
index c7cb5f6..4db427b 100644
--- a/src/starboard/common/common.gyp
+++ b/src/starboard/common/common.gyp
@@ -29,7 +29,7 @@
'condition_variable.cc',
'condition_variable.h',
'flat_map.h',
- 'locked_ptr.h',
+ 'locked_ptr.h',
'log.cc',
'log.h',
'memory.cc',
diff --git a/src/starboard/cpu_features.h b/src/starboard/cpu_features.h
index 6aed047..166bd74 100644
--- a/src/starboard/cpu_features.h
+++ b/src/starboard/cpu_features.h
@@ -31,6 +31,10 @@
#if SB_API_VERSION >= 11
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef enum SbCPUFeaturesArchitecture {
kSbCPUFeaturesArchitectureArm,
kSbCPUFeaturesArchitectureArm64,
@@ -263,9 +267,12 @@
// under the key "model name" or "Processor".
const char* brand;
- // Processor cache line size in bytes. Queried from /proc/cpuinfo or
+ // Processor cache line size in bytes of Level 1 instruction cache and data
+ // cache. Queried by sysconf(_SC_LEVEL1_ICACHE_LINESIZE) and
+ // sysconf(_SC_LEVEL1_DCACHE_LINESIZE), or from files /proc/cpuinfo,
// /proc/self/auxv, or CPUID with CLFLUSH instruction.
- int32_t cache_size;
+ int32_t icache_line_size;
+ int32_t dcache_line_size;
// Processor has floating-point unit on-chip.
bool has_fpu;
@@ -314,5 +321,9 @@
// all fields in |features| are invalid.
SB_EXPORT bool SbCPUFeaturesGet(SbCPUFeatures* features);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
#endif // SB_API_VERSION >= 11
#endif // STARBOARD_CPU_FEATURES_H_
diff --git a/src/starboard/elf_loader/dynamic_section.cc b/src/starboard/elf_loader/dynamic_section.cc
new file mode 100644
index 0000000..b4d9422
--- /dev/null
+++ b/src/starboard/elf_loader/dynamic_section.cc
@@ -0,0 +1,203 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/dynamic_section.h"
+
+#include "starboard/common/log.h"
+
+namespace starboard {
+namespace elf_loader {
+
+DynamicSection::DynamicSection(Addr base_memory_address,
+ Dyn* dynamic,
+ size_t dynamic_count,
+ Word dynamic_flags)
+ : base_memory_address_(base_memory_address),
+ soname_(NULL),
+ dynamic_(dynamic),
+ dynamic_count_(dynamic_count),
+ dynamic_flags_(dynamic_flags),
+ has_DT_SYMBOLIC_(false),
+ symbol_table_(NULL),
+ string_table_(NULL),
+ preinit_array_(NULL),
+ preinit_array_count_(0),
+ init_array_(NULL),
+ init_array_count_(0),
+ fini_array_(NULL),
+ fini_array_count_(0),
+ init_func_(NULL),
+ fini_func_(NULL) {}
+
+bool DynamicSection::InitDynamicSection() {
+ SB_LOG(INFO) << "Dynamic section count=" << dynamic_count_;
+ for (int i = 0; i < dynamic_count_; i++) {
+ Addr dyn_value = dynamic_[i].d_un.d_val;
+ uintptr_t dyn_addr = base_memory_address_ + dynamic_[i].d_un.d_ptr;
+ SB_LOG(INFO) << "Dynamic tag=" << dynamic_[i].d_tag;
+ switch (dynamic_[i].d_tag) {
+ case DT_DEBUG:
+ // TODO: implement.
+ break;
+ case DT_INIT:
+ SB_LOG(INFO) << " DT_INIT addr=0x" << std::hex << dyn_addr;
+ init_func_ = reinterpret_cast<linker_function_t>(dyn_addr);
+ break;
+ case DT_FINI:
+ SB_LOG(INFO) << " DT_FINI addr=0x" << std::hex << dyn_addr;
+ fini_func_ = reinterpret_cast<linker_function_t>(dyn_addr);
+ break;
+ case DT_INIT_ARRAY:
+ SB_LOG(INFO) << " DT_INIT_ARRAY addr=0x" << std::hex << dyn_addr;
+ init_array_ = reinterpret_cast<linker_function_t*>(dyn_addr);
+ break;
+ case DT_INIT_ARRAYSZ:
+ init_array_count_ = dyn_value / sizeof(Addr);
+ SB_LOG(INFO) << " DT_INIT_ARRAYSZ value=0x" << std::hex << dyn_value
+ << " count=" << std::dec << init_array_count_;
+ break;
+ case DT_FINI_ARRAY:
+ SB_LOG(INFO) << " DT_FINI_ARRAY addr=0x" << std::hex << dyn_addr;
+ fini_array_ = reinterpret_cast<linker_function_t*>(dyn_addr);
+ break;
+ case DT_FINI_ARRAYSZ:
+ fini_array_count_ = dyn_value / sizeof(Addr);
+ SB_LOG(INFO) << " DT_FINI_ARRAYSZ value=0x" << std::hex << dyn_value
+ << " count=" << fini_array_count_;
+ break;
+ case DT_PREINIT_ARRAY:
+ SB_LOG(INFO) << " DT_PREINIT_ARRAY addr=0x" << std::hex << dyn_addr;
+ preinit_array_ = reinterpret_cast<linker_function_t*>(dyn_addr);
+ break;
+ case DT_PREINIT_ARRAYSZ:
+ preinit_array_count_ = dyn_value / sizeof(Addr);
+ SB_LOG(INFO) << " DT_PREINIT_ARRAYSZ addr=" << dyn_addr
+ << " count=" << preinit_array_count_;
+ break;
+ case DT_SYMBOLIC:
+ SB_LOG(INFO) << " DT_SYMBOLIC";
+ has_DT_SYMBOLIC_ = true;
+ break;
+ case DT_FLAGS:
+ if (dyn_value & DF_SYMBOLIC)
+ has_DT_SYMBOLIC_ = true;
+ break;
+ case DT_SONAME:
+ soname_ = string_table_ + dyn_value;
+ break;
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
+bool DynamicSection::InitDynamicSymbols() {
+ for (int i = 0; i < dynamic_count_; i++) {
+ Addr dyn_value = dynamic_[i].d_un.d_val;
+ uintptr_t dyn_addr = base_memory_address_ + dynamic_[i].d_un.d_ptr;
+ switch (dynamic_[i].d_tag) {
+ case DT_HASH:
+ SB_LOG(INFO) << " DT_HASH addr=0x" << std::hex << dyn_addr;
+ elf_hash_.Init(dyn_addr);
+ break;
+ case DT_GNU_HASH:
+ SB_LOG(INFO) << " DT_GNU_HASH addr=0x" << std::hex << dyn_addr;
+ gnu_hash_.Init(dyn_addr);
+ break;
+ case DT_STRTAB:
+ SB_LOG(INFO) << " DT_STRTAB addr=0x" << std::hex << dyn_addr;
+ string_table_ = reinterpret_cast<const char*>(dyn_addr);
+ break;
+ case DT_SYMTAB:
+ SB_LOG(INFO) << " DT_SYMTAB addr=0x" << std::hex << dyn_addr;
+ symbol_table_ = reinterpret_cast<Sym*>(dyn_addr);
+ break;
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
+const Dyn* DynamicSection::GetDynamicTable() {
+ return dynamic_;
+}
+
+size_t DynamicSection::GetDynamicTableSize() {
+ return dynamic_count_;
+}
+
+void DynamicSection::CallConstructors() {
+ CallFunction(init_func_, "DT_INIT");
+ for (size_t n = 0; n < init_array_count_; ++n)
+ CallFunction(init_array_[n], "DT_INIT_ARRAY");
+}
+
+void DynamicSection::CallDestructors() {
+ for (size_t n = fini_array_count_; n > 0; --n) {
+ CallFunction(fini_array_[n - 1], "DT_FINI_ARRAY");
+ }
+ CallFunction(fini_func_, "DT_FINI");
+}
+
+void DynamicSection::CallFunction(linker_function_t func,
+ const char* func_type) {
+ uintptr_t func_address = reinterpret_cast<uintptr_t>(func);
+
+ // On some platforms the entries in the array can be 0 or -1,
+ // and should be ignored e.g. Android:
+ // https://android.googlesource.com/platform/bionic/+/android-4.2_r1/linker/README.TXT
+ if (func_address != 0 && func_address != uintptr_t(-1)) {
+ func();
+ }
+}
+
+const Sym* DynamicSection::LookupById(size_t symbol_id) const {
+ // TODO: Calculated the symbol_table size and validation check.
+ return &symbol_table_[symbol_id];
+}
+
+bool DynamicSection::IsWeakById(size_t symbol_id) const {
+ // TODO: Calculated the symbol_table size and validation check.
+ return ELF_ST_BIND(symbol_table_[symbol_id].st_info) == STB_WEAK;
+}
+
+const char* DynamicSection::LookupNameById(size_t symbol_id) const {
+ const Sym* sym = LookupById(symbol_id);
+ // TODO: Confirm that LookupById actually can return NULL.
+ if (!sym)
+ return NULL;
+ return string_table_ + sym->st_name;
+}
+
+const Sym* DynamicSection::LookupByName(const char* symbol_name) const {
+ const Sym* sym =
+ gnu_hash_.IsValid()
+ ? gnu_hash_.LookupByName(symbol_name, symbol_table_, string_table_)
+ : elf_hash_.LookupByName(symbol_name, symbol_table_, string_table_);
+
+ // Ignore undefined symbols or those that are not global or weak definitions.
+ if (!sym || sym->st_shndx == SHN_UNDEF)
+ return NULL;
+
+ uint8_t info = ELF_ST_BIND(sym->st_info);
+ if (info != STB_GLOBAL && info != STB_WEAK)
+ return NULL;
+
+ return sym;
+}
+
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/dynamic_section.h b/src/starboard/elf_loader/dynamic_section.h
new file mode 100644
index 0000000..eec44c2
--- /dev/null
+++ b/src/starboard/elf_loader/dynamic_section.h
@@ -0,0 +1,106 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef STARBOARD_ELF_LOADER_DYNAMIC_SECTION_H_
+#define STARBOARD_ELF_LOADER_DYNAMIC_SECTION_H_
+
+#include "starboard/elf_loader/elf.h"
+#include "starboard/elf_loader/elf_hash_table.h"
+#include "starboard/elf_loader/exported_symbols.h"
+#include "starboard/elf_loader/gnu_hash_table.h"
+#include "starboard/elf_loader/program_table.h"
+
+namespace starboard {
+namespace elf_loader {
+
+typedef void (*linker_function_t)();
+
+// class representing the ELF dynamic
+// section with dynamic symbols and a
+// string tables.
+
+// The initialization requires calling:
+// 1. InitDynamicSection()
+// 2. InitDynamicSymbols()
+//
+class DynamicSection {
+ public:
+ DynamicSection(Addr base_memory_address,
+ Dyn* dynamic,
+ size_t dynamic_count,
+ Word dynamic_flags);
+
+ // Initialize the dynamic section.
+ bool InitDynamicSection();
+
+ // Initialize all the dynamic symbol tables.
+ bool InitDynamicSymbols();
+
+ // Get pointer to the dynamic table.
+ const Dyn* GetDynamicTable();
+
+ // Get the size of the dynamic table
+ size_t GetDynamicTableSize();
+
+ // Call all the global constructors.
+ void CallConstructors();
+
+ // Call all the global destructors.
+ void CallDestructors();
+
+ // Call a function.
+ void CallFunction(linker_function_t func, const char* func_type);
+
+ // Lookup a symbol using its name.
+ const Sym* LookupByName(const char* symbol_name) const;
+
+ // Lookup a symbol using its id.
+ const Sym* LookupById(size_t symbol_id) const;
+
+ // Checks if a symbols is weak.
+ bool IsWeakById(size_t symbol_id) const;
+
+ // Lookup the name of a symbol by using its id.
+ const char* LookupNameById(size_t symbol_id) const;
+
+ private:
+ Addr base_memory_address_;
+ const char* soname_;
+
+ Dyn* dynamic_;
+ size_t dynamic_count_;
+ Word dynamic_flags_;
+ bool has_DT_SYMBOLIC_;
+
+ Sym* symbol_table_;
+ const char* string_table_;
+ ElfHashTable elf_hash_;
+ GnuHashTable gnu_hash_;
+
+ linker_function_t* preinit_array_;
+ size_t preinit_array_count_;
+ linker_function_t* init_array_;
+ size_t init_array_count_;
+ linker_function_t* fini_array_;
+ size_t fini_array_count_;
+ linker_function_t init_func_;
+ linker_function_t fini_func_;
+
+ SB_DISALLOW_COPY_AND_ASSIGN(DynamicSection);
+};
+
+} // namespace elf_loader
+} // namespace starboard
+
+#endif // STARBOARD_ELF_LOADER_DYNAMIC_SECTION_H_
diff --git a/src/starboard/elf_loader/dynamic_section_test.cc b/src/starboard/elf_loader/dynamic_section_test.cc
new file mode 100644
index 0000000..9aa68be
--- /dev/null
+++ b/src/starboard/elf_loader/dynamic_section_test.cc
@@ -0,0 +1,38 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/elf_loader_impl.h"
+
+#include "starboard/common/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace elf_loader {
+
+namespace {
+
+// TODO: implement
+class DynamicSection : public ::testing::Test {
+ protected:
+ DynamicSection() {}
+ ~DynamicSection() {}
+};
+
+TEST_F(DynamicSection, Initialize) {
+ EXPECT_TRUE(true);
+}
+
+} // namespace
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/elf.h b/src/starboard/elf_loader/elf.h
new file mode 100644
index 0000000..1ecd908
--- /dev/null
+++ b/src/starboard/elf_loader/elf.h
@@ -0,0 +1,651 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef STARBOARD_ELF_LOADER_ELF_H_
+#define STARBOARD_ELF_LOADER_ELF_H_
+
+// Subset of the ELF specification for loading Dynamic Shared Libraries.
+// System V Application Binary Interface - DRAFT - 10 June 2013
+// http://www.sco.com/developers/gabi/latest/contents.html
+
+#ifndef __cplusplus
+#error "Only C++ files can include this header."
+#endif
+
+#include "starboard/types.h"
+
+namespace starboard {
+namespace elf_loader {
+
+// 32 bit data types
+
+// Unsigned program address - 4 bytes.
+typedef uint32_t Elf32_Addr;
+
+// Unsigned medium integer - 2 bytes.
+typedef uint16_t Elf32_Half;
+
+// Unsigned file offset - 4 bytes.
+typedef uint32_t Elf32_Off;
+
+// Signed large integer - 4 bytes.
+typedef int32_t Elf32_Sword;
+
+// Unsigned large integer - 4 bytes.
+typedef uint32_t Elf32_Word;
+
+// 64 bit data types
+
+// Unsigned program address - 8 bytes.
+typedef uint64_t Elf64_Addr;
+
+// Unsigned file offset - 8 bytes.
+typedef uint64_t Elf64_Off;
+
+// Unsigned medium intege 2 - bytes.
+typedef uint16_t Elf64_Half;
+
+// Unsigned integer - 4 bytes.
+typedef uint32_t Elf64_Word;
+
+// Signed integer - 4 bytes.
+typedef int32_t Elf64_Sword;
+
+// Unsigned long integer - 8 bytes.
+typedef uint64_t Elf64_Xword;
+
+// Signed long integer - 8 bytes.
+typedef int64_t Elf64_Sxword;
+
+#define EI_NIDENT (16)
+
+// Pack all the structs at 1 byte alignment.
+#pragma pack(push)
+#pragma pack(1)
+
+// 32 bit ELF file header.
+typedef struct {
+ // The initial bytes mark the file as an object file and provide
+ // machine-independent data.
+ unsigned char e_ident[EI_NIDENT];
+
+ // The object file type. We support only ET_DYN.
+ Elf32_Half e_type;
+
+ // Architecture of the file.
+ Elf32_Half e_machine;
+
+ // Object file version. The value should be 1.
+ Elf32_Word e_version;
+
+ // Virtual address to which the system first transfers
+ // control, thus starting the process.
+ Elf32_Addr e_entry;
+
+ // Program header table's file offset in bytes.
+ Elf32_Off e_phoff;
+
+ // Section header table's file offset in bytes.
+ Elf32_Off e_shoff;
+
+ // Processor-specific flags associated with the file.
+ Elf32_Word e_flags;
+
+ // ELF header's size in bytes.
+ Elf32_Half e_ehsize;
+
+ // Size in bytes of one entry in the file's program header table
+ Elf32_Half e_phentsize;
+
+ // The number of entries in the program header table.
+ Elf32_Half e_phnum;
+
+ // Section header's size in bytes.
+ Elf32_Half e_shentsize;
+
+ // The number of entries in the section header table.
+ Elf32_Half e_shnum;
+
+ // The section header table index of the entry associated
+ // with the section name string table.
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+// 64 bit ELF file header.
+typedef struct {
+ // The initial bytes mark the file as an object file and provide
+ // machine-independent data.
+ unsigned char e_ident[EI_NIDENT];
+
+ // The object file type. We support only ET_DYN.
+ Elf64_Half e_type;
+
+ // Architecture of the file.
+ Elf64_Half e_machine;
+
+ // Object file version. The value should be 1.
+ Elf64_Word e_version;
+
+ // Virtual address to which the system first transfers
+ // control, thus starting the process.
+ Elf64_Addr e_entry;
+
+ // Program header table's file offset in bytes.
+ Elf64_Off e_phoff;
+
+ // Section header table's file offset in bytes.
+ Elf64_Off e_shoff;
+
+ // Processor-specific flags associated with the file.
+ Elf64_Word e_flags;
+
+ // This member holds the ELF header's size in bytes.
+ Elf64_Half e_ehsize;
+
+ // Size in bytes of one entry in the file's program header table
+ Elf64_Half e_phentsize;
+
+ // The number of entries in the section header table.
+ Elf64_Half e_phnum;
+
+ // Section header's size in bytes.
+ Elf64_Half e_shentsize;
+
+ // The number of entries in the section header table.
+ Elf64_Half e_shnum;
+
+ // The section header table index of the entry associated
+ // with the section name string table.
+ Elf64_Half e_shstrndx;
+} Elf64_Ehdr;
+
+// 32 bit Program header.
+typedef struct {
+ // The kind of segment this array element describes.
+ Elf32_Word p_type;
+
+ // The offset from the beginning of the file at which the
+ // first byte of the segment resides.
+ Elf32_Off p_offset;
+
+ // The virtual address at which the first byte of the
+ // segment resides in memory.
+ Elf32_Addr p_vaddr;
+
+ // Segment's physical address. Unused for shared libraries.
+ Elf32_Addr p_paddr;
+
+ // The number of bytes in the file image of the segment. May be zero.
+ Elf32_Word p_filesz;
+
+ // The number of bytes in the memory image of the segment. May be zero.
+ Elf32_Word p_memsz;
+
+ // Segment flags
+ Elf32_Word p_flags;
+
+ // Segment alignment constraint.
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+// 64 bit Program header.
+typedef struct {
+ // The kind of segment this array element describes.
+ Elf64_Word p_type;
+
+ // Segment flags
+ Elf64_Word p_flags;
+
+ // The offset from the beginning of the file at which the
+ // first byte of the segment resides.
+ Elf64_Off p_offset;
+
+ // The virtual address at which the first byte of the
+ // segment resides in memory.
+ Elf64_Addr p_vaddr;
+
+ // Segment's physical address. Unused for shared libraries.
+ Elf64_Addr p_paddr;
+
+ // The number of bytes in the file image of the segment. May be zero.
+ Elf64_Xword p_filesz;
+
+ // The number of bytes in the memory image of the segment. May be zero.
+ Elf64_Xword p_memsz;
+
+ // Segment alignment constraint
+ Elf64_Xword p_align;
+} Elf64_Phdr;
+
+// 32 bit Dynamic Section Entry
+typedef struct {
+ // Controls the interpretation of d_un.
+ Elf32_Sword d_tag;
+ union {
+ // These objects represent integer values with various interpretations.
+ Elf32_Word d_val;
+ // These objects represent program virtual addresses.
+ Elf32_Addr d_ptr;
+ } d_un;
+} Elf32_Dyn;
+
+// 64 bit Dynamic Section Entry
+typedef struct {
+ // Controls the interpretation of d_un.
+ Elf64_Sxword d_tag;
+ union {
+ // These objects represent integer values with various interpretations.
+ Elf64_Xword d_val;
+ // These objects represent program virtual addresses.
+ Elf64_Addr d_ptr;
+ } d_un;
+} Elf64_Dyn;
+
+// 32 bit Symbol Table Entry
+typedef struct {
+ // An index into the object file's symbol string table,
+ // which holds the character representations of the symbol names. If the value
+ // is non-zero, it represents a string table index that gives the symbol name.
+ // Otherwise, the symbol table entry has no name.
+ Elf32_Word st_name;
+
+ // The value of the associated symbol. Depending on the
+ // context, this may be an absolute value, an address, and so on;
+ Elf32_Addr st_value;
+
+ // Many symbols have associated sizes. For example, a data object's size is
+ // the number of bytes contained in the object.
+ Elf32_Word st_size;
+
+ // The symbol's type and binding attributes.
+ unsigned char st_info;
+
+ // Symbol's visibility.
+ unsigned char st_other;
+
+ // Every symbol table entry is defined in relation to some section. This
+ // member holds the relevant section header table index.
+ Elf32_Half st_shndx;
+} Elf32_Sym;
+
+// 64 bit Symbol Table Entry
+typedef struct {
+ // An index into the object file's symbol string table,
+ // which holds the character representations of the symbol names. If the value
+ // is non-zero, it represents a string table index that gives the symbol name.
+ // Otherwise, the symbol table entry has no name.
+ Elf64_Word st_name;
+
+ // The symbol's type and binding attributes.
+ unsigned char st_info;
+
+ // Symbol's visibility.
+ unsigned char st_other;
+
+ // Every symbol table entry is defined in relation to some section. This
+ // member holds the relevant section header table index.
+ Elf64_Half st_shndx;
+
+ // The value of the associated symbol. Depending on the
+ // context, this may be an absolute value, an address, and so on;
+ Elf64_Addr st_value;
+
+ // Many symbols have associated sizes. For example, a data object's size is
+ // the number of bytes contained in the object.
+ Elf64_Xword st_size;
+} Elf64_Sym;
+
+// 32 bit Relocation Entry
+typedef struct {
+ // The location at which to apply the relocation action. For a relocatable
+ // file, the value is the byte offset from the beginning of the section to
+ // the storage unit affected by the relocation. For an executable file or a
+ // shared object, the value is the virtual address of the storage unit
+ // affected by the relocation.
+ Elf32_Addr r_offset;
+ // The symbol table index with respect to which the
+ // relocation must be made, and the type of relocation to apply.
+ Elf32_Word r_info;
+} Elf32_Rel;
+
+// 64 bit Relocation Entry
+typedef struct {
+ // The location at which to apply the relocation action. For
+ // a relocatable file, the value is the byte offset from the beginning of the
+ // section to the storage unit affected by the relocation. For an executable
+ // file or a shared object, the value is the virtual address of the storage
+ // unit affected by the relocation.
+ Elf64_Addr r_offset;
+
+ // The symbol table index with respect to which the
+ // relocation must be made, and the type of relocation to apply.
+ Elf64_Xword r_info;
+} Elf64_Rel;
+
+// 32 bit Relocation Entry with Addend.
+typedef struct {
+ // The location at which to apply the relocation action. For
+ // a relocatable file, the value is the byte offset from the beginning of the
+ // section to the storage unit affected by the relocation. For an executable
+ // file or a shared object, the value is the virtual address of the storage
+ // unit affected by the relocation.
+ Elf32_Addr r_offset;
+
+ // The symbol table index with respect to which the
+ // relocation must be made, and the type of relocation to apply.
+ Elf32_Word r_info;
+
+ // A constant addend used to compute the value to be stored into the
+ // relocatable field.
+ Elf32_Sword r_addend;
+} Elf32_Rela;
+
+// 64 bit Relocation Entry with Addend.
+typedef struct {
+ // The location at which to apply the relocation action. For a relocatable
+ // file, the value is the byte offset from the beginning of the section to the
+ // storage unit affected by the relocation. For an executable file or a shared
+ // object, the value is the virtual address of the storage unit affected by
+ // the relocation.
+ Elf64_Addr r_offset;
+
+ // The symbol table index with respect to which the
+ // relocation must be made, and the type of relocation to apply.
+ Elf64_Xword r_info;
+
+ // A constant addend used to compute the value to be stored into the
+ // relocatable field.
+ Elf64_Sxword r_addend;
+} Elf64_Rela;
+
+#pragma pack(pop)
+
+#define EI_CLASS 4
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+#define EI_DATA 5
+#define ELFDATA2LSB 1
+#define ET_DYN 3
+#define EV_CURRENT 1
+
+#if SB_HAS(32_BIT_POINTERS)
+typedef Elf32_Ehdr Ehdr;
+typedef Elf32_Phdr Phdr;
+typedef Elf32_Addr Addr;
+typedef Elf32_Dyn Dyn;
+typedef Elf32_Word Word;
+typedef Elf32_Sym Sym;
+typedef Elf32_Rel Rel;
+typedef Elf32_Rela Rela;
+typedef Elf32_Word Relr;
+typedef Elf32_Sword Sword;
+#define ELF_BITS 32
+#define ELF_R_TYPE ELF32_R_TYPE
+#define ELF_R_SYM ELF32_R_SYM
+#define ELF_CLASS_VALUE ELFCLASS32
+#elif SB_HAS(64_BIT_POINTERS)
+typedef Elf64_Ehdr Ehdr;
+typedef Elf64_Phdr Phdr;
+typedef Elf64_Addr Addr;
+typedef Elf64_Dyn Dyn;
+typedef Elf64_Word Word;
+typedef Elf64_Sym Sym;
+typedef Elf64_Rel Rel;
+typedef Elf64_Rela Rela;
+typedef Elf64_Word Relr;
+typedef Elf64_Sword Sword;
+#define ELF_BITS 64
+#define ELF_R_TYPE ELF64_R_TYPE
+#define ELF_R_SYM ELF64_R_SYM
+#define ELF_CLASS_VALUE ELFCLASS64
+#else
+#error "Unsupported pointer size"
+#endif
+
+#define ELF32_R_SYM(val) ((val) >> 8)
+#define ELF32_R_TYPE(val) ((val)&0xff)
+#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type)&0xff))
+
+#define ELF64_R_SYM(i) ((i) >> 32)
+#define ELF64_R_TYPE(i) ((i)&0xffffffff)
+#define ELF64_R_INFO(sym, type) ((((Elf64_Xword)(sym)) << 32) + (type))
+
+#define ELFMAG "\177ELF"
+#define SELFMAG 4
+
+// TODO: Refactor the code to detect it at runtime
+// using DT_PLTREL.
+#if (SB_IS(ARCH_ARM) || SB_IS(ARCH_X86)) && SB_IS(64_BIT)
+#define USE_RELA
+#endif
+
+#if defined(USE_RELA)
+typedef Rela rel_t;
+#else
+typedef Rel rel_t;
+#endif
+
+#if SB_IS(ARCH_ARM) && SB_IS(32_BIT)
+#define ELF_MACHINE 40
+#elif SB_IS(ARCH_X86) && SB_IS(32_BIT)
+#define ELF_MACHINE 3
+#elif SB_IS(ARCH_X86) && SB_IS(64_BIT)
+#define ELF_MACHINE 62
+#elif SB_IS(ARCH_ARM) && SB_IS(64_BIT)
+#define ELF_MACHINE 183
+#else
+#error "Unsupported target CPU architecture"
+#endif
+
+// Segment types.
+typedef enum SegmentTypes {
+ // Unused segment.
+ PT_NULL = 0,
+
+ // Loadable segment.
+ PT_LOAD = 1,
+
+ // Dynamic linking information.
+ PT_DYNAMIC = 2,
+
+ // Interpreter pathname.
+ PT_INTERP = 3,
+
+ // Auxiliary information.
+ PT_NOTE = 4,
+
+ // Reserved.
+ PT_SHLIB = 5,
+
+ // The program header table itself.
+ PT_PHDR = 6,
+
+ // The thread-local storage template.
+ PT_TLS = 7
+} SegmentTypes;
+
+// Symbol bindings.
+typedef enum SymbolBindings {
+ // Local symbol, not visible outside obj file containing def
+ STB_LOCAL = 0,
+
+ // Global symbol, visible to all object files being combined
+ STB_GLOBAL = 1,
+
+ // Weak symbol, like global but lower-precedence
+ STB_WEAK = 2,
+
+ STB_GNU_UNIQUE = 10,
+
+ // Lowest operating system-specific binding type
+ STB_LOOS = 10,
+
+ // Highest operating system-specific binding type
+ STB_HIOS = 12,
+
+ // Lowest processor-specific binding type
+ STB_LOPROC = 13,
+
+ // Highest processor-specific binding type
+ STB_HIPROC = 15
+} SymbolBindings;
+
+#define ELF_ST_BIND(x) ((x) >> 4)
+#define ELF32_ST_BIND(x) ELF_ST_BIND(x)
+#define ELF64_ST_BIND(x) ELF_ST_BIND(x)
+
+#define PF_X (1 << 0)
+#define PF_W (1 << 1)
+#define PF_R (1 << 2)
+#define PF_MASKOS 0x0ff00000
+#define PF_MASKPROC 0xf0000000
+
+// Dynamic table tags.
+typedef enum DynamicTags {
+ DT_NULL = 0,
+ DT_NEEDED = 1,
+ DT_PLTRELSZ = 2,
+ DT_PLTGOT = 3,
+ DT_HASH = 4,
+ DT_STRTAB = 5,
+ DT_SYMTAB = 6,
+ DT_RELA = 7,
+ DT_RELASZ = 8,
+ DT_RELAENT = 9,
+ DT_STRSZ = 10,
+ DT_SYMENT = 11,
+ DT_INIT = 12,
+ DT_FINI = 13,
+ DT_SONAME = 14,
+ DT_RPATH = 15,
+ DT_SYMBOLIC = 16,
+ DT_REL = 17,
+ DT_RELSZ = 18,
+ DT_RELENT = 19,
+ DT_PLTREL = 20,
+ DT_DEBUG = 21,
+ DT_TEXTREL = 22,
+ DT_JMPREL = 23,
+ DT_BIND_NOW = 24,
+ DT_INIT_ARRAY = 25,
+ DT_FINI_ARRAY = 26,
+ DT_INIT_ARRAYSZ = 27,
+ DT_FINI_ARRAYSZ = 28,
+ DT_RUNPATH = 29,
+ DT_FLAGS = 30,
+ DT_ENCODING = 32,
+ DT_PREINIT_ARRAY = 32,
+ DT_PREINIT_ARRAYSZ = 33,
+ DT_SYMTAB_SHNDX = 34,
+ DT_RELRSZ = 35,
+ DT_RELR = 36,
+ DT_RELRENT = 37,
+ DT_LOOS = 0x6000000D,
+ DT_ANDROID_REL = 0x6000000F,
+ DT_ANDROID_RELSZ = 0x60000010,
+ DT_ANDROID_RELA = 0x60000011,
+ DT_ANDROID_RELASZ = 0x60000012,
+ DT_HIOS = 0x6ffff000,
+ DT_ANDROID_RELR = 0x6fffe000,
+ DT_ANDROID_RELRSZ = 0x6fffe001,
+ DT_ANDROID_RELRENT = 0x6fffe003,
+ DT_GNU_HASH = 0x6ffffef5,
+ DT_LOPROC = 0x70000000,
+ DT_HIPROC = 0x7fffffff,
+} DynamicTags;
+
+typedef enum DynamicFlags {
+ // This flag signifies that the object being loaded may make reference to the
+ DF_ORIGIN = 0x00000001,
+
+ // If this flag is set in a shared object library, the dynamic linker's symbol
+ // resolution algorithm for references within the library is changed. Instead
+ // of starting a symbol search with the executable file, the dynamic linker
+ // starts from the shared object itself. If the shared object fails to supply
+ // the referenced symbol, the dynamic linker then searches the executable file
+ // and other shared objects as usual.
+ DF_SYMBOLIC = 0x00000002,
+
+ // This flag is not set, no relocation entry should cause a modification to a
+ // non-writable segment, as specified by the segment permissions in the
+ // program header table.
+ DF_TEXTREL = 0x00000004,
+
+ // If set in a shared object or executable, this flag instructs the dynamic
+ // linker to process all relocations for the object containing this entry
+ // before transferring control to the program.
+ DF_BIND_NOW = 0x00000008,
+
+ // If set in a shared object or executable, this flag instructs the dynamic
+ // linker to reject attempts to load this file dynamically. It indicates that
+ // the shared object or executable contains code using a static thread-local
+ // storage scheme. Implementations need not support any form of thread-local
+ // storage.
+ DF_STATIC_TLS = 0x00000010,
+} DynamicFalgs;
+
+// Relocation types per CPU architecture
+#if SB_IS(ARCH_ARM) && SB_IS(32_BIT)
+typedef enum RelocationTypes {
+ R_ARM_ABS32 = 2,
+ R_ARM_REL32 = 3,
+ R_ARM_GLOB_DAT = 21,
+ R_ARM_JUMP_SLOT = 22,
+ R_ARM_COPY = 20,
+ R_ARM_RELATIVE = 23,
+} RelocationTypes;
+#elif SB_IS(ARCH_ARM) && SB_IS(64_BIT)
+typedef enum RelocationTypes {
+ R_AARCH64_ABS64 = 257,
+ R_AARCH64_COPY = 1024,
+ R_AARCH64_GLOB_DAT = 1025,
+ R_AARCH64_JUMP_SLOT = 1026,
+ R_AARCH64_RELATIVE = 1027,
+} RelocationTypes;
+#elif SB_IS(ARCH_X86) && SB_IS(32_BIT)
+typedef enum RelocationTypes {
+ R_386_32 = 1,
+ R_386_PC32 = 2,
+ R_386_GLOB_DAT = 6,
+ R_386_JMP_SLOT = 7,
+ R_386_RELATIVE = 8,
+} RelocationTypes;
+#elif SB_IS(ARCH_X86) && SB_IS(64_BIT)
+typedef enum RelocationTypes {
+ R_X86_64_64 = 1,
+ R_X86_64_PC32 = 2,
+ R_X86_64_GLOB_DAT = 6,
+ R_X86_64_JMP_SLOT = 7,
+ R_X86_64_RELATIVE = 8,
+} RelocationTypes;
+#else
+#error "Unsupported architecture for relocations."
+#endif
+
+// Helper macros for memory page computations.
+#ifndef PAGE_SIZE
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1UL << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+#endif
+
+#define PAGE_START(x) ((x)&PAGE_MASK)
+#define PAGE_OFFSET(x) ((x) & ~PAGE_MASK)
+#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE - 1))
+
+#define SHN_UNDEF 0
+
+} // namespace elf_loader
+} // namespace starboard
+#endif // STARBOARD_ELF_LOADER_ELF_H_
diff --git a/src/starboard/elf_loader/elf_hash_table.cc b/src/starboard/elf_loader/elf_hash_table.cc
new file mode 100644
index 0000000..b6b6c70
--- /dev/null
+++ b/src/starboard/elf_loader/elf_hash_table.cc
@@ -0,0 +1,69 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/elf_hash_table.h"
+#include "starboard/string.h"
+
+namespace starboard {
+namespace elf_loader {
+
+// Compute the ELF hash of a given symbol.
+// Defined in
+// https://refspecs.linuxfoundation.org/elf/gabi4+/ch5.dynamic.html#hash
+static unsigned ElfHash(const char* name) {
+ const uint8_t* ptr = reinterpret_cast<const uint8_t*>(name);
+ unsigned h = 0;
+ while (*ptr) {
+ h = (h << 4) + *ptr++;
+ unsigned g = h & 0xf0000000;
+ h ^= g;
+ h ^= g >> 24;
+ }
+ return h;
+}
+
+ElfHashTable::ElfHashTable()
+ : hash_bucket_(NULL),
+ hash_bucket_size_(0),
+ hash_chain_(NULL),
+ hash_chain_size_(0) {}
+void ElfHashTable::Init(uintptr_t dt_elf_hash) {
+ const Word* data = reinterpret_cast<const Word*>(dt_elf_hash);
+ hash_bucket_size_ = data[0];
+ hash_bucket_ = data + 2;
+ hash_chain_size_ = data[1];
+ hash_chain_ = hash_bucket_ + hash_bucket_size_;
+}
+
+bool ElfHashTable::IsValid() const {
+ return hash_bucket_size_ > 0;
+}
+
+const Sym* ElfHashTable::LookupByName(const char* symbol_name,
+ const Sym* symbol_table,
+ const char* string_table) const {
+ unsigned hash = ElfHash(symbol_name);
+
+ for (unsigned n = hash_bucket_[hash % hash_bucket_size_]; n != 0;
+ n = hash_chain_[n]) {
+ const Sym* symbol = &symbol_table[n];
+ // Check that the symbol has the appropriate name.
+ if (!SbStringCompareAll(string_table + symbol->st_name, symbol_name))
+ return symbol;
+ }
+ return NULL;
+}
+
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/elf_hash_table.h b/src/starboard/elf_loader/elf_hash_table.h
new file mode 100644
index 0000000..14bb9ca
--- /dev/null
+++ b/src/starboard/elf_loader/elf_hash_table.h
@@ -0,0 +1,62 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef STARBOARD_ELF_LOADER_ELF_HASH_TABLE_H_
+#define STARBOARD_ELF_LOADER_ELF_HASH_TABLE_H_
+
+#include <stddef.h>
+#include "starboard/elf_loader/elf.h"
+
+namespace starboard {
+namespace elf_loader {
+
+// Models the hash table used to map symbol names to symbol entries using
+// the standard ELF format.
+class ElfHashTable {
+ public:
+ ElfHashTable();
+ // Initialize instance. |dt_elf_hash| should be the address that the
+ // DT_HASH entry points to in the input ELF dynamic section. Call IsValid()
+ // to determine whether the table was well-formed.
+ void Init(uintptr_t dt_elf_hash);
+
+ // Returns true iff the content of the table is valid.
+ bool IsValid() const;
+
+ // Index of the first dynamic symbol within the ELF symbol table.
+ size_t dyn_symbols_offset() const { return 1; }
+
+ // Number of dynamic symbols in the ELF symbol table.
+ size_t dyn_symbols_count() const { return hash_chain_size_ - 1; }
+
+ // Lookup |symbol_name| in the table. |symbol_table| should point to the
+ // ELF symbol table, and |string_table| to the start of its string table.
+ // Returns NULL on failure.
+ const Sym* LookupByName(const char* symbol_name,
+ const Sym* symbol_table,
+ const char* string_table) const;
+
+ private:
+ const Word* hash_bucket_;
+ size_t hash_bucket_size_;
+ const Word* hash_chain_;
+ size_t hash_chain_size_;
+
+ SB_DISALLOW_COPY_AND_ASSIGN(ElfHashTable);
+};
+
+} // namespace elf_loader
+} // namespace starboard
+
+#endif // STARBOARD_ELF_LOADER_ELF_HASH_TABLE_H_
diff --git a/src/starboard/elf_loader/elf_header.cc b/src/starboard/elf_loader/elf_header.cc
new file mode 100644
index 0000000..bb3c07b
--- /dev/null
+++ b/src/starboard/elf_loader/elf_header.cc
@@ -0,0 +1,75 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/elf_header.h"
+
+#include "starboard/common/log.h"
+#include "starboard/memory.h"
+
+namespace starboard {
+namespace elf_loader {
+
+ElfHeader::ElfHeader() {
+ elf_header_.reset(new Ehdr());
+}
+
+bool ElfHeader::LoadElfHeader(File* file) {
+ SB_LOG(INFO) << "LoadElfHeader";
+ if (!file->ReadFromOffset(0, reinterpret_cast<char*>(elf_header_.get()),
+ sizeof(Ehdr))) {
+ SB_LOG(ERROR) << "Failed to read file";
+ return false;
+ }
+
+ if (SbMemoryCompare(elf_header_->e_ident, ELFMAG, SELFMAG) != 0) {
+ SB_LOG(ERROR) << "Bad ELF magic: " << elf_header_->e_ident;
+ return false;
+ }
+
+ if (elf_header_->e_ident[EI_CLASS] != ELF_CLASS_VALUE) {
+ SB_LOG(ERROR) << "Not a " << ELF_BITS
+ << "-bit class: " << elf_header_->e_ident[EI_CLASS];
+ return false;
+ }
+ if (elf_header_->e_ident[EI_DATA] != ELFDATA2LSB) {
+ SB_LOG(ERROR) << "Not little-endian class" << elf_header_->e_ident[EI_DATA];
+ return false;
+ }
+
+ if (elf_header_->e_type != ET_DYN) {
+ SB_LOG(ERROR) << "Not a shared library type:" << std::hex
+ << elf_header_->e_type;
+ return false;
+ }
+
+ if (elf_header_->e_version != EV_CURRENT) {
+ SB_LOG(ERROR) << "Unexpected ELF version: " << elf_header_->e_version;
+ return false;
+ }
+
+ if (elf_header_->e_machine != ELF_MACHINE) {
+ SB_LOG(ERROR) << "Unexpected ELF machine type: " << std::hex
+ << elf_header_->e_machine;
+ return false;
+ }
+
+ return true;
+}
+
+const Ehdr* ElfHeader::GetHeader() {
+ return elf_header_.get();
+}
+
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/elf_header.h b/src/starboard/elf_loader/elf_header.h
new file mode 100644
index 0000000..a8b666c
--- /dev/null
+++ b/src/starboard/elf_loader/elf_header.h
@@ -0,0 +1,45 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef STARBOARD_ELF_LOADER_ELF_HEADER_H_
+#define STARBOARD_ELF_LOADER_ELF_HEADER_H_
+
+#include "starboard/elf_loader/elf.h"
+
+#include "starboard/common/scoped_ptr.h"
+#include "starboard/elf_loader/file.h"
+
+namespace starboard {
+namespace elf_loader {
+
+// Class for loading, parsing and validating the ELF header section.
+class ElfHeader {
+ public:
+ ElfHeader();
+
+ // Load, parse and validate the ELF header.
+ bool LoadElfHeader(File* file);
+
+ // Get the actual header data.
+ const Ehdr* GetHeader();
+
+ private:
+ scoped_ptr<Ehdr> elf_header_;
+ SB_DISALLOW_COPY_AND_ASSIGN(ElfHeader);
+};
+
+} // namespace elf_loader
+} // namespace starboard
+
+#endif // STARBOARD_ELF_LOADER_ELF_HEADER_H_
diff --git a/src/starboard/elf_loader/elf_header_test.cc b/src/starboard/elf_loader/elf_header_test.cc
new file mode 100644
index 0000000..c129af7
--- /dev/null
+++ b/src/starboard/elf_loader/elf_header_test.cc
@@ -0,0 +1,125 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/elf_header.h"
+
+#include "starboard/common/scoped_ptr.h"
+#include "starboard/elf_loader/file.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace elf_loader {
+
+namespace {
+
+class DummyFile : public File {
+ public:
+ DummyFile(const char* buffer, int size) : buffer_(buffer), size_(size) {}
+
+ bool Open(const char* name) { return true; }
+ bool ReadFromOffset(int64_t offset, char* buffer, int size) {
+ SB_LOG(INFO) << "ReadFromOffset";
+ if (offset != 0) {
+ SB_LOG(ERROR) << "ReadFromOffset: Invalid offset " << offset;
+ return false;
+ }
+ if (size < size_) {
+ SB_LOG(ERROR) << "ReadFromOffset: Invalid size " << size;
+ return false;
+ }
+ SbMemoryCopy(buffer, buffer_, size);
+ return true;
+ }
+ void Close() {}
+
+ private:
+ const char* buffer_;
+ int size_;
+};
+
+class ElfHeaderTest : public ::testing::Test {
+ protected:
+ ElfHeaderTest() {
+ elf_header_.reset(new ElfHeader());
+ SbMemorySet(reinterpret_cast<char*>(&ehdr_data_), 0, sizeof(ehdr_data_));
+ ehdr_data_.e_machine = ELF_MACHINE;
+ ehdr_data_.e_ident[0] = 0x7F;
+ ehdr_data_.e_ident[1] = 'E';
+ ehdr_data_.e_ident[2] = 'L';
+ ehdr_data_.e_ident[3] = 'F';
+ ehdr_data_.e_ident[EI_CLASS] = ELF_CLASS_VALUE;
+ ehdr_data_.e_ident[EI_DATA] = ELFDATA2LSB;
+ ehdr_data_.e_type = ET_DYN;
+ ehdr_data_.e_version = EV_CURRENT;
+ ehdr_data_.e_machine = ELF_MACHINE;
+
+ dummy_file_.reset(new DummyFile(reinterpret_cast<const char*>(&ehdr_data_),
+ sizeof(ehdr_data_)));
+ }
+ ~ElfHeaderTest() {}
+
+ scoped_ptr<ElfHeader> elf_header_;
+ Ehdr ehdr_data_;
+ scoped_ptr<DummyFile> dummy_file_;
+};
+
+TEST_F(ElfHeaderTest, Initialize) {
+ EXPECT_TRUE(elf_header_->LoadElfHeader(dummy_file_.get()));
+}
+
+TEST_F(ElfHeaderTest, NegativeBadImage) {
+ ehdr_data_.e_ident[1] = 'F';
+ dummy_file_.reset(new DummyFile(reinterpret_cast<const char*>(&ehdr_data_),
+ sizeof(ehdr_data_)));
+ EXPECT_FALSE(elf_header_->LoadElfHeader(dummy_file_.get()));
+}
+
+TEST_F(ElfHeaderTest, NegativeBadClass) {
+ ehdr_data_.e_ident[EI_CLASS] = 0;
+ dummy_file_.reset(new DummyFile(reinterpret_cast<const char*>(&ehdr_data_),
+ sizeof(ehdr_data_)));
+ EXPECT_FALSE(elf_header_->LoadElfHeader(dummy_file_.get()));
+}
+
+TEST_F(ElfHeaderTest, NegativeWrongGulliverLilliput) {
+ ehdr_data_.e_type = 2;
+ dummy_file_.reset(new DummyFile(reinterpret_cast<const char*>(&ehdr_data_),
+ sizeof(ehdr_data_)));
+ EXPECT_FALSE(elf_header_->LoadElfHeader(dummy_file_.get()));
+}
+
+TEST_F(ElfHeaderTest, NegativeBadType) {
+ ehdr_data_.e_type = 2;
+ dummy_file_.reset(new DummyFile(reinterpret_cast<const char*>(&ehdr_data_),
+ sizeof(ehdr_data_)));
+ EXPECT_FALSE(elf_header_->LoadElfHeader(dummy_file_.get()));
+}
+
+TEST_F(ElfHeaderTest, NegativeBadVersion) {
+ ehdr_data_.e_version = 2;
+ dummy_file_.reset(new DummyFile(reinterpret_cast<const char*>(&ehdr_data_),
+ sizeof(ehdr_data_)));
+ EXPECT_FALSE(elf_header_->LoadElfHeader(dummy_file_.get()));
+}
+
+TEST_F(ElfHeaderTest, NegativeBadMachine) {
+ ehdr_data_.e_machine = 0;
+ dummy_file_.reset(new DummyFile(reinterpret_cast<const char*>(&ehdr_data_),
+ sizeof(ehdr_data_)));
+ EXPECT_FALSE(elf_header_->LoadElfHeader(dummy_file_.get()));
+}
+} // namespace
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/elf_loader.cc b/src/starboard/elf_loader/elf_loader.cc
new file mode 100644
index 0000000..d62d07a
--- /dev/null
+++ b/src/starboard/elf_loader/elf_loader.cc
@@ -0,0 +1,38 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/elf_loader.h"
+#include "starboard/common/log.h"
+#include "starboard/elf_loader/elf_loader_impl.h"
+#include "starboard/elf_loader/file_impl.h"
+
+namespace starboard {
+namespace elf_loader {
+
+ElfLoader::~ElfLoader() {}
+
+bool ElfLoader::Load(const char* file_name) {
+ return impl_->Load(file_name);
+}
+
+void* ElfLoader::LookupSymbol(const char* symbol) {
+ return impl_->LookupSymbol(symbol);
+}
+
+ElfLoader::ElfLoader() {
+ impl_.reset(new ElfLoaderImpl());
+}
+
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/elf_loader.gyp b/src/starboard/elf_loader/elf_loader.gyp
new file mode 100644
index 0000000..7860e03
--- /dev/null
+++ b/src/starboard/elf_loader/elf_loader.gyp
@@ -0,0 +1,84 @@
+# Copyright 2019 The Cobalt Authors. All Rights Reserved.
+#
+# 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'elf_loader',
+ 'type': 'static_library',
+ 'include_dirs': [
+ 'src/include',
+ 'src/src/',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/starboard/starboard.gyp:starboard',
+ ],
+ 'sources': [
+ 'elf_header.h',
+ 'elf_header.cc',
+ 'elf_hash_table.h',
+ 'elf_hash_table.cc',
+ 'elf_loader.h',
+ 'elf_loader.cc',
+ 'elf_loader_impl.h',
+ 'elf_loader_impl.cc',
+ 'exported_symbols.cc',
+ 'file.h',
+ 'file_impl.h',
+ 'file_impl.cc',
+ 'gnu_hash_table.h',
+ 'gnu_hash_table.cc',
+ 'dynamic_section.h',
+ 'dynamic_section.cc',
+ 'program_table.h',
+ 'program_table.cc',
+ 'relocations.h',
+ 'relocations.cc',
+ ],
+ },
+ {
+ 'target_name': 'elf_loader_sandbox',
+ 'type': '<(final_executable_type)',
+ 'include_dirs': [
+ 'src/include',
+ 'src/src/',
+ ],
+ 'dependencies': [
+ 'elf_loader',
+ '<(DEPTH)/starboard/starboard.gyp:starboard_full',
+ ],
+ 'sources': [
+ 'sandbox.cc',
+ ],
+ },
+ {
+ 'target_name': 'elf_loader_test',
+ 'type': '<(gtest_target_type)',
+ 'sources': [
+ '<(DEPTH)/starboard/common/test_main.cc',
+ 'elf_loader_test.cc',
+ 'elf_header_test.cc',
+ 'dynamic_section_test.cc',
+ 'program_table_test.cc',
+ 'relocations_test.cc',
+ ],
+ 'dependencies': [
+ 'elf_loader',
+ '<(DEPTH)/starboard/starboard.gyp:starboard_full',
+ '<(DEPTH)/testing/gmock.gyp:gmock',
+ '<(DEPTH)/testing/gtest.gyp:gtest',
+ ],
+ },
+ ]
+}
diff --git a/src/starboard/elf_loader/elf_loader.h b/src/starboard/elf_loader/elf_loader.h
new file mode 100644
index 0000000..7bda25d
--- /dev/null
+++ b/src/starboard/elf_loader/elf_loader.h
@@ -0,0 +1,47 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef STARBOARD_ELF_LOADER_ELF_LOADER_H_
+#define STARBOARD_ELF_LOADER_ELF_LOADER_H_
+
+#include "starboard/common/scoped_ptr.h"
+
+namespace starboard {
+namespace elf_loader {
+
+class ElfLoaderImpl;
+
+// A loader for ELF dynamic shared library.
+class ElfLoader {
+ public:
+ ElfLoader();
+
+ // Loads the shared library
+ bool Load(const char* file_name);
+
+ // Looks up the symbol address in the
+ // shared library.
+ void* LookupSymbol(const char* symbol);
+
+ ~ElfLoader();
+
+ private:
+ scoped_ptr<ElfLoaderImpl> impl_;
+
+ SB_DISALLOW_COPY_AND_ASSIGN(ElfLoader);
+};
+
+} // namespace elf_loader
+} // namespace starboard
+#endif // STARBOARD_ELF_LOADER_ELF_LOADER_H_
diff --git a/src/starboard/elf_loader/elf_loader_impl.cc b/src/starboard/elf_loader/elf_loader_impl.cc
new file mode 100644
index 0000000..f81db05
--- /dev/null
+++ b/src/starboard/elf_loader/elf_loader_impl.cc
@@ -0,0 +1,136 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/elf_loader_impl.h"
+#include "starboard/common/log.h"
+#include "starboard/elf_loader/elf.h"
+#include "starboard/elf_loader/file_impl.h"
+#include "starboard/memory.h"
+#include "starboard/string.h"
+
+namespace starboard {
+namespace elf_loader {
+
+ElfLoaderImpl::ElfLoaderImpl() {}
+
+bool ElfLoaderImpl::Load(const char* name) {
+ SB_LOG(INFO) << "Loading: " << name;
+ elf_file_.reset(new FileImpl());
+ elf_file_->Open(name);
+
+ elf_header_loader_.reset(new ElfHeader());
+ if (!elf_header_loader_->LoadElfHeader(elf_file_.get())) {
+ SB_LOG(ERROR) << "Failed to loaded ELF header";
+ return false;
+ }
+
+ SB_LOG(INFO) << "Loaded ELF header";
+
+ program_table_.reset(new ProgramTable());
+ program_table_->LoadProgramHeader(elf_header_loader_->GetHeader(),
+ elf_file_.get());
+
+ SB_LOG(INFO) << "Loaded Program header";
+
+ if (!program_table_->ReserveLoadMemory()) {
+ SB_LOG(ERROR) << "Failed to reserve memory space";
+ return false;
+ }
+
+ SB_LOG(INFO) << "Reserved address space";
+
+ if (!program_table_->LoadSegments(elf_file_.get())) {
+ SB_LOG(ERROR) << "Failed to load segments";
+ return false;
+ }
+ SB_LOG(INFO) << "Loaded segments";
+
+ Dyn* dynamic = NULL;
+ size_t dynamic_count = 0;
+ Word dynamic_flags = 0;
+ program_table_->GetDynamicSection(&dynamic, &dynamic_count, &dynamic_flags);
+ if (!dynamic) {
+ SB_LOG(ERROR) << "No PT_DYNAMIC section!";
+ return false;
+ }
+ dynamic_section_.reset(
+ new DynamicSection(program_table_->GetBaseMemoryAddress(), dynamic,
+ dynamic_count, dynamic_flags));
+ if (!dynamic_section_->InitDynamicSection()) {
+ SB_LOG(ERROR) << "Failed to initialize dynamic section";
+ return false;
+ }
+ SB_LOG(INFO) << "Initialized dynamic section";
+ if (!dynamic_section_->InitDynamicSymbols()) {
+ SB_LOG(ERROR) << "Failed to load dynamic symbols";
+ return false;
+ }
+ SB_LOG(INFO) << "Initialized dynamic symbols";
+
+ exported_symbols_.reset(new ExportedSymbols());
+ relocations_.reset(new Relocations(program_table_->GetBaseMemoryAddress(),
+ dynamic_section_.get(),
+ exported_symbols_.get()));
+ if (!relocations_->InitRelocations()) {
+ SB_LOG(ERROR) << "Failed to initialize relocations";
+ return false;
+ }
+ if (relocations_->HasTextRelocations()) {
+ SB_LOG(INFO) << "HasTextRelocations";
+ // Adjust the memory protection to its to allow modifications.
+ if (program_table_->AdjustMemoryProtectionOfReadOnlySegments(
+ kSbMemoryMapProtectWrite) < 0) {
+ SB_LOG(ERROR) << "Unable to make segments writable";
+ return false;
+ }
+ }
+ SB_LOG(INFO) << "Loaded relocations";
+ if (!relocations_->ApplyAllRelocations()) {
+ SB_LOG(ERROR) << "Failed to apply relocations";
+ return false;
+ }
+
+ if (relocations_->HasTextRelocations()) {
+ // Restores the memory protection to its original state.
+ if (program_table_->AdjustMemoryProtectionOfReadOnlySegments(
+ kSbMemoryMapProtectReserved) < 0) {
+ SB_LOG(ERROR) << "Unable to restore segment protection";
+ return false;
+ }
+ }
+
+ SB_LOG(INFO) << "Applied relocations";
+
+ SB_LOG(INFO) << "Call constructors";
+ dynamic_section_->CallConstructors();
+
+ SB_LOG(INFO) << "Finished loading";
+
+ return true;
+}
+void* ElfLoaderImpl::LookupSymbol(const char* symbol) {
+ const Sym* sym = dynamic_section_->LookupByName(symbol);
+ void* address = NULL;
+ if (sym) {
+ address = reinterpret_cast<void*>(program_table_->GetBaseMemoryAddress() +
+ sym->st_value);
+ }
+ return address;
+}
+
+ElfLoaderImpl::~ElfLoaderImpl() {
+ dynamic_section_->CallDestructors();
+}
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/elf_loader_impl.h b/src/starboard/elf_loader/elf_loader_impl.h
new file mode 100644
index 0000000..b317ecf
--- /dev/null
+++ b/src/starboard/elf_loader/elf_loader_impl.h
@@ -0,0 +1,53 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef STARBOARD_ELF_LOADER_ELF_LOADER_IMPL_H_
+#define STARBOARD_ELF_LOADER_ELF_LOADER_IMPL_H_
+
+#include "starboard/common/scoped_ptr.h"
+#include "starboard/elf_loader/dynamic_section.h"
+#include "starboard/elf_loader/elf.h"
+#include "starboard/elf_loader/elf_hash_table.h"
+#include "starboard/elf_loader/elf_header.h"
+#include "starboard/elf_loader/exported_symbols.h"
+#include "starboard/elf_loader/file.h"
+#include "starboard/elf_loader/gnu_hash_table.h"
+#include "starboard/elf_loader/program_table.h"
+#include "starboard/elf_loader/relocations.h"
+
+namespace starboard {
+namespace elf_loader {
+
+// Implementation of the elf loader.
+class ElfLoaderImpl {
+ public:
+ ElfLoaderImpl();
+ bool Load(const char* file_name);
+ void* LookupSymbol(const char* symbol);
+ ~ElfLoaderImpl();
+
+ private:
+ scoped_ptr<File> elf_file_;
+ scoped_ptr<ElfHeader> elf_header_loader_;
+ scoped_ptr<ProgramTable> program_table_;
+ scoped_ptr<DynamicSection> dynamic_section_;
+ scoped_ptr<ExportedSymbols> exported_symbols_;
+ scoped_ptr<Relocations> relocations_;
+
+ SB_DISALLOW_COPY_AND_ASSIGN(ElfLoaderImpl);
+};
+
+} // namespace elf_loader
+} // namespace starboard
+#endif // STARBOARD_ELF_LOADER_ELF_LOADER_IMPL_H_
diff --git a/src/starboard/elf_loader/elf_loader_test.cc b/src/starboard/elf_loader/elf_loader_test.cc
new file mode 100644
index 0000000..d3351f3
--- /dev/null
+++ b/src/starboard/elf_loader/elf_loader_test.cc
@@ -0,0 +1,38 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/elf_loader_impl.h"
+
+#include "starboard/common/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace elf_loader {
+
+namespace {
+
+// TODO: implement using real shared library fro the file system.
+class ElfLoaderTest : public ::testing::Test {
+ protected:
+ ElfLoaderTest() {}
+ ~ElfLoaderTest() {}
+};
+
+TEST_F(ElfLoaderTest, Initialize) {
+ EXPECT_TRUE(true);
+}
+
+} // namespace
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/exported_symbols.cc b/src/starboard/elf_loader/exported_symbols.cc
new file mode 100644
index 0000000..a4c4539
--- /dev/null
+++ b/src/starboard/elf_loader/exported_symbols.cc
@@ -0,0 +1,512 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/exported_symbols.h"
+
+// TODO: Remove these once the API leaks are fixed.
+//#define LOCAL_TEST_WITH_API_LEAKS
+#ifdef LOCAL_TEST_WITH_API_LEAKS
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <nl_types.h>
+#include <setjmp.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include "starboard/accessibility.h"
+#include "starboard/audio_sink.h"
+#include "starboard/byte_swap.h"
+#include "starboard/character.h"
+#include "starboard/condition_variable.h"
+#include "starboard/cpu_features.h"
+#include "starboard/decode_target.h"
+#include "starboard/directory.h"
+#include "starboard/double.h"
+#include "starboard/egl.h"
+#include "starboard/event.h"
+#include "starboard/file.h"
+#include "starboard/gles.h"
+#include "starboard/image.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/microphone.h"
+#include "starboard/mutex.h"
+#include "starboard/once.h"
+#include "starboard/player.h"
+#include "starboard/socket.h"
+#include "starboard/socket_waiter.h"
+#include "starboard/speech_recognizer.h"
+#include "starboard/speech_synthesis.h"
+#include "starboard/storage.h"
+#include "starboard/string.h"
+#include "starboard/system.h"
+#include "starboard/thread.h"
+#include "starboard/time_zone.h"
+#include "starboard/ui_navigation.h"
+
+// TODO: cleanup these hack as we fix the API leaks
+
+void tmp_dl_iterate_phdr() {
+ SB_LOG(INFO) << "tmp_dl_iterate_phdr";
+}
+
+void tmp__cxa_thread_atexit_impl() {
+ SB_LOG(INFO) << "tmp__cxa_thread_atexit_impl";
+}
+
+namespace starboard {
+namespace elf_loader {
+
+ExportedSymbols::ExportedSymbols() {
+ map_["SbAccessibilityGetDisplaySettings"] =
+ reinterpret_cast<const void*>(SbAccessibilityGetDisplaySettings);
+ map_["SbAccessibilityGetTextToSpeechSettings"] =
+ reinterpret_cast<const void*>(SbAccessibilityGetTextToSpeechSettings);
+ map_["SbAudioSinkCreate"] = reinterpret_cast<const void*>(SbAudioSinkCreate);
+ map_["SbAudioSinkDestroy"] =
+ reinterpret_cast<const void*>(SbAudioSinkDestroy);
+ map_["SbAudioSinkGetNearestSupportedSampleFrequency"] =
+ reinterpret_cast<const void*>(
+ SbAudioSinkGetNearestSupportedSampleFrequency);
+ map_["SbAudioSinkIsAudioFrameStorageTypeSupported"] =
+ reinterpret_cast<const void*>(
+ SbAudioSinkIsAudioFrameStorageTypeSupported);
+ map_["SbAudioSinkIsAudioSampleTypeSupported"] =
+ reinterpret_cast<const void*>(SbAudioSinkIsAudioSampleTypeSupported);
+ map_["SbAudioSinkIsValid"] =
+ reinterpret_cast<const void*>(SbAudioSinkIsValid);
+ map_["SbByteSwapU16"] = reinterpret_cast<const void*>(SbByteSwapU16);
+ map_["SbByteSwapU32"] = reinterpret_cast<const void*>(SbByteSwapU32);
+ map_["SbByteSwapU64"] = reinterpret_cast<const void*>(SbByteSwapU64);
+ map_["SbCharacterIsDigit"] =
+ reinterpret_cast<const void*>(SbCharacterIsDigit);
+ map_["SbCharacterIsHexDigit"] =
+ reinterpret_cast<const void*>(SbCharacterIsHexDigit);
+ map_["SbCharacterIsSpace"] =
+ reinterpret_cast<const void*>(SbCharacterIsSpace);
+ map_["SbCharacterToLower"] =
+ reinterpret_cast<const void*>(SbCharacterToLower);
+ map_["SbCharacterToUpper"] =
+ reinterpret_cast<const void*>(SbCharacterToUpper);
+ map_["SbConditionVariableBroadcast"] =
+ reinterpret_cast<const void*>(SbConditionVariableBroadcast);
+ map_["SbConditionVariableCreate"] =
+ reinterpret_cast<const void*>(SbConditionVariableCreate);
+ map_["SbConditionVariableDestroy"] =
+ reinterpret_cast<const void*>(SbConditionVariableDestroy);
+ map_["SbConditionVariableSignal"] =
+ reinterpret_cast<const void*>(SbConditionVariableSignal);
+ map_["SbConditionVariableWait"] =
+ reinterpret_cast<const void*>(SbConditionVariableWait);
+ map_["SbConditionVariableWaitTimed"] =
+ reinterpret_cast<const void*>(SbConditionVariableWaitTimed);
+ map_["SbCPUFeaturesGet"] = reinterpret_cast<const void*>(SbCPUFeaturesGet);
+ map_["SbDecodeTargetGetInfo"] =
+ reinterpret_cast<const void*>(SbDecodeTargetGetInfo);
+ map_["SbDecodeTargetRelease"] =
+ reinterpret_cast<const void*>(SbDecodeTargetRelease);
+ map_["SbDirectoryCanOpen"] =
+ reinterpret_cast<const void*>(SbDirectoryCanOpen);
+ map_["SbDirectoryClose"] = reinterpret_cast<const void*>(SbDirectoryClose);
+ map_["SbDirectoryCreate"] = reinterpret_cast<const void*>(SbDirectoryCreate);
+ map_["SbDirectoryGetNext"] =
+ reinterpret_cast<const void*>(SbDirectoryGetNext);
+ map_["SbDirectoryOpen"] = reinterpret_cast<const void*>(SbDirectoryOpen);
+ map_["SbDoubleAbsolute"] = reinterpret_cast<const void*>(SbDoubleAbsolute);
+ map_["SbDoubleExponent"] = reinterpret_cast<const void*>(SbDoubleExponent);
+ map_["SbDoubleFloor"] = reinterpret_cast<const void*>(SbDoubleFloor);
+ map_["SbDoubleIsFinite"] = reinterpret_cast<const void*>(SbDoubleIsFinite);
+ map_["SbDoubleIsNan"] = reinterpret_cast<const void*>(SbDoubleIsNan);
+ map_["SbDrmCloseSession"] = reinterpret_cast<const void*>(SbDrmCloseSession);
+ map_["SbDrmCreateSystem"] = reinterpret_cast<const void*>(SbDrmCreateSystem);
+ map_["SbDrmDestroySystem"] =
+ reinterpret_cast<const void*>(SbDrmDestroySystem);
+ map_["SbDrmGenerateSessionUpdateRequest"] =
+ reinterpret_cast<const void*>(SbDrmGenerateSessionUpdateRequest);
+ map_["SbDrmIsServerCertificateUpdatable"] =
+ reinterpret_cast<const void*>(SbDrmIsServerCertificateUpdatable);
+ map_["SbDrmUpdateServerCertificate"] =
+ reinterpret_cast<const void*>(SbDrmUpdateServerCertificate);
+ map_["SbDrmUpdateSession"] =
+ reinterpret_cast<const void*>(SbDrmUpdateSession);
+ map_["SbEventCancel"] = reinterpret_cast<const void*>(SbEventCancel);
+ map_["SbEventSchedule"] = reinterpret_cast<const void*>(SbEventSchedule);
+ map_["SbFileCanOpen"] = reinterpret_cast<const void*>(SbFileCanOpen);
+ map_["SbFileClose"] = reinterpret_cast<const void*>(SbFileClose);
+ map_["SbFileDelete"] = reinterpret_cast<const void*>(SbFileDelete);
+ map_["SbFileExists"] = reinterpret_cast<const void*>(SbFileExists);
+ map_["SbFileFlush"] = reinterpret_cast<const void*>(SbFileFlush);
+ map_["SbFileGetInfo"] = reinterpret_cast<const void*>(SbFileGetInfo);
+ map_["SbFileGetPathInfo"] = reinterpret_cast<const void*>(SbFileGetPathInfo);
+ map_["SbFileModeStringToFlags"] =
+ reinterpret_cast<const void*>(SbFileModeStringToFlags);
+ map_["SbFileOpen"] = reinterpret_cast<const void*>(SbFileOpen);
+ map_["SbFileRead"] = reinterpret_cast<const void*>(SbFileRead);
+ map_["SbFileSeek"] = reinterpret_cast<const void*>(SbFileSeek);
+ map_["SbFileTruncate"] = reinterpret_cast<const void*>(SbFileTruncate);
+ map_["SbFileWrite"] = reinterpret_cast<const void*>(SbFileWrite);
+ map_["SbGetEglInterface"] = reinterpret_cast<const void*>(SbGetEglInterface);
+ map_["SbGetGlesInterface"] =
+ reinterpret_cast<const void*>(SbGetGlesInterface);
+ map_["SbImageDecode"] = reinterpret_cast<const void*>(SbImageDecode);
+ map_["SbImageIsDecodeSupported"] =
+ reinterpret_cast<const void*>(SbImageIsDecodeSupported);
+ map_["SbLog"] = reinterpret_cast<const void*>(SbLog);
+ map_["SbLogFlush"] = reinterpret_cast<const void*>(SbLogFlush);
+ map_["SbLogFormat"] = reinterpret_cast<const void*>(SbLogFormat);
+ map_["SbLogIsTty"] = reinterpret_cast<const void*>(SbLogIsTty);
+ map_["SbLogRaw"] = reinterpret_cast<const void*>(SbLogRaw);
+ map_["SbLogRawFormat"] = reinterpret_cast<const void*>(SbLogRawFormat);
+ map_["SbMediaCanPlayMimeAndKeySystem"] =
+ reinterpret_cast<const void*>(SbMediaCanPlayMimeAndKeySystem);
+ map_["SbMediaGetAudioBufferBudget"] =
+ reinterpret_cast<const void*>(SbMediaGetAudioBufferBudget);
+ map_["SbMediaGetBufferAlignment"] =
+ reinterpret_cast<const void*>(SbMediaGetBufferAlignment);
+ map_["SbMediaGetBufferAllocationUnit"] =
+ reinterpret_cast<const void*>(SbMediaGetBufferAllocationUnit);
+ map_["SbMediaGetBufferGarbageCollectionDurationThreshold"] =
+ reinterpret_cast<const void*>(
+ SbMediaGetBufferGarbageCollectionDurationThreshold);
+ map_["SbMediaGetBufferPadding"] =
+ reinterpret_cast<const void*>(SbMediaGetBufferPadding);
+ map_["SbMediaGetInitialBufferCapacity"] =
+ reinterpret_cast<const void*>(SbMediaGetInitialBufferCapacity);
+ map_["SbMediaGetMaxBufferCapacity"] =
+ reinterpret_cast<const void*>(SbMediaGetMaxBufferCapacity);
+ map_["SbMediaGetProgressiveBufferBudget"] =
+ reinterpret_cast<const void*>(SbMediaGetProgressiveBufferBudget);
+ map_["SbMediaGetVideoBufferBudget"] =
+ reinterpret_cast<const void*>(SbMediaGetVideoBufferBudget);
+ map_["SbMediaIsBufferPoolAllocateOnDemand"] =
+ reinterpret_cast<const void*>(SbMediaIsBufferPoolAllocateOnDemand);
+ map_["SbMediaIsBufferUsingMemoryPool"] =
+ reinterpret_cast<const void*>(SbMediaIsBufferUsingMemoryPool);
+ map_["SbMediaSetAudioWriteDuration"] =
+ reinterpret_cast<const void*>(SbMediaSetAudioWriteDuration);
+ map_["SbMemoryAllocateAlignedUnchecked"] =
+ reinterpret_cast<const void*>(SbMemoryAllocateAlignedUnchecked);
+ map_["SbMemoryAllocateUnchecked"] =
+ reinterpret_cast<const void*>(SbMemoryAllocateUnchecked);
+ map_["SbMemoryCompare"] = reinterpret_cast<const void*>(SbMemoryCompare);
+ map_["SbMemoryCopy"] = reinterpret_cast<const void*>(SbMemoryCopy);
+ map_["SbMemoryFindByte"] = reinterpret_cast<const void*>(SbMemoryFindByte);
+ map_["SbMemoryFree"] = reinterpret_cast<const void*>(SbMemoryFree);
+ map_["SbMemoryFreeAligned"] =
+ reinterpret_cast<const void*>(SbMemoryFreeAligned);
+ map_["SbMemoryMap"] = reinterpret_cast<const void*>(SbMemoryMap);
+ map_["SbMemoryMove"] = reinterpret_cast<const void*>(SbMemoryMove);
+ map_["SbMemoryProtect"] = reinterpret_cast<const void*>(SbMemoryProtect);
+ map_["SbMemoryReallocateUnchecked"] =
+ reinterpret_cast<const void*>(SbMemoryReallocateUnchecked);
+ map_["SbMemorySet"] = reinterpret_cast<const void*>(SbMemorySet);
+ map_["SbMemoryUnmap"] = reinterpret_cast<const void*>(SbMemoryUnmap);
+
+#if SB_HAS(MICROPHONE)
+ map_["SbMicrophoneClose"] = reinterpret_cast<const void*>(SbMicrophoneClose);
+ map_["SbMicrophoneCreate"] =
+ reinterpret_cast<const void*>(SbMicrophoneCreate);
+ map_["SbMicrophoneDestroy"] =
+ reinterpret_cast<const void*>(SbMicrophoneDestroy);
+ map_["SbMicrophoneGetAvailable"] =
+ reinterpret_cast<const void*>(SbMicrophoneGetAvailable);
+ map_["SbMicrophoneIsSampleRateSupported"] =
+ reinterpret_cast<const void*>(SbMicrophoneIsSampleRateSupported);
+ map_["SbMicrophoneOpen"] = reinterpret_cast<const void*>(SbMicrophoneOpen);
+ map_["SbMicrophoneRead"] = reinterpret_cast<const void*>(SbMicrophoneRead);
+#endif
+
+ map_["SbMutexAcquire"] = reinterpret_cast<const void*>(SbMutexAcquire);
+ map_["SbMutexAcquireTry"] = reinterpret_cast<const void*>(SbMutexAcquireTry);
+ map_["SbMutexCreate"] = reinterpret_cast<const void*>(SbMutexCreate);
+ map_["SbMutexDestroy"] = reinterpret_cast<const void*>(SbMutexDestroy);
+ map_["SbMutexRelease"] = reinterpret_cast<const void*>(SbMutexRelease);
+ map_["SbOnce"] = reinterpret_cast<const void*>(SbOnce);
+
+ map_["SbPlayerCreate"] = reinterpret_cast<const void*>(SbPlayerCreate);
+ map_["SbPlayerDestroy"] = reinterpret_cast<const void*>(SbPlayerDestroy);
+ map_["SbPlayerGetCurrentFrame"] =
+ reinterpret_cast<const void*>(SbPlayerGetCurrentFrame);
+ map_["SbPlayerGetInfo2"] = reinterpret_cast<const void*>(SbPlayerGetInfo2);
+ map_["SbPlayerGetMaximumNumberOfSamplesPerWrite"] =
+ reinterpret_cast<const void*>(SbPlayerGetMaximumNumberOfSamplesPerWrite);
+ map_["SbPlayerOutputModeSupported"] =
+ reinterpret_cast<const void*>(SbPlayerOutputModeSupported);
+ map_["SbPlayerSeek2"] = reinterpret_cast<const void*>(SbPlayerSeek2);
+ map_["SbPlayerSetBounds"] = reinterpret_cast<const void*>(SbPlayerSetBounds);
+ map_["SbPlayerSetPlaybackRate"] =
+ reinterpret_cast<const void*>(SbPlayerSetPlaybackRate);
+ map_["SbPlayerSetVolume"] = reinterpret_cast<const void*>(SbPlayerSetVolume);
+ map_["SbPlayerWriteEndOfStream"] =
+ reinterpret_cast<const void*>(SbPlayerWriteEndOfStream);
+ map_["SbPlayerWriteSample2"] =
+ reinterpret_cast<const void*>(SbPlayerWriteSample2);
+ map_["SbSocketAccept"] = reinterpret_cast<const void*>(SbSocketAccept);
+ map_["SbSocketBind"] = reinterpret_cast<const void*>(SbSocketBind);
+ map_["SbSocketClearLastError"] = reinterpret_cast<const void*>(SbSocketClearLastError);
+ map_["SbSocketConnect"] = reinterpret_cast<const void*>(SbSocketConnect);
+ map_["SbSocketCreate"] = reinterpret_cast<const void*>(SbSocketCreate);
+ map_["SbSocketDestroy"] = reinterpret_cast<const void*>(SbSocketDestroy);
+ map_["SbSocketFreeResolution"] =
+ reinterpret_cast<const void*>(SbSocketFreeResolution);
+ map_["SbSocketGetInterfaceAddress"] =
+ reinterpret_cast<const void*>(SbSocketGetInterfaceAddress);
+ map_["SbSocketGetLastError"] =
+ reinterpret_cast<const void*>(SbSocketGetLastError);
+ map_["SbSocketGetLocalAddress"] =
+ reinterpret_cast<const void*>(SbSocketGetLocalAddress);
+ map_["SbSocketIsConnected"] =
+ reinterpret_cast<const void*>(SbSocketIsConnected);
+ map_["SbSocketIsConnectedAndIdle"] =
+ reinterpret_cast<const void*>(SbSocketIsConnectedAndIdle);
+ map_["SbSocketJoinMulticastGroup"] =
+ reinterpret_cast<const void*>(SbSocketJoinMulticastGroup);
+ map_["SbSocketListen"] = reinterpret_cast<const void*>(SbSocketListen);
+ map_["SbSocketReceiveFrom"] =
+ reinterpret_cast<const void*>(SbSocketReceiveFrom);
+ map_["SbSocketResolve"] = reinterpret_cast<const void*>(SbSocketResolve);
+ map_["SbSocketSendTo"] = reinterpret_cast<const void*>(SbSocketSendTo);
+ map_["SbSocketSetBroadcast"] =
+ reinterpret_cast<const void*>(SbSocketSetBroadcast);
+ map_["SbSocketSetReceiveBufferSize"] =
+ reinterpret_cast<const void*>(SbSocketSetReceiveBufferSize);
+ map_["SbSocketSetReuseAddress"] =
+ reinterpret_cast<const void*>(SbSocketSetReuseAddress);
+ map_["SbSocketSetSendBufferSize"] =
+ reinterpret_cast<const void*>(SbSocketSetSendBufferSize);
+ map_["SbSocketSetTcpKeepAlive"] =
+ reinterpret_cast<const void*>(SbSocketSetTcpKeepAlive);
+ map_["SbSocketSetTcpNoDelay"] =
+ reinterpret_cast<const void*>(SbSocketSetTcpNoDelay);
+ map_["SbSocketSetTcpWindowScaling"] =
+ reinterpret_cast<const void*>(SbSocketSetTcpWindowScaling);
+ map_["SbSocketWaiterAdd"] = reinterpret_cast<const void*>(SbSocketWaiterAdd);
+ map_["SbSocketWaiterCreate"] =
+ reinterpret_cast<const void*>(SbSocketWaiterCreate);
+ map_["SbSocketWaiterDestroy"] =
+ reinterpret_cast<const void*>(SbSocketWaiterDestroy);
+ map_["SbSocketWaiterRemove"] =
+ reinterpret_cast<const void*>(SbSocketWaiterRemove);
+ map_["SbSocketWaiterWait"] =
+ reinterpret_cast<const void*>(SbSocketWaiterWait);
+ map_["SbSocketWaiterWaitTimed"] =
+ reinterpret_cast<const void*>(SbSocketWaiterWaitTimed);
+ map_["SbSocketWaiterWakeUp"] =
+ reinterpret_cast<const void*>(SbSocketWaiterWakeUp);
+
+#if SB_HAS(SPEECH_RECOGNIZER) && SB_API_VERSION >= 5
+ map_["SbSpeechRecognizerCreate"] =
+ reinterpret_cast<const void*>(SbSpeechRecognizerCreate);
+ map_["SbSpeechRecognizerDestroy"] =
+ reinterpret_cast<const void*>(SbSpeechRecognizerDestroy);
+ map_["SbSpeechRecognizerStart"] =
+ reinterpret_cast<const void*>(SbSpeechRecognizerStart);
+ map_["SbSpeechRecognizerStop"] =
+ reinterpret_cast<const void*>(SbSpeechRecognizerStop);
+ map_["SbSpeechSynthesisCancel"] =
+ reinterpret_cast<const void*>(SbSpeechSynthesisCancel);
+ map_["SbSpeechSynthesisSpeak"] =
+ reinterpret_cast<const void*>(SbSpeechSynthesisSpeak);
+#endif
+
+ map_["SbStorageCloseRecord"] =
+ reinterpret_cast<const void*>(SbStorageCloseRecord);
+ map_["SbStorageDeleteRecord"] =
+ reinterpret_cast<const void*>(SbStorageDeleteRecord);
+ map_["SbStorageGetRecordSize"] =
+ reinterpret_cast<const void*>(SbStorageGetRecordSize);
+ map_["SbStorageOpenRecord"] =
+ reinterpret_cast<const void*>(SbStorageOpenRecord);
+ map_["SbStorageReadRecord"] =
+ reinterpret_cast<const void*>(SbStorageReadRecord);
+ map_["SbStorageWriteRecord"] =
+ reinterpret_cast<const void*>(SbStorageWriteRecord);
+ map_["SbStringCompare"] = reinterpret_cast<const void*>(SbStringCompare);
+ map_["SbStringCompareAll"] =
+ reinterpret_cast<const void*>(SbStringCompareAll);
+ map_["SbStringCompareNoCase"] =
+ reinterpret_cast<const void*>(SbStringCompareNoCase);
+ map_["SbStringCompareNoCaseN"] =
+ reinterpret_cast<const void*>(SbStringCompareNoCaseN);
+ map_["SbStringConcat"] = reinterpret_cast<const void*>(SbStringConcat);
+ map_["SbStringCopy"] = reinterpret_cast<const void*>(SbStringCopy);
+ map_["SbStringDuplicate"] = reinterpret_cast<const void*>(SbStringDuplicate);
+ map_["SbStringFindCharacter"] =
+ reinterpret_cast<const void*>(SbStringFindCharacter);
+ map_["SbStringFindLastCharacter"] =
+ reinterpret_cast<const void*>(SbStringFindLastCharacter);
+ map_["SbStringFindString"] =
+ reinterpret_cast<const void*>(SbStringFindString);
+ map_["SbStringFormat"] = reinterpret_cast<const void*>(SbStringFormat);
+ map_["SbStringFormatWide"] =
+ reinterpret_cast<const void*>(SbStringFormatWide);
+ map_["SbStringGetLength"] = reinterpret_cast<const void*>(SbStringGetLength);
+ map_["SbStringParseDouble"] =
+ reinterpret_cast<const void*>(SbStringParseDouble);
+ map_["SbStringParseSignedInteger"] =
+ reinterpret_cast<const void*>(SbStringParseSignedInteger);
+ map_["SbStringParseUInt64"] =
+ reinterpret_cast<const void*>(SbStringParseUInt64);
+ map_["SbStringParseUnsignedInteger"] =
+ reinterpret_cast<const void*>(SbStringParseUnsignedInteger);
+ map_["SbStringScan"] = reinterpret_cast<const void*>(SbStringScan);
+ map_["SbSystemBinarySearch"] =
+ reinterpret_cast<const void*>(SbSystemBinarySearch);
+ map_["SbSystemBreakIntoDebugger"] =
+ reinterpret_cast<const void*>(SbSystemBreakIntoDebugger);
+ map_["SbSystemClearLastError"] =
+ reinterpret_cast<const void*>(SbSystemClearLastError);
+ map_["SbSystemGetConnectionType"] =
+ reinterpret_cast<const void*>(SbSystemGetConnectionType);
+ map_["SbSystemGetDeviceType"] =
+ reinterpret_cast<const void*>(SbSystemGetDeviceType);
+ map_["SbSystemGetErrorString"] =
+ reinterpret_cast<const void*>(SbSystemGetErrorString);
+ map_["SbSystemGetExtension"] =
+ reinterpret_cast<const void*>(SbSystemGetExtension);
+ map_["SbSystemGetLastError"] =
+ reinterpret_cast<const void*>(SbSystemGetLastError);
+ map_["SbSystemGetLocaleId"] =
+ reinterpret_cast<const void*>(SbSystemGetLocaleId);
+ map_["SbSystemGetNumberOfProcessors"] =
+ reinterpret_cast<const void*>(SbSystemGetNumberOfProcessors);
+ map_["SbSystemGetPath"] = reinterpret_cast<const void*>(SbSystemGetPath);
+ map_["SbSystemGetProperty"] =
+ reinterpret_cast<const void*>(SbSystemGetProperty);
+ map_["SbSystemGetRandomData"] =
+ reinterpret_cast<const void*>(SbSystemGetRandomData);
+ map_["SbSystemGetRandomUInt64"] =
+ reinterpret_cast<const void*>(SbSystemGetRandomUInt64);
+ map_["SbSystemGetStack"] = reinterpret_cast<const void*>(SbSystemGetStack);
+ map_["SbSystemGetTotalCPUMemory"] =
+ reinterpret_cast<const void*>(SbSystemGetTotalCPUMemory);
+ map_["SbSystemGetTotalGPUMemory"] =
+ reinterpret_cast<const void*>(SbSystemGetTotalGPUMemory);
+ map_["SbSystemGetUsedCPUMemory"] =
+ reinterpret_cast<const void*>(SbSystemGetUsedCPUMemory);
+ map_["SbSystemGetUsedGPUMemory"] =
+ reinterpret_cast<const void*>(SbSystemGetUsedGPUMemory);
+ map_["SbSystemHasCapability"] =
+ reinterpret_cast<const void*>(SbSystemHasCapability);
+ map_["SbSystemHideSplashScreen"] =
+ reinterpret_cast<const void*>(SbSystemHideSplashScreen);
+ map_["SbSystemIsDebuggerAttached"] =
+ reinterpret_cast<const void*>(SbSystemIsDebuggerAttached);
+ map_["SbSystemRaisePlatformError"] =
+ reinterpret_cast<const void*>(SbSystemRaisePlatformError);
+ map_["SbSystemRequestPause"] =
+ reinterpret_cast<const void*>(SbSystemRequestPause);
+ map_["SbSystemRequestStop"] =
+ reinterpret_cast<const void*>(SbSystemRequestStop);
+ map_["SbSystemRequestSuspend"] =
+ reinterpret_cast<const void*>(SbSystemRequestSuspend);
+ map_["SbSystemRequestUnpause"] =
+ reinterpret_cast<const void*>(SbSystemRequestUnpause);
+ map_["SbSystemSort"] = reinterpret_cast<const void*>(SbSystemSort);
+ map_["SbSystemSupportsResume"] =
+ reinterpret_cast<const void*>(SbSystemSupportsResume);
+ map_["SbSystemSymbolize"] = reinterpret_cast<const void*>(SbSystemSymbolize);
+ map_["SbThreadContextGetPointer"] =
+ reinterpret_cast<const void*>(SbThreadContextGetPointer);
+ map_["SbThreadCreate"] = reinterpret_cast<const void*>(SbThreadCreate);
+ map_["SbThreadCreateLocalKey"] =
+ reinterpret_cast<const void*>(SbThreadCreateLocalKey);
+ map_["SbThreadDestroyLocalKey"] =
+ reinterpret_cast<const void*>(SbThreadDestroyLocalKey);
+ map_["SbThreadDetach"] = reinterpret_cast<const void*>(SbThreadDetach);
+ map_["SbThreadGetCurrent"] =
+ reinterpret_cast<const void*>(SbThreadGetCurrent);
+ map_["SbThreadGetId"] = reinterpret_cast<const void*>(SbThreadGetId);
+ map_["SbThreadGetLocalValue"] =
+ reinterpret_cast<const void*>(SbThreadGetLocalValue);
+ map_["SbThreadIsEqual"] = reinterpret_cast<const void*>(SbThreadIsEqual);
+ map_["SbThreadJoin"] = reinterpret_cast<const void*>(SbThreadJoin);
+ map_["SbThreadSamplerCreate"] =
+ reinterpret_cast<const void*>(SbThreadSamplerCreate);
+ map_["SbThreadSamplerDestroy"] =
+ reinterpret_cast<const void*>(SbThreadSamplerDestroy);
+ map_["SbThreadSamplerFreeze"] =
+ reinterpret_cast<const void*>(SbThreadSamplerFreeze);
+ map_["SbThreadSamplerThaw"] =
+ reinterpret_cast<const void*>(SbThreadSamplerThaw);
+ map_["SbThreadSetLocalValue"] =
+ reinterpret_cast<const void*>(SbThreadSetLocalValue);
+ map_["SbThreadSetName"] = reinterpret_cast<const void*>(SbThreadSetName);
+ map_["SbThreadSleep"] = reinterpret_cast<const void*>(SbThreadSleep);
+ map_["SbThreadYield"] = reinterpret_cast<const void*>(SbThreadYield);
+ map_["SbTimeGetMonotonicNow"] =
+ reinterpret_cast<const void*>(SbTimeGetMonotonicNow);
+ map_["SbTimeGetMonotonicThreadNow"] =
+ reinterpret_cast<const void*>(SbTimeGetMonotonicThreadNow);
+ map_["SbTimeGetNow"] = reinterpret_cast<const void*>(SbTimeGetNow);
+ map_["SbTimeZoneGetCurrent"] =
+ reinterpret_cast<const void*>(SbTimeZoneGetCurrent);
+ map_["SbTimeZoneGetName"] = reinterpret_cast<const void*>(SbTimeZoneGetName);
+#if SB_API_VERSION >= SB_UI_NAVIGATION_VERSION
+ map_["SbUiNavGetInterface"] =
+ reinterpret_cast<const void*>(SbUiNavGetInterface);
+#endif
+ map_["SbUserGetCurrent"] = reinterpret_cast<const void*>(SbUserGetCurrent);
+ map_["SbUserGetProperty"] = reinterpret_cast<const void*>(SbUserGetProperty);
+ map_["SbUserGetPropertySize"] =
+ reinterpret_cast<const void*>(SbUserGetPropertySize);
+ map_["SbWindowCreate"] = reinterpret_cast<const void*>(SbWindowCreate);
+ map_["SbWindowDestroy"] = reinterpret_cast<const void*>(SbWindowDestroy);
+ map_["SbWindowGetDiagonalSizeInInches"] =
+ reinterpret_cast<const void*>(SbWindowGetDiagonalSizeInInches);
+ map_["SbWindowGetPlatformHandle"] =
+ reinterpret_cast<const void*>(SbWindowGetPlatformHandle);
+ map_["SbWindowGetSize"] = reinterpret_cast<const void*>(SbWindowGetSize);
+ map_["SbWindowSetDefaultOptions"] =
+ reinterpret_cast<const void*>(SbWindowSetDefaultOptions);
+#ifdef LOCAL_TEST_WITH_API_LEAKS
+ map_["atexit"] = reinterpret_cast<const void*>(atexit);
+ map_["btowc"] = reinterpret_cast<const void*>(btowc);
+ map_["__ctype_get_mb_cur_max"] =
+ map_["__cxa_thread_atexit_impl"] =
+ reinterpret_cast<const void*>(tmp__cxa_thread_atexit_impl);
+ map_["dladdr"] = reinterpret_cast<const void*>(dladdr);
+ map_["dl_iterate_phdr"] = reinterpret_cast<const void*>(tmp_dl_iterate_phdr);
+ map_["longjmp"] = reinterpret_cast<const void*>(longjmp);
+ map_["mbrlen"] = reinterpret_cast<const void*>(mbrlen);
+ map_["mbrtowc"] = reinterpret_cast<const void*>(mbrtowc);
+ map_["mbsnrtowcs"] = reinterpret_cast<const void*>(mbsnrtowcs);
+ map_["mbsrtowcs"] = reinterpret_cast<const void*>(mbsrtowcs);
+ map_["mbtowc"] = reinterpret_cast<const void*>(mbtowc);
+
+ map_["setjmp"] = reinterpret_cast<const void*>(setjmp);
+ map_["wcrtomb"] = reinterpret_cast<const void*>(wcrtomb);
+ map_["wcsnrtombs"] = reinterpret_cast<const void*>(wcsnrtombs);
+ map_["wcstod"] = reinterpret_cast<const void*>(wcstod);
+ map_["wcstof"] = reinterpret_cast<const void*>(wcstof);
+ map_["wcstol"] = reinterpret_cast<const void*>(wcstol);
+ map_["wcstold"] = reinterpret_cast<const void*>(wcstold);
+ map_["wcstoll"] = reinterpret_cast<const void*>(wcstoll);
+ map_["wcstoul"] = reinterpret_cast<const void*>(wcstoul);
+ map_["wcstoull"] = reinterpret_cast<const void*>(wcstoull);
+ map_["wcsxfrm_l"] = reinterpret_cast<const void*>(wcsxfrm_l);
+ map_["wctob"] = reinterpret_cast<const void*>(wctob);
+#endif
+}
+
+const void* ExportedSymbols::Lookup(const char* name) {
+ const void* ret = map_[name];
+ SB_CHECK(ret);
+ return ret;
+}
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/exported_symbols.h b/src/starboard/elf_loader/exported_symbols.h
new file mode 100644
index 0000000..a28c583
--- /dev/null
+++ b/src/starboard/elf_loader/exported_symbols.h
@@ -0,0 +1,46 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef STARBOARD_ELF_LOADER_EXPORTED_SYMBOLS_H_
+#define STARBOARD_ELF_LOADER_EXPORTED_SYMBOLS_H_
+
+#include <map>
+#include <string>
+
+#include "starboard/elf_loader/elf_hash_table.h"
+#include "starboard/elf_loader/gnu_hash_table.h"
+#include "starboard/file.h"
+
+namespace starboard {
+namespace elf_loader {
+
+// class representing all exported symbols
+// by the starboard layer.
+
+// The elf_loader will not use any other symbols
+// outside of the set represented in this class.
+class ExportedSymbols {
+ public:
+ ExportedSymbols();
+ const void* Lookup(const char* name);
+
+ private:
+ std::map<std::string, const void*> map_;
+
+ SB_DISALLOW_COPY_AND_ASSIGN(ExportedSymbols);
+};
+
+} // namespace elf_loader
+} // namespace starboard
+#endif // STARBOARD_ELF_LOADER_EXPORTED_SYMBOLS_H_
diff --git a/src/starboard/elf_loader/file.h b/src/starboard/elf_loader/file.h
new file mode 100644
index 0000000..90296e7
--- /dev/null
+++ b/src/starboard/elf_loader/file.h
@@ -0,0 +1,44 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef STARBOARD_ELF_LOADER_FILE_H_
+#define STARBOARD_ELF_LOADER_FILE_H_
+
+#include "starboard/elf_loader/elf.h"
+
+namespace starboard {
+namespace elf_loader {
+
+// File abstraction to be used by the ELF loader.
+// The main reason to introduce this class is to allow for
+// easy testing.
+class File {
+ public:
+ // Opens the file specified for reading.
+ virtual bool Open(const char* name) = 0;
+
+ // Reads a buffer from the file using the specified offset from the beginning
+ // of the file.
+ virtual bool ReadFromOffset(int64_t offset, char* buffer, int size) = 0;
+
+ // Closes the underlying file.
+ virtual void Close() = 0;
+
+ virtual ~File() {}
+};
+
+} // namespace elf_loader
+} // namespace starboard
+
+#endif // STARBOARD_ELF_LOADER_FILE_H_
diff --git a/src/starboard/elf_loader/file_impl.cc b/src/starboard/elf_loader/file_impl.cc
new file mode 100644
index 0000000..8250e8f
--- /dev/null
+++ b/src/starboard/elf_loader/file_impl.cc
@@ -0,0 +1,71 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/file_impl.h"
+
+#include "starboard/common/log.h"
+
+namespace {
+void LogLastError(const char* msg) {
+ const int kErrorMessageBufferSize = 256;
+ char msgbuf[kErrorMessageBufferSize];
+ SbSystemError error_code = SbSystemGetLastError();
+ if (SbSystemGetErrorString(error_code, msgbuf, kErrorMessageBufferSize) > 0) {
+ SB_LOG(ERROR) << msg << ": " << msgbuf;
+ }
+}
+} // namespace
+
+namespace starboard {
+namespace elf_loader {
+
+FileImpl::FileImpl() : file_(NULL) {}
+
+bool FileImpl::Open(const char* name) {
+ SB_LOG(INFO) << "Loading: " << name;
+ file_ = SbFileOpen(name, kSbFileOpenOnly | kSbFileRead, NULL, NULL);
+ if (!file_) {
+ return false;
+ }
+ return true;
+}
+
+bool FileImpl::ReadFromOffset(int64_t offset, char* buffer, int size) {
+ if (!file_) {
+ return false;
+ }
+ int64_t ret = SbFileSeek(file_, kSbFileFromBegin, offset);
+ SB_LOG(INFO) << "SbFileSeek: ret=" << ret;
+ if (ret == -1) {
+ SB_LOG(INFO) << "SbFileSeek: failed";
+ return false;
+ }
+
+ int count = SbFileReadAll(file_, buffer, size);
+ SB_LOG(INFO) << "SbFileReadAll: count=" << count;
+ if (count == -1) {
+ LogLastError("SbFileReadAll failed");
+ return false;
+ }
+ return true;
+}
+
+void FileImpl::Close() {
+ if (file_) {
+ SbFileClose(file_);
+ }
+}
+
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/file_impl.h b/src/starboard/elf_loader/file_impl.h
new file mode 100644
index 0000000..2a923be
--- /dev/null
+++ b/src/starboard/elf_loader/file_impl.h
@@ -0,0 +1,43 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef STARBOARD_ELF_LOADER_FILE_IMPL_H_
+#define STARBOARD_ELF_LOADER_FILE_IMPL_H_
+
+#include "starboard/elf_loader/elf.h"
+
+#include "starboard/elf_loader/file.h"
+#include "starboard/file.h"
+
+namespace starboard {
+namespace elf_loader {
+
+// Starboard implementation for reading a file.
+class FileImpl : public File {
+ public:
+ FileImpl();
+ bool Open(const char* name);
+ bool ReadFromOffset(int64_t offset, char* buffer, int size);
+ void Close();
+
+ private:
+ SbFile file_;
+
+ SB_DISALLOW_COPY_AND_ASSIGN(FileImpl);
+};
+
+} // namespace elf_loader
+} // namespace starboard
+
+#endif // STARBOARD_ELF_LOADER_FILE_IMPL_H_
diff --git a/src/starboard/elf_loader/gnu_hash_table.cc b/src/starboard/elf_loader/gnu_hash_table.cc
new file mode 100644
index 0000000..37db118
--- /dev/null
+++ b/src/starboard/elf_loader/gnu_hash_table.cc
@@ -0,0 +1,142 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/gnu_hash_table.h"
+#include "starboard/common/log.h"
+#include "starboard/string.h"
+
+namespace starboard {
+namespace elf_loader {
+
+// Compute the GNU hash of a given symbol.
+// For more details on the hash function:
+// https://blogs.oracle.com/solaris/gnu-hash-elf-sections-v2
+static uint32_t GnuHash(const char* name) {
+ uint32_t h = 5381;
+ const uint8_t* ptr = reinterpret_cast<const uint8_t*>(name);
+ while (*ptr) {
+ h = h * 33 + *ptr++;
+ }
+ return h;
+}
+
+GnuHashTable::GnuHashTable()
+ : num_buckets_(0),
+ sym_offset_(0),
+ sym_count_(0),
+ bloom_word_mask_(0),
+ bloom_shift_(0),
+ bloom_filter_(NULL),
+ buckets_(NULL),
+ chain_(NULL) {}
+void GnuHashTable::Init(uintptr_t dt_gnu_hash) {
+ SB_LOG(INFO) << "GnuHashTable::Init 0x" << std::hex << dt_gnu_hash;
+ sym_count_ = 0;
+
+ const uint32_t* data = reinterpret_cast<const uint32_t*>(dt_gnu_hash);
+ num_buckets_ = data[0];
+ sym_offset_ = data[1];
+
+ SB_LOG(INFO) << "GnuHashTable::Init num_buckets_=" << num_buckets_
+ << " sym_offset_" << sym_offset_;
+ if (!num_buckets_)
+ return;
+
+ const uint32_t bloom_size = data[2];
+ SB_LOG(INFO) << "GnuHashTable::Init bloom_size=" << bloom_size;
+ if ((bloom_size & (bloom_size - 1U)) != 0) // must be a power of 2
+ return;
+
+ bloom_word_mask_ = bloom_size - 1U;
+ bloom_shift_ = data[3];
+
+ SB_LOG(INFO) << "GnuHashTable::Init bloom_word_mask_=" << bloom_word_mask_;
+ SB_LOG(INFO) << "GnuHashTable::Init bloom_shift_=" << bloom_shift_;
+ bloom_filter_ = reinterpret_cast<const Addr*>(data + 4);
+ SB_LOG(INFO) << "GnuHashTable::Init bloom_filter_=0x" << std::hex
+ << bloom_filter_;
+ buckets_ = reinterpret_cast<const uint32_t*>(bloom_filter_ + bloom_size);
+
+ SB_LOG(INFO) << "GnuHashTable::Init buckets_=0x" << std::hex << buckets_;
+ chain_ = buckets_ + num_buckets_;
+
+ // Compute number of dynamic symbols by parsing the table.
+ if (num_buckets_ > 0) {
+ // First find the maximum index in the buckets table.
+ uint32_t max_index = buckets_[0];
+ for (size_t n = 1; n < num_buckets_; ++n) {
+ uint32_t sym_index = buckets_[n];
+ if (sym_index > max_index)
+ max_index = sym_index;
+ }
+ // Now start to look at the chain_ table from (max_index - sym_offset_)
+ // until there is a value with LSB set to 1, indicating the end of the
+ // last chain.
+ while ((chain_[max_index - sym_offset_] & 1) == 0)
+ max_index++;
+
+ sym_count_ = (max_index - sym_offset_) + 1;
+ }
+}
+
+bool GnuHashTable::IsValid() const {
+ return sym_count_ > 0;
+}
+
+const Sym* GnuHashTable::LookupByName(const char* symbol_name,
+ const Sym* symbol_table,
+ const char* string_table) const {
+ SB_LOG(INFO) << "GnuHashTable::LookupByName: " << symbol_name;
+ uint32_t hash = GnuHash(symbol_name);
+
+ SB_LOG(INFO) << "GnuHashTable::LookupByName: hash=" << hash;
+ SB_LOG(INFO) << "GnuHashTable::LookupByName: ELF_BITS=" << ELF_BITS;
+
+ // First, bloom filter test.
+ Addr word = bloom_filter_[(hash / ELF_BITS) & bloom_word_mask_];
+
+ SB_LOG(INFO) << "GnuHashTable::LookupByName: word=" << word;
+ Addr mask = (Addr(1) << (hash % ELF_BITS)) |
+ (Addr(1) << ((hash >> bloom_shift_) % ELF_BITS));
+
+ SB_LOG(INFO) << "GnuHashTable::LookupByName: mask=" << mask;
+ if ((word & mask) != mask)
+ return NULL;
+
+ uint32_t sym_index = buckets_[hash % num_buckets_];
+ if (sym_index < sym_offset_)
+ return NULL;
+
+ // TODO: add validations of the syn_index
+ while (true) {
+ const Sym* sym = symbol_table + sym_index;
+ const uint32_t sym_hash = chain_[sym_index - sym_offset_];
+ const char* sym_name = string_table + sym->st_name;
+
+ if ((sym_hash | 1) == (hash | 1) &&
+ !SbStringCompareAll(sym_name, symbol_name)) {
+ return sym;
+ }
+
+ if (sym_hash & 1)
+ break;
+
+ sym_index++;
+ }
+
+ return NULL;
+}
+
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/gnu_hash_table.h b/src/starboard/elf_loader/gnu_hash_table.h
new file mode 100644
index 0000000..5bdf199
--- /dev/null
+++ b/src/starboard/elf_loader/gnu_hash_table.h
@@ -0,0 +1,66 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef STARBOARD_ELF_LOADER_GNU_HASH_TABLE_H_
+#define STARBOARD_ELF_LOADER_GNU_HASH_TABLE_H_
+
+#include <stddef.h>
+#include "starboard/elf_loader/elf.h"
+
+namespace starboard {
+namespace elf_loader {
+
+// Models the hash table used to map symbol names to symbol entries using
+// the GNU format. This one is smaller and faster than the standard ELF one.
+class GnuHashTable {
+ public:
+ GnuHashTable();
+ // Initialize instance. |dt_gnu_hash| should be the address that the
+ // DT_GNU_HASH entry points to in the input ELF dynamic section. Call
+ // IsValid() to determine whether the table was well-formed.
+ void Init(uintptr_t dt_gnu_hash);
+
+ // Returns true iff the content of the table is valid.
+ bool IsValid() const;
+
+ // Return the index of the first dynamic symbol within the ELF symbol table.
+ size_t dyn_symbols_offset() const { return sym_offset_; }
+
+ // Number of dynamic symbols in the ELF symbol table.
+ size_t dyn_symbols_count() const { return sym_count_; }
+
+ // Lookup |symbol_name| in the table. |symbol_table| should point to the
+ // ELF symbol table, and |string_table| to the start of its string table.
+ // Returns NULL on failure.
+ const Sym* LookupByName(const char* symbol_name,
+ const Sym* symbol_table,
+ const char* string_table) const;
+
+ private:
+ uint32_t num_buckets_;
+ uint32_t sym_offset_;
+ uint32_t sym_count_;
+ uint32_t bloom_word_mask_;
+ uint32_t bloom_shift_;
+ const Addr* bloom_filter_;
+ const uint32_t* buckets_;
+ const uint32_t* chain_;
+
+ SB_DISALLOW_COPY_AND_ASSIGN(GnuHashTable);
+};
+
+} // namespace elf_loader
+} // namespace starboard
+
+#endif // STARBOARD_ELF_LOADER_GNU_HASH_TABLE_H_
diff --git a/src/starboard/elf_loader/program_table.cc b/src/starboard/elf_loader/program_table.cc
new file mode 100644
index 0000000..7542604
--- /dev/null
+++ b/src/starboard/elf_loader/program_table.cc
@@ -0,0 +1,329 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/program_table.h"
+
+#include "starboard/common/log.h"
+#include "starboard/memory.h"
+
+#define MAYBE_MAP_FLAG(x, from, to) (((x) & (from)) ? (to) : 0)
+#define PFLAGS_TO_PROT(x) \
+ (MAYBE_MAP_FLAG((x), PF_X, kSbMemoryMapProtectExec) | \
+ MAYBE_MAP_FLAG((x), PF_R, kSbMemoryMapProtectRead) | \
+ MAYBE_MAP_FLAG((x), PF_W, kSbMemoryMapProtectWrite))
+
+#define MAP_FAILED ((void*)-1)
+
+namespace starboard {
+namespace elf_loader {
+
+ProgramTable::ProgramTable()
+ : phdr_num_(0),
+ phdr_mmap_(NULL),
+ phdr_table_(NULL),
+ phdr_size_(0),
+ load_start_(NULL),
+ load_size_(0),
+ base_memory_address_(0) {}
+
+bool ProgramTable::LoadProgramHeader(const Ehdr* elf_header, File* elf_file) {
+ if (!elf_header) {
+ SB_LOG(ERROR) << "Ehdr is required";
+ return false;
+ }
+ if (!elf_file) {
+ SB_LOG(ERROR) << "File is required";
+ return false;
+ }
+ phdr_num_ = elf_header->e_phnum;
+
+ SB_LOG(INFO) << "Program Header count=" << phdr_num_;
+ // Like the kernel, only accept program header tables smaller than 64 KB.
+ if (phdr_num_ < 1 || phdr_num_ > 65536 / elf_header->e_phentsize) {
+ SB_LOG(ERROR) << "Invalid program header count: " << phdr_num_;
+ return false;
+ }
+
+ SB_LOG(INFO) << "elf_header->e_phoff=" << elf_header->e_phoff;
+ SB_LOG(INFO) << "elf_header->e_phnum=" << elf_header->e_phnum;
+
+ Addr page_min = PAGE_START(elf_header->e_phoff);
+ Addr page_max = PAGE_END(elf_header->e_phoff + (phdr_num_ * elf_header->e_phentsize));
+ Addr page_offset = PAGE_OFFSET(elf_header->e_phoff);
+
+ SB_LOG(INFO) << "page_min=" << page_min;
+ SB_LOG(INFO) << "page_max=" << page_max;
+
+ phdr_size_ = page_max - page_min;
+
+ SB_LOG(INFO) << "page_max - page_min=" << page_max - page_min;
+
+ phdr_mmap_ =
+ SbMemoryMap(phdr_size_, kSbMemoryMapProtectWrite, "program_header");
+ if (!phdr_mmap_) {
+ SB_LOG(ERROR) << "Failed to allocate memory";
+ return false;
+ }
+
+ SB_LOG(INFO) << "Allocated address=" << phdr_mmap_;
+
+ if (!elf_file->ReadFromOffset(page_min, reinterpret_cast<char*>(phdr_mmap_),
+ phdr_size_)) {
+ SB_LOG(ERROR) << "Failed to read program header from file offset: "
+ << page_min;
+ return false;
+ }
+
+ bool mp_result =
+ SbMemoryProtect(phdr_mmap_, phdr_size_, kSbMemoryMapProtectRead);
+ SB_LOG(INFO) << "mp_result=" << mp_result;
+ if (!mp_result) {
+ SB_LOG(ERROR) << "Failed to protect program header";
+ return false;
+ }
+ phdr_table_ = reinterpret_cast<Phdr*>(reinterpret_cast<char*>(phdr_mmap_) +
+ page_offset);
+
+ return true;
+}
+
+bool ProgramTable::LoadSegments(File* elf_file) {
+ for (size_t i = 0; i < phdr_num_; ++i) {
+ const Phdr* phdr = &phdr_table_[i];
+
+ if (phdr->p_type != PT_LOAD) {
+ continue;
+ }
+
+ // Segment byte addresses in memory.
+ Addr seg_start = phdr->p_vaddr + base_memory_address_;
+ Addr seg_end = seg_start + phdr->p_memsz;
+
+ // Segment page addresses in memory.
+ Addr seg_page_start = PAGE_START(seg_start);
+ Addr seg_page_end = PAGE_END(seg_end);
+
+ // File offsets.
+ Addr seg_file_end = seg_start + phdr->p_filesz;
+ Addr file_start = phdr->p_offset;
+ Addr file_end = file_start + phdr->p_filesz;
+
+ SB_LOG(INFO) << " phdr->p_offset=" << phdr->p_offset
+ << " phdr->p_filesz=" << phdr->p_filesz;
+
+ Addr file_page_start = PAGE_START(file_start);
+ Addr file_length = file_end - file_page_start;
+
+ SB_LOG(INFO) << "Mapping segment: "
+ << " file_page_start=" << file_page_start
+ << " file_length=" << file_length << " seg_page_start=0x"
+ << std::hex << seg_page_start;
+
+ if (file_length != 0) {
+ const int prot_flags = PFLAGS_TO_PROT(phdr->p_flags);
+ SB_LOG(INFO) << "segment prot_flags=" << std::hex << prot_flags;
+
+ void* seg_addr = reinterpret_cast<void*>(seg_page_start);
+ bool mp_ret =
+ SbMemoryProtect(seg_addr, file_length, kSbMemoryMapProtectWrite);
+ SB_LOG(INFO) << "segment vaddress=" << seg_addr;
+
+ if (!mp_ret) {
+ SB_LOG(ERROR) << "Failed to unprotect segment";
+ return false;
+ }
+ if (!elf_file->ReadFromOffset(file_page_start,
+ reinterpret_cast<char*>(seg_addr),
+ file_length)) {
+ SB_LOG(INFO) << "Failed to read segment from file offset: "
+ << file_page_start;
+ return false;
+ }
+
+ mp_ret = SbMemoryProtect(seg_addr, file_length, prot_flags);
+ SB_LOG(INFO) << "mp_ret=" << mp_ret;
+ if (!mp_ret) {
+ SB_LOG(ERROR) << "Failed to protect segment";
+ return false;
+ }
+ if (!seg_addr) {
+ SB_LOG(ERROR) << "Could not map segment " << i;
+ return false;
+ }
+ }
+
+ // if the segment is writable, and does not end on a page boundary,
+ // zero-fill it until the page limit.
+ if ((phdr->p_flags & PF_W) != 0 && PAGE_OFFSET(seg_file_end) > 0) {
+ SbMemorySet(reinterpret_cast<void*>(seg_file_end), 0,
+ PAGE_SIZE - PAGE_OFFSET(seg_file_end));
+ }
+
+ seg_file_end = PAGE_END(seg_file_end);
+
+ // seg_file_end is now the first page address after the file
+ // content. If seg_page_end is larger, we need to zero anything
+ // between them. This is done by using a private anonymous
+ // map for all extra pages.
+ if (seg_page_end > seg_file_end) {
+ bool mprotect_fix = SbMemoryProtect(reinterpret_cast<void*>(seg_file_end),
+ seg_page_end - seg_file_end,
+ kSbMemoryMapProtectWrite);
+ SB_LOG(INFO) << "mprotect_fix=" << mprotect_fix;
+ if (!mprotect_fix) {
+ SB_LOG(ERROR) << "Failed to unprotect end of segment";
+ return false;
+ }
+ SbMemorySet(reinterpret_cast<void*>(seg_file_end), 0,
+ seg_page_end - seg_file_end);
+ SbMemoryProtect(reinterpret_cast<void*>(seg_file_end),
+ seg_page_end - seg_file_end,
+ PFLAGS_TO_PROT(phdr->p_flags));
+ SB_LOG(INFO) << "mprotect_fix=" << mprotect_fix;
+ if (!mprotect_fix) {
+ SB_LOG(ERROR) << "Failed to protect end of segment";
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+size_t ProgramTable::GetLoadMemorySize() {
+ Addr min_vaddr = ~static_cast<Addr>(0);
+ Addr max_vaddr = 0x00000000U;
+
+ bool found_pt_load = false;
+ for (size_t i = 0; i < phdr_num_; ++i) {
+ const Phdr* phdr = &phdr_table_[i];
+
+ if (phdr->p_type != PT_LOAD) {
+ SB_LOG(INFO) << "GetLoadMemorySize: ignoring segment with type: "
+ << phdr->p_type;
+ continue;
+ }
+ found_pt_load = true;
+
+ if (phdr->p_vaddr < min_vaddr) {
+ SB_LOG(INFO) << "p_vaddr=" << std::hex << phdr->p_vaddr;
+ min_vaddr = phdr->p_vaddr;
+ }
+
+ if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
+ max_vaddr = phdr->p_vaddr + phdr->p_memsz;
+ SB_LOG(INFO) << "phdr->p_vaddr=" << phdr->p_vaddr
+ << " phdr->p_memsz=" << phdr->p_memsz;
+ SB_LOG(INFO) << " max_vaddr=0x" << std::hex << max_vaddr;
+ }
+ }
+ if (!found_pt_load) {
+ min_vaddr = 0x00000000U;
+ }
+
+ min_vaddr = PAGE_START(min_vaddr);
+ max_vaddr = PAGE_END(max_vaddr);
+
+ return max_vaddr - min_vaddr;
+}
+
+void ProgramTable::GetDynamicSection(Dyn** dynamic,
+ size_t* dynamic_count,
+ Word* dynamic_flags) {
+ const Phdr* phdr = phdr_table_;
+ const Phdr* phdr_limit = phdr + phdr_num_;
+
+ for (phdr = phdr_table_; phdr < phdr_limit; phdr++) {
+ if (phdr->p_type != PT_DYNAMIC) {
+ SB_LOG(INFO) << "Ignore section with type: " << phdr->p_type;
+ continue;
+ }
+
+ SB_LOG(INFO) << "Reading at vaddr: " << phdr->p_vaddr;
+ *dynamic = reinterpret_cast<Dyn*>(base_memory_address_ + phdr->p_vaddr);
+ if (dynamic_count) {
+ *dynamic_count = (size_t)(phdr->p_memsz / sizeof(Dyn));
+ }
+ if (dynamic_flags) {
+ *dynamic_flags = phdr->p_flags;
+ }
+ return;
+ }
+ *dynamic = NULL;
+ if (dynamic_count) {
+ *dynamic_count = 0;
+ }
+}
+
+int ProgramTable::AdjustMemoryProtectionOfReadOnlySegments(
+ int extra_prot_flags) {
+ const Phdr* phdr = phdr_table_;
+ const Phdr* phdr_limit = phdr + phdr_num_;
+
+ for (; phdr < phdr_limit; phdr++) {
+ if (phdr->p_type != PT_LOAD || (phdr->p_flags & PF_W) != 0)
+ continue;
+
+ Addr seg_page_start = PAGE_START(phdr->p_vaddr) + base_memory_address_;
+ Addr seg_page_end =
+ PAGE_END(phdr->p_vaddr + phdr->p_memsz) + base_memory_address_;
+
+ int ret = SbMemoryProtect(reinterpret_cast<void*>(seg_page_start),
+ seg_page_end - seg_page_start,
+ PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags);
+ if (ret < 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+bool ProgramTable::ReserveLoadMemory() {
+ load_size_ = GetLoadMemorySize();
+ if (load_size_ == 0) {
+ SB_LOG(ERROR) << "No loadable segments";
+ return false;
+ }
+
+ SB_LOG(INFO) << "Load size=" << load_size_;
+
+ load_start_ =
+ SbMemoryMap(load_size_, kSbMemoryMapProtectReserved, "reserved_mem");
+ if (load_start_ == MAP_FAILED) {
+ SB_LOG(ERROR) << "Could not reserve " << load_size_
+ << " bytes of address space";
+ return false;
+ }
+
+ base_memory_address_ = reinterpret_cast<Addr>(load_start_);
+
+ SB_LOG(INFO) << "Load start=" << std::hex << load_start_
+ << " base_memory_address=0x" << base_memory_address_;
+ return true;
+}
+
+Addr ProgramTable::GetBaseMemoryAddress() {
+ return base_memory_address_;
+}
+
+ProgramTable::~ProgramTable() {
+ if (load_start_) {
+ SbMemoryUnmap(load_start_, load_size_);
+ }
+ if (phdr_mmap_) {
+ SbMemoryUnmap(phdr_mmap_, phdr_size_);
+ }
+}
+
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/program_table.h b/src/starboard/elf_loader/program_table.h
new file mode 100644
index 0000000..c4229e7
--- /dev/null
+++ b/src/starboard/elf_loader/program_table.h
@@ -0,0 +1,91 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef STARBOARD_ELF_LOADER_PROGRAM_TABLE_H_
+#define STARBOARD_ELF_LOADER_PROGRAM_TABLE_H_
+
+#include "starboard/elf_loader/elf.h"
+#include "starboard/elf_loader/file.h"
+
+namespace starboard {
+namespace elf_loader {
+
+// Loads the ELF's binary program table and memory maps
+// the loadable segments.
+//
+// To properly initialize the program table and the segments
+// the following calls are required:
+// 1. LoadProgramHeader()
+// 2. LoadSegments()
+//
+// After those calls the ProgramTable class is fully functional and
+// the segments properly loaded.
+
+class ProgramTable {
+ public:
+ ProgramTable();
+
+ // Loads the program header.
+ bool LoadProgramHeader(const Ehdr* elf_header, File* elf_file);
+
+ // Loads the segments.
+ bool LoadSegments(File* elf_file);
+
+ // Retrieves the dynamic section table.
+ void GetDynamicSection(Dyn** dynamic,
+ size_t* dynamic_count,
+ Word* dynamic_flags);
+
+ // Adjusts the memory protection of read only segments.
+ // This call is used to make text segments writable in order
+ // to apply relocations. After the relocations are done the
+ // protection is restored to its original read only state.
+ int AdjustMemoryProtectionOfReadOnlySegments(int extra_prot_flags);
+
+ // Reserves a contiguous block of memory, page aligned for mapping all
+ // the segments of the binary.
+ bool ReserveLoadMemory();
+
+ // Retrieves the base load address for the binary.
+ Addr GetBaseMemoryAddress();
+
+ ~ProgramTable();
+
+ private:
+ // Calculates the memory size of the binary.
+ size_t GetLoadMemorySize();
+
+ private:
+ size_t phdr_num_;
+ void* phdr_mmap_;
+ Phdr* phdr_table_;
+ Addr phdr_size_;
+
+ // First page of reserved address space.
+ void* load_start_;
+
+ // Size in bytes of reserved address space.
+ Addr load_size_;
+
+ // The base memory address. All virtual addresses
+ // from the ELF file are offsets from this address.
+ Addr base_memory_address_;
+
+ SB_DISALLOW_COPY_AND_ASSIGN(ProgramTable);
+};
+
+} // namespace elf_loader
+} // namespace starboard
+
+#endif // STARBOARD_ELF_LOADER_PROGRAM_TABLE_H_
diff --git a/src/starboard/elf_loader/program_table_test.cc b/src/starboard/elf_loader/program_table_test.cc
new file mode 100644
index 0000000..da15cae
--- /dev/null
+++ b/src/starboard/elf_loader/program_table_test.cc
@@ -0,0 +1,182 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/program_table.h"
+
+#include <vector>
+
+#include "starboard/common/scoped_ptr.h"
+#include "starboard/elf_loader/file.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace elf_loader {
+
+namespace {
+
+class DummyFile : public File {
+ public:
+ typedef struct FileChunk {
+ FileChunk(int file_offset, const char* buffer, int size)
+ : file_offset_(file_offset), buffer_(buffer), size_(size) {}
+ int file_offset_;
+ const char* buffer_;
+ int size_;
+ } FileChunk;
+
+ explicit DummyFile(const std::vector<FileChunk>& file_chunks)
+ : file_chunks_(file_chunks), read_index_(0) {}
+
+ bool Open(const char* name) { return true; }
+ bool ReadFromOffset(int64_t offset, char* buffer, int size) {
+ SB_LOG(INFO) << "ReadFromOffset offset=" << offset << " size=" << size
+ << " read_index_=" << read_index_;
+ if (read_index_ >= file_chunks_.size()) {
+ SB_LOG(INFO) << "ReadFromOffset EOF";
+ return false;
+ }
+ const FileChunk& file_chunk = file_chunks_[read_index_++];
+ if (offset != file_chunk.file_offset_) {
+ SB_LOG(ERROR) << "ReadFromOffset: Invalid offset " << offset
+ << " expected " << file_chunk.file_offset_;
+ return false;
+ }
+ if (size > file_chunk.size_) {
+ SB_LOG(ERROR) << "ReadFromOffset: Invalid size " << size << " expected < "
+ << file_chunk.size_;
+ return false;
+ }
+ SbMemoryCopy(buffer, file_chunk.buffer_, size);
+ return true;
+ }
+ void Close() {}
+
+ private:
+ int file_offset_;
+ const char* buffer_;
+ int size_;
+ std::vector<FileChunk> file_chunks_;
+ int read_index_;
+};
+
+class ProgramTableTest : public ::testing::Test {
+ protected:
+ ProgramTableTest() { program_table_.reset(new ProgramTable()); }
+ ~ProgramTableTest() {}
+
+ void HelperMethod() {}
+
+ protected:
+ scoped_ptr<ProgramTable> program_table_;
+};
+
+TEST_F(ProgramTableTest, LoadSegments) {
+ // File structure
+ // [Phdr1]
+ // [Phdr2]
+ // [200, 300) sement for phdr1
+ // [250, 300) dyanmic section in segment for phdr1
+ // [400, 500) sement for phdr2
+ Ehdr ehdr;
+ ehdr.e_phnum = 3;
+ ehdr.e_phoff = 0;
+
+ Phdr ent1;
+ Phdr ent2;
+ Phdr ent3;
+ SbMemorySet(&ent1, 0, sizeof(Phdr));
+ SbMemorySet(&ent2, 0, sizeof(Phdr));
+ SbMemorySet(&ent3, 0, sizeof(Phdr));
+
+ ent1.p_type = PT_LOAD;
+ ent1.p_vaddr = 0;
+ ent1.p_memsz = 2 * PAGE_SIZE;
+ ent1.p_offset = 200;
+ ent1.p_filesz = 100;
+ ent1.p_flags = kSbMemoryMapProtectRead;
+
+ ent2.p_type = PT_LOAD;
+ ent2.p_vaddr = 2 * PAGE_SIZE;
+ ent2.p_memsz = 3 * PAGE_SIZE;
+ ent2.p_offset = 400;
+ ent2.p_filesz = 100;
+ ent1.p_flags = kSbMemoryMapProtectRead | kSbMemoryMapProtectExec;
+
+ ent3.p_type = PT_DYNAMIC;
+ ent3.p_vaddr = 250;
+ ent3.p_memsz = 3 * sizeof(Dyn);
+ ent3.p_offset = 250;
+ ent3.p_filesz = 5 * sizeof(Dyn);
+ ent3.p_flags = 0x42;
+
+ Phdr program_table_data[3];
+ program_table_data[0] = ent1;
+ program_table_data[1] = ent2;
+ program_table_data[2] = ent3;
+
+ Dyn dynamic_table_data[3];
+ dynamic_table_data[0].d_tag = DT_DEBUG;
+ dynamic_table_data[1].d_tag = DT_DEBUG;
+ dynamic_table_data[2].d_tag = DT_DEBUG;
+
+ char program_table_page[PAGE_SIZE];
+ SbMemorySet(program_table_page, 0, sizeof(program_table_page));
+ SbMemoryCopy(program_table_page, program_table_data,
+ sizeof(program_table_data));
+
+ char segment_file_data1[2 * PAGE_SIZE];
+ char segment_file_data2[3 * PAGE_SIZE];
+
+ SbMemoryCopy(segment_file_data1 + 250, dynamic_table_data,
+ sizeof(dynamic_table_data));
+
+ std::vector<DummyFile::FileChunk> file_chunks;
+ file_chunks.push_back(
+ DummyFile::FileChunk(0, program_table_page, sizeof(program_table_page)));
+ file_chunks.push_back(
+ DummyFile::FileChunk(0, segment_file_data1, sizeof(segment_file_data1)));
+ file_chunks.push_back(
+ DummyFile::FileChunk(0, segment_file_data2, sizeof(segment_file_data2)));
+
+ DummyFile file(file_chunks);
+
+ EXPECT_TRUE(program_table_->LoadProgramHeader(&ehdr, &file));
+
+ EXPECT_EQ(program_table_->GetBaseMemoryAddress(), 0);
+
+ EXPECT_TRUE(program_table_->ReserveLoadMemory());
+
+ EXPECT_NE(program_table_->GetBaseMemoryAddress(), 0);
+
+ EXPECT_TRUE(program_table_->LoadSegments(&file));
+
+ Dyn* dynamic = NULL;
+ size_t dynamic_count = 0;
+ Word dynamic_flags = 0;
+
+ program_table_->GetDynamicSection(&dynamic, &dynamic_count, &dynamic_flags);
+ Dyn* expected_dyn = reinterpret_cast<Dyn*>(
+ program_table_->GetBaseMemoryAddress() + ent3.p_vaddr);
+ EXPECT_TRUE(dynamic != NULL);
+ EXPECT_EQ(dynamic[0].d_tag, DT_DEBUG);
+ EXPECT_EQ(dynamic[1].d_tag, DT_DEBUG);
+ EXPECT_EQ(dynamic[2].d_tag, DT_DEBUG);
+ EXPECT_EQ(dynamic_count, 3);
+ EXPECT_EQ(dynamic_flags, 0x42);
+}
+
+} // namespace
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/relocations.cc b/src/starboard/elf_loader/relocations.cc
new file mode 100644
index 0000000..4b7131c
--- /dev/null
+++ b/src/starboard/elf_loader/relocations.cc
@@ -0,0 +1,551 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/relocations.h"
+
+#include "starboard/common/log.h"
+
+namespace starboard {
+namespace elf_loader {
+
+Relocations::Relocations(Addr base_memory_address,
+ DynamicSection* dynamic_section,
+ ExportedSymbols* exported_symbols)
+ : base_memory_address_(base_memory_address),
+ dynamic_section_(dynamic_section),
+ plt_relocations_(0),
+ plt_relocations_size_(0),
+ plt_got_(NULL),
+ relocations_(0),
+ relocations_size_(0),
+ android_relocations_(NULL),
+ android_relocations_size_(0),
+ has_text_relocations_(false),
+ has_symbolic_(false),
+ exported_symbols_(exported_symbols) {}
+
+bool Relocations::HasTextRelocations() {
+ return has_text_relocations_;
+}
+
+bool Relocations::InitRelocations() {
+ SB_LOG(INFO) << "InitRelocations: dynamic_count="
+ << dynamic_section_->GetDynamicTableSize();
+ const Dyn* dynamic = dynamic_section_->GetDynamicTable();
+ for (int i = 0; i < dynamic_section_->GetDynamicTableSize(); i++) {
+ Addr dyn_value = dynamic[i].d_un.d_val;
+ uintptr_t dyn_addr = base_memory_address_ + dynamic[i].d_un.d_ptr;
+ Addr tag = dynamic[i].d_tag;
+ SB_LOG(INFO) << "InitRelocations: tag=" << tag;
+ switch (tag) {
+#if defined(USE_RELA)
+ case DT_REL:
+ case DT_RELSZ:
+ case DT_ANDROID_REL:
+ case DT_ANDROID_RELSZ:
+#else
+ case DT_RELA:
+ case DT_RELASZ:
+ case DT_ANDROID_RELA:
+ case DT_ANDROID_RELASZ:
+#endif
+ SB_LOG(ERROR) << "unsupported relocation type";
+ return false;
+ case DT_PLTREL:
+ SB_LOG(INFO) << " DT_PLTREL value=" << dyn_value;
+#if defined(USE_RELA)
+ if (dyn_value != DT_RELA) {
+ SB_LOG(ERROR) << "unsupported DT_PLTREL expected DT_RELA";
+ return false;
+ }
+#else
+ if (dyn_value != DT_REL) {
+ SB_LOG(ERROR) << "unsupported DT_PLTREL expected DT_REL";
+ return false;
+ }
+#endif
+ break;
+ case DT_JMPREL:
+ SB_LOG(INFO) << " DT_JMPREL addr=0x" << std::hex
+ << (dyn_addr - base_memory_address_);
+ plt_relocations_ = dyn_addr;
+ break;
+ case DT_PLTRELSZ:
+ plt_relocations_size_ = dyn_value;
+ SB_LOG(INFO) << " DT_PLTRELSZ size=" << dyn_value;
+ break;
+#if defined(USE_RELA)
+ case DT_RELA:
+#else
+ case DT_REL:
+#endif
+ SB_LOG(INFO) << " " << ((tag == DT_RELA) ? "DT_RELA" : "DT_REL")
+ << " addr=" << std::hex
+ << (dyn_addr - base_memory_address_);
+ if (relocations_) {
+ SB_LOG(ERROR)
+ << "Unsupported DT_RELA/DT_REL combination in dynamic section";
+ return false;
+ }
+ relocations_ = dyn_addr;
+ break;
+#if defined(USE_RELA)
+ case DT_RELASZ:
+#else
+ case DT_RELSZ:
+#endif
+ SB_LOG(INFO) << " " << ((tag == DT_RELASZ) ? "DT_RELASZ" : "DT_RELSZ")
+ << " size=" << dyn_value;
+ relocations_size_ = dyn_value;
+ break;
+#if defined(USE_RELA)
+ case DT_ANDROID_RELA:
+#else
+ case DT_ANDROID_REL:
+#endif
+ SB_LOG(INFO) << " "
+ << ((tag == DT_ANDROID_REL) ? "DT_ANDROID_REL"
+ : "DT_ANDROID_RELA")
+ << " addr=" << std::hex
+ << (dyn_addr - base_memory_address_);
+ if (android_relocations_) {
+ SB_LOG(ERROR) << "Multiple DT_ANDROID_* sections defined.";
+ return false;
+ }
+ android_relocations_ = reinterpret_cast<uint8_t*>(dyn_addr);
+ break;
+#if defined(USE_RELA)
+ case DT_ANDROID_RELASZ:
+#else
+ case DT_ANDROID_RELSZ:
+#endif
+ SB_LOG(ERROR) << " DT_ANDROID_RELSZ NOT IMPELMENTED";
+ android_relocations_size_ = dyn_value;
+ break;
+ case DT_RELR:
+ case DT_ANDROID_RELR:
+ SB_LOG(ERROR) << " DT_RELR NOT IMPELMENTED";
+ break;
+ case DT_ANDROID_RELRSZ:
+ case DT_RELRSZ:
+ SB_LOG(ERROR) << " DT_RELRSZ NOT IMPELMENTED";
+ break;
+ case DT_RELRENT:
+ case DT_ANDROID_RELRENT:
+ if (dyn_value != sizeof(Relr)) {
+ SB_LOG(ERROR) << "Invalid DT_RELRENT value=" << std::hex
+ << static_cast<int>(dyn_value)
+ << " expected=" << static_cast<int>(sizeof(Relr));
+ return false;
+ }
+ break;
+ case DT_PLTGOT:
+ SB_LOG(INFO) << "DT_PLTGOT addr=0x" << std::hex
+ << (dyn_addr - base_memory_address_);
+ plt_got_ = reinterpret_cast<Addr*>(dyn_addr);
+ break;
+ case DT_TEXTREL:
+ SB_LOG(INFO) << " DT_TEXTREL";
+ has_text_relocations_ = true;
+ break;
+ case DT_SYMBOLIC:
+ SB_LOG(INFO) << " DT_SYMBOLIC";
+ has_symbolic_ = true;
+ break;
+ case DT_FLAGS:
+ if (dyn_value & DF_TEXTREL)
+ has_text_relocations_ = true;
+ if (dyn_value & DF_SYMBOLIC)
+ has_symbolic_ = true;
+
+ SB_LOG(INFO) << " DT_FLAGS has_text_relocations="
+ << has_text_relocations_
+ << " has_symbolic=" << has_symbolic_;
+
+ break;
+ default:
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool Relocations::ApplyAllRelocations() {
+ SB_LOG(INFO) << "Applying regular relocations";
+ if (!ApplyRelocations(reinterpret_cast<rel_t*>(relocations_),
+ relocations_size_ / sizeof(rel_t))) {
+ SB_LOG(ERROR) << "regular relocations failed";
+ return false;
+ }
+
+ SB_LOG(INFO) << "Applying PLT relocations";
+ if (!ApplyRelocations(reinterpret_cast<rel_t*>(plt_relocations_),
+ plt_relocations_size_ / sizeof(rel_t))) {
+ SB_LOG(ERROR) << "PLT relocations failed";
+ return false;
+ }
+ return true;
+}
+
+bool Relocations::ApplyRelocations(const rel_t* rel, size_t rel_count) {
+ SB_LOG(INFO) << "rel=" << std::hex << rel << std::dec
+ << " rel_count=" << rel_count;
+
+ if (!rel)
+ return true;
+
+ for (size_t rel_n = 0; rel_n < rel_count; rel++, rel_n++) {
+ SB_LOG(INFO) << " Relocation " << rel_n + 1 << " of " << rel_count;
+
+ if (!ApplyRelocation(rel))
+ return false;
+ }
+
+ return true;
+}
+
+bool Relocations::ApplyRelocation(const rel_t* rel) {
+ const Word rel_type = ELF_R_TYPE(rel->r_info);
+ const Word rel_symbol = ELF_R_SYM(rel->r_info);
+
+ Addr sym_addr = 0;
+ Addr reloc = static_cast<Addr>(rel->r_offset + base_memory_address_);
+ SB_LOG(INFO) << " offset=0x" << std::hex << rel->r_offset
+ << " type=" << std::dec << rel_type << " reloc=0x" << std::hex
+ << reloc << " symbol=" << rel_symbol;
+
+ if (rel_type == 0)
+ return true;
+
+ if (rel_symbol != 0) {
+ if (!ResolveSymbol(rel_type, rel_symbol, reloc, &sym_addr)) {
+ SB_LOG(ERROR) << "Failed to resolve symbol: " << rel_symbol;
+ return false;
+ }
+ }
+
+ return ApplyResolvedReloc(rel, sym_addr);
+}
+
+#if defined(USE_RELA)
+bool Relocations::ApplyResolvedReloc(const Rela* rela, Addr sym_addr) {
+ const Word rela_type = ELF_R_TYPE(rela->r_info);
+ const Word rela_symbol = ELF_R_SYM(rela->r_info);
+ const Sword addend = rela->r_addend;
+ const Addr reloc = static_cast<Addr>(rela->r_offset + base_memory_address_);
+
+ SB_LOG(INFO) << " rela reloc=0x" << std::hex << reloc << " offset=0x"
+ << rela->r_offset << " type=" << std::dec << rela_type
+ << " addend=0x" << std::hex << addend;
+ Addr* target = reinterpret_cast<Addr*>(reloc);
+ switch (rela_type) {
+#if SB_IS(ARCH_ARM) && SB_IS(64_BIT)
+ case R_AARCH64_JUMP_SLOT:
+ SB_LOG(INFO) << " R_AARCH64_JUMP_SLOT target=" << std::hex << target
+ << " addr=" << (sym_addr + addend);
+ *target = sym_addr + addend;
+ break;
+
+ case R_AARCH64_GLOB_DAT:
+ SB_LOG(INFO) << " R_AARCH64_GLOB_DAT target=" << std::hex << target
+ << " addr=" << (sym_addr + addend);
+ *target = sym_addr + addend;
+ break;
+
+ case R_AARCH64_ABS64:
+ SB_LOG(INFO) << " R_AARCH64_ABS64 target=" << std::hex << target << " "
+ << *target << " addr=" << sym_addr + addend;
+ *target += sym_addr + addend;
+ break;
+
+ case R_AARCH64_RELATIVE:
+ SB_LOG(INFO) << " R_AARCH64_RELATIVE target=" << std::hex << target
+ << " " << *target
+ << " bias=" << base_memory_address_ + addend;
+ if (!rela_symbol) {
+ SB_LOG(ERROR) << "Invalid relative relocation with symbol";
+ return false;
+ }
+ *target = base_memory_address_ + addend;
+ break;
+
+ case R_AARCH64_COPY:
+ // NOTE: These relocations are forbidden in shared libraries.
+ SB_LOG(ERROR) << "Invalid R_AARCH64_COPY relocation in shared library";
+ return false;
+#endif
+
+#if SB_IS(ARCH_X86) && SB_IS(64_BIT)
+ case R_X86_64_JMP_SLOT:
+ SB_LOG(INFO) << " R_X86_64_JMP_SLOT target=" << std::hex << target
+ << " addr=" << (sym_addr + addend);
+ *target = sym_addr + addend;
+ break;
+
+ case R_X86_64_GLOB_DAT:
+ SB_LOG(INFO) << " R_X86_64_GLOB_DAT target=" << std::hex << target
+ << " addr=" << (sym_addr + addend);
+
+ *target = sym_addr + addend;
+ break;
+
+ case R_X86_64_RELATIVE:
+ if (rela_symbol) {
+ SB_LOG(ERROR) << "Invalid R_X86_64_RELATIVE";
+ return false;
+ }
+
+ SB_LOG(INFO) << " R_X86_64_RELATIVE target=" << std::hex << target << " "
+ << *target << " bias=" << base_memory_address_ + addend;
+ *target = base_memory_address_ + addend;
+ break;
+
+ case R_X86_64_64:
+ *target = sym_addr + addend;
+ break;
+
+ case R_X86_64_PC32:
+ *target = sym_addr + (addend - reloc);
+ break;
+#endif
+
+ default:
+ SB_LOG(ERROR) << "Invalid relocation type: " << rela_type;
+ return false;
+ }
+
+ return true;
+}
+#else
+bool Relocations::ApplyResolvedReloc(const Rel* rel, Addr sym_addr) {
+ const Word rel_type = ELF_R_TYPE(rel->r_info);
+ const Word rel_symbol = ELF_R_SYM(rel->r_info);
+
+ const Addr reloc = static_cast<Addr>(rel->r_offset + base_memory_address_);
+
+ SB_LOG(INFO) << " rel reloc=0x" << std::hex << reloc << " offset=0x"
+ << rel->r_offset << " type=" << std::dec << rel_type;
+
+ Addr* target = reinterpret_cast<Addr*>(reloc);
+ switch (rel_type) {
+#if SB_IS(ARCH_ARM) && SB_IS(32_BIT)
+ case R_ARM_JUMP_SLOT:
+ SB_LOG(INFO) << " R_ARM_JUMP_SLOT target=" << std::hex << target
+ << " addr=" << sym_addr;
+ *target = sym_addr;
+ break;
+
+ case R_ARM_GLOB_DAT:
+ SB_LOG(INFO) << " R_ARM_GLOB_DAT target=" << std::hex << target
+ << " addr=" << sym_addr;
+ *target = sym_addr;
+ break;
+
+ case R_ARM_ABS32:
+ SB_LOG(INFO) << " R_ARM_ABS32 target=" << std::hex << target << " "
+ << *target << " addr=" << sym_addr;
+ *target += sym_addr;
+ break;
+
+ case R_ARM_REL32:
+ SB_LOG(INFO) << " R_ARM_REL32 target=" << std::hex << target << " "
+ << *target << " addr=" << sym_addr
+ << " offset=" << rel->r_offset;
+ *target += sym_addr - rel->r_offset;
+ break;
+
+ case R_ARM_RELATIVE:
+ SB_LOG(INFO) << " RR_ARM_RELATIVE target=" << std::hex << target << " "
+ << *target << " bias=" << base_memory_address_;
+ if (!rel_symbol) {
+ SB_LOG(ERROR) << "Invalid relative relocation with symbol";
+ return false;
+ }
+ *target += base_memory_address_;
+ break;
+
+ case R_ARM_COPY:
+ // NOTE: These relocations are forbidden in shared libraries.
+ // The Android linker has special code to deal with this, which
+ // is not needed here.
+ SB_LOG(ERROR) << "Invalid R_ARM_COPY relocation in shared library";
+
+ return false;
+#endif
+
+#if SB_IS(ARCH_X86) && SB_IS(32_BIT)
+ case R_386_JMP_SLOT:
+ SB_LOG(INFO) << " R_386_JMP_SLOT target=" << std::hex << target
+ << " addr=" << sym_addr;
+
+ *target = sym_addr;
+ break;
+
+ case R_386_GLOB_DAT:
+ SB_LOG(INFO) << " R_386_GLOB_DAT target=" << std::hex << target
+ << " addr=" << sym_addr;
+ *target = sym_addr;
+
+ break;
+
+ case R_386_RELATIVE:
+ if (rel_symbol) {
+ SB_LOG(ERROR) << "Invalid relative relocation with symbol";
+ return false;
+ }
+ SB_LOG(INFO) << " R_386_RELATIVE target=" << std::hex << target << " "
+ << *target << " bias=" << base_memory_address_;
+
+ *target += base_memory_address_;
+ break;
+
+ case R_386_32:
+ SB_LOG(INFO) << " R_386_32 target=" << std::hex << target << " "
+ << *target << " addr=" << sym_addr;
+ *target += sym_addr;
+ break;
+
+ case R_386_PC32:
+ SB_LOG(INFO) << " R_386_PC32 target=" << std::hex << target << " "
+ << *target << " addr=" << sym_addr << " reloc=" << reloc;
+ *target += (sym_addr - reloc);
+ break;
+#endif
+
+ default:
+ SB_LOG(ERROR) << "Invalid relocation type: " << rel_type;
+ return false;
+ }
+
+ return true;
+}
+#endif
+
+RelocationType Relocations::GetRelocationType(Word r_type) {
+ switch (r_type) {
+#if SB_IS(ARCH_ARM) && SB_IS(32_BIT)
+ case R_ARM_JUMP_SLOT:
+ case R_ARM_GLOB_DAT:
+ case R_ARM_ABS32:
+ return RELOCATION_TYPE_ABSOLUTE;
+
+ case R_ARM_REL32:
+ case R_ARM_RELATIVE:
+ return RELOCATION_TYPE_RELATIVE;
+
+ case R_ARM_COPY:
+ return RELOCATION_TYPE_COPY;
+#endif
+
+#if SB_IS(ARCH_ARM) && SB_IS(64_BIT)
+ case R_AARCH64_JUMP_SLOT:
+ case R_AARCH64_GLOB_DAT:
+ case R_AARCH64_ABS64:
+ return RELOCATION_TYPE_ABSOLUTE;
+
+ case R_AARCH64_RELATIVE:
+ return RELOCATION_TYPE_RELATIVE;
+
+ case R_AARCH64_COPY:
+ return RELOCATION_TYPE_COPY;
+#endif
+
+#if SB_IS(ARCH_X86) && SB_IS(32_BIT)
+ case R_386_JMP_SLOT:
+ case R_386_GLOB_DAT:
+ case R_386_32:
+ return RELOCATION_TYPE_ABSOLUTE;
+
+ case R_386_RELATIVE:
+ return RELOCATION_TYPE_RELATIVE;
+
+ case R_386_PC32:
+ return RELOCATION_TYPE_PC_RELATIVE;
+#endif
+
+#if SB_IS(ARCH_X86) && SB_IS(64_BIT)
+ case R_X86_64_JMP_SLOT:
+ case R_X86_64_GLOB_DAT:
+ case R_X86_64_64:
+ return RELOCATION_TYPE_ABSOLUTE;
+
+ case R_X86_64_RELATIVE:
+ return RELOCATION_TYPE_RELATIVE;
+
+ case R_X86_64_PC32:
+ return RELOCATION_TYPE_PC_RELATIVE;
+#endif
+ default:
+ return RELOCATION_TYPE_UNKNOWN;
+ }
+}
+
+bool Relocations::ResolveSymbol(Word rel_type,
+ Word rel_symbol,
+ Addr reloc,
+ Addr* sym_addr) {
+ const char* sym_name = dynamic_section_->LookupNameById(rel_symbol);
+ SB_LOG(INFO) << "Resolve: " << sym_name;
+ const void* address = NULL;
+
+ const Sym* sym = dynamic_section_->LookupByName(sym_name);
+ if (sym) {
+ address = reinterpret_cast<void*>(base_memory_address_ + sym->st_value);
+ } else {
+ address = exported_symbols_->Lookup(sym_name);
+ }
+
+ SB_LOG(INFO) << "Resolve: address=0x" << std::hex << address;
+
+ if (address) {
+ // The symbol was found, so compute its address.
+ *sym_addr = reinterpret_cast<Addr>(address);
+ return true;
+ }
+
+ // The symbol was not found. Normally this is an error except
+ // if this is a weak reference.
+ if (!dynamic_section_->IsWeakById(rel_symbol)) {
+ SB_LOG(ERROR) << "Could not find symbol: " << sym_name;
+ return false;
+ }
+
+ // IHI0044C AAELF 4.5.1.1:
+ // Libraries are not searched to resolve weak references.
+ // It is not an error for a weak reference to remain
+ // unsatisfied.
+ //
+ // During linking, the value of an undefined weak reference is:
+ // - Zero if the relocation type is absolute
+ // - The address of the place if the relocation is pc-relative
+ // - The address of nominal base address if the relocation
+ // type is base-relative.
+ RelocationType r = GetRelocationType(rel_type);
+ if (r == RELOCATION_TYPE_ABSOLUTE || r == RELOCATION_TYPE_RELATIVE) {
+ *sym_addr = 0;
+ return true;
+ }
+
+ if (r == RELOCATION_TYPE_PC_RELATIVE) {
+ *sym_addr = reloc;
+ return true;
+ }
+
+ SB_LOG(ERROR) << "Invalid weak relocation type (" << r
+ << ") for unknown symbol '" << sym_name << "'";
+ return false;
+}
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/relocations.h b/src/starboard/elf_loader/relocations.h
new file mode 100644
index 0000000..b763c1b
--- /dev/null
+++ b/src/starboard/elf_loader/relocations.h
@@ -0,0 +1,96 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef STARBOARD_ELF_LOADER_RELOCATIONS_H_
+#define STARBOARD_ELF_LOADER_RELOCATIONS_H_
+
+#include "starboard/elf_loader/elf.h"
+
+#include "starboard/elf_loader/dynamic_section.h"
+#include "starboard/elf_loader/program_table.h"
+
+namespace starboard {
+namespace elf_loader {
+
+enum RelocationType {
+ RELOCATION_TYPE_UNKNOWN = 0,
+ RELOCATION_TYPE_ABSOLUTE = 1,
+ RELOCATION_TYPE_RELATIVE = 2,
+ RELOCATION_TYPE_PC_RELATIVE = 3,
+ RELOCATION_TYPE_COPY = 4,
+};
+
+// class representing the ELF relocations.
+class Relocations {
+ public:
+ Relocations(Addr base_memory_adddress,
+ DynamicSection* dynamic_section,
+ ExportedSymbols* exported_symbols);
+
+ // Initialize the relocation tables.
+ bool InitRelocations();
+
+ // Apply all the relocations.
+ bool ApplyAllRelocations();
+
+ // Apply a set of relocations.
+ bool ApplyRelocations(const rel_t* rel, size_t rel_count);
+
+ // Apply an individual relocation.
+ bool ApplyRelocation(const rel_t* rel);
+
+// Apply a resolved symbol relocation.
+#if defined(USE_RELA)
+ bool ApplyResolvedReloc(const Rela* rela, Addr sym_addr);
+#else
+ bool ApplyResolvedReloc(const Rel* rel, Addr sym_addr);
+#endif
+
+ // Convert an ELF relocation type info a RelocationType value.
+ RelocationType GetRelocationType(Word r_type);
+
+ // Resolve a symbol address.
+ bool ResolveSymbol(Word rel_type,
+ Word rel_symbol,
+ Addr reloc,
+ Addr* sym_addr);
+
+ // Checks if there are any text relocations.
+ bool HasTextRelocations();
+
+ private:
+ Addr base_memory_address_;
+ DynamicSection* dynamic_section_;
+ Addr plt_relocations_;
+ size_t plt_relocations_size_;
+ Addr* plt_got_;
+
+ Addr relocations_;
+ size_t relocations_size_;
+
+ uint8_t* android_relocations_;
+ size_t android_relocations_size_;
+
+ bool has_text_relocations_;
+ bool has_symbolic_;
+
+ ExportedSymbols* exported_symbols_;
+
+ SB_DISALLOW_COPY_AND_ASSIGN(Relocations);
+};
+
+} // namespace elf_loader
+} // namespace starboard
+
+#endif // STARBOARD_ELF_LOADER_RELOCATIONS_H_
diff --git a/src/starboard/elf_loader/relocations_test.cc b/src/starboard/elf_loader/relocations_test.cc
new file mode 100644
index 0000000..a95d7e5
--- /dev/null
+++ b/src/starboard/elf_loader/relocations_test.cc
@@ -0,0 +1,74 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/elf_loader/relocations.h"
+
+#include "starboard/common/scoped_ptr.h"
+#include "starboard/elf_loader/elf.h"
+#include "starboard/elf_loader/file_impl.h"
+#include "starboard/string.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace elf_loader {
+
+namespace {
+
+// TODO: implement
+class RelocationsTest : public ::testing::Test {
+ protected:
+ RelocationsTest() {}
+ ~RelocationsTest() {}
+
+ scoped_ptr<Relocations> relocations_;
+};
+
+#if SB_IS(ARCH_X86) && SB_IS(64_BIT)
+TEST_F(RelocationsTest, Initialize_X86_64) {
+ char buff[1024] = "AAAAAAAAAAAAAAAAAAA";
+ Addr load_bias = reinterpret_cast<Addr>(&buff);
+ Dyn dynamic_table[10];
+ Dyn entry1;
+ entry1.d_tag = DT_REL;
+
+ dynamic_table[0] = entry1;
+ Dyn* dyn = dynamic_table;
+ size_t dyn_count = 1;
+ Word dyn_flags = 0;
+
+ scoped_ptr<DynamicSection> dynamic_section(
+ new DynamicSection(load_bias, dyn, dyn_count, dyn_flags));
+ dynamic_section->InitDynamicSection();
+ dynamic_section->InitDynamicSymbols();
+
+ scoped_ptr<ExportedSymbols> exported_symbols(new ExportedSymbols());
+ relocations_.reset(new Relocations(load_bias, dynamic_section.get(),
+ exported_symbols.get()));
+ Rela rela;
+ rela.r_offset = 2;
+ rela.r_info = R_X86_64_JMP_SLOT;
+ rela.r_addend = 5;
+ Addr sym_addr = 34;
+
+ Addr target = rela.r_offset + load_bias;
+ SB_LOG(INFO) << "target= " << reinterpret_cast<char*>(target);
+ relocations_->ApplyResolvedReloc(&rela, sym_addr);
+ EXPECT_EQ(39, *reinterpret_cast<Elf64_Sxword*>(buff + 2));
+ SB_LOG(INFO) << "buffer= " << *reinterpret_cast<Elf64_Sxword*>(buff + 2);
+}
+#endif
+
+} // namespace
+} // namespace elf_loader
+} // namespace starboard
diff --git a/src/starboard/elf_loader/sandbox.cc b/src/starboard/elf_loader/sandbox.cc
new file mode 100644
index 0000000..86e0476
--- /dev/null
+++ b/src/starboard/elf_loader/sandbox.cc
@@ -0,0 +1,52 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/common/log.h"
+#include "starboard/event.h"
+
+#include "starboard/elf_loader/elf_loader.h"
+
+starboard::elf_loader::ElfLoader g_elfLoader;
+
+void (*g_sb_event_func)(const SbEvent*) = NULL;
+
+void SbEventHandle(const SbEvent* event) {
+ switch (event->type) {
+ case kSbEventTypeStart: {
+ SbEventStartData* data = static_cast<SbEventStartData*>(event->data);
+ if (!g_sb_event_func && data->argument_count == 2) {
+ if (!g_elfLoader.Load(data->argument_values[1])) {
+ SB_LOG(INFO) << "Failed to load library";
+ return;
+ }
+
+ SB_LOG(INFO) << "Successfully loaded library\n";
+ void* p = g_elfLoader.LookupSymbol("SbEventHandle");
+ if (p != NULL) {
+ SB_LOG(INFO) << "Symbol Lookup succeeded address=0x" << std::hex << p;
+ g_sb_event_func = (void (*)(const SbEvent*))p;
+ g_sb_event_func(event);
+ } else {
+ SB_LOG(INFO) << "Symbol Lookup failed\n";
+ }
+ }
+ break;
+ }
+ default: {
+ if (g_sb_event_func) {
+ g_sb_event_func(event);
+ }
+ }
+ }
+}
diff --git a/src/starboard/linux/shared/audio_sink_type_dispatcher.cc b/src/starboard/linux/shared/audio_sink_type_dispatcher.cc
index 22bc79b..2a0b581 100644
--- a/src/starboard/linux/shared/audio_sink_type_dispatcher.cc
+++ b/src/starboard/linux/shared/audio_sink_type_dispatcher.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "starboard/common/log.h"
#include "starboard/shared/alsa/alsa_audio_sink_type.h"
#include "starboard/shared/pulse/pulse_audio_sink_type.h"
#include "starboard/shared/starboard/audio_sink/audio_sink_internal.h"
@@ -23,7 +24,10 @@
// static
void SbAudioSinkPrivate::PlatformInitialize() {
starboard::shared::pulse::PlatformInitialize();
- if (!GetPrimaryType()) {
+ if (GetPrimaryType()) {
+ SB_LOG(INFO) << "Use PulseAudio";
+ } else {
+ SB_LOG(INFO) << "Use ALSA";
starboard::shared::alsa::PlatformInitialize();
is_fallback_to_alsa = true;
}
diff --git a/src/starboard/nplb/audio_sink_test.cc b/src/starboard/nplb/audio_sink_test.cc
index 326fb8d..caa7870 100644
--- a/src/starboard/nplb/audio_sink_test.cc
+++ b/src/starboard/nplb/audio_sink_test.cc
@@ -38,9 +38,10 @@
AudioSinkTestEnvironment environment(frame_buffers);
ASSERT_TRUE(environment.is_valid());
+ // Audio sink need to be fully filled once to ensure it can start working.
int frames_to_append = frame_buffers.frames_per_channel();
+ environment.AppendFrame(frames_to_append);
- environment.AppendFrame(frames_to_append / 2);
EXPECT_TRUE(environment.WaitUntilSomeFramesAreConsumed());
}
@@ -50,8 +51,8 @@
ASSERT_TRUE(environment.is_valid());
int frames_to_append = frame_buffers.frames_per_channel();
-
environment.AppendFrame(frames_to_append / 2);
+
EXPECT_TRUE(environment.WaitUntilAllFramesAreConsumed());
}
@@ -60,11 +61,13 @@
AudioSinkTestEnvironment environment(frame_buffers);
ASSERT_TRUE(environment.is_valid());
+ // Audio sink need to be fully filled once to ensure it can start working.
int frames_to_append = frame_buffers.frames_per_channel();
+ environment.AppendFrame(frames_to_append);
- environment.AppendFrame(frames_to_append / 2);
EXPECT_TRUE(environment.WaitUntilSomeFramesAreConsumed());
- environment.AppendFrame(frames_to_append / 2);
+ ASSERT_GT(environment.GetFrameBufferFreeSpaceAmount(), 0);
+ environment.AppendFrame(environment.GetFrameBufferFreeSpaceAmount());
EXPECT_TRUE(environment.WaitUntilAllFramesAreConsumed());
}
@@ -75,9 +78,10 @@
environment.SetIsPlaying(false);
+ // Audio sink need to be fully filled once to ensure it can start working.
int frames_to_append = frame_buffers.frames_per_channel();
+ environment.AppendFrame(frames_to_append);
- environment.AppendFrame(frames_to_append / 2);
int free_space = environment.GetFrameBufferFreeSpaceAmount();
EXPECT_TRUE(environment.WaitUntilUpdateStatusCalled());
EXPECT_TRUE(environment.WaitUntilUpdateStatusCalled());
@@ -91,12 +95,14 @@
AudioSinkTestEnvironment environment(frame_buffers);
ASSERT_TRUE(environment.is_valid());
+ // Audio sink need to be fully filled once to ensure it can start working.
int frames_to_append = frame_buffers.frames_per_channel();
+ environment.AppendFrame(frames_to_append);
- environment.AppendFrame(frames_to_append / 2);
EXPECT_TRUE(environment.WaitUntilSomeFramesAreConsumed());
SbThreadSleep(250 * kSbTimeMillisecond);
- environment.AppendFrame(frames_to_append / 2);
+ ASSERT_GT(environment.GetFrameBufferFreeSpaceAmount(), 0);
+ environment.AppendFrame(environment.GetFrameBufferFreeSpaceAmount());
EXPECT_TRUE(environment.WaitUntilAllFramesAreConsumed());
}
diff --git a/src/starboard/nplb/cpu_features_get_test.cc b/src/starboard/nplb/cpu_features_get_test.cc
index 87fa1ba..97c2271 100644
--- a/src/starboard/nplb/cpu_features_get_test.cc
+++ b/src/starboard/nplb/cpu_features_get_test.cc
@@ -100,7 +100,8 @@
EXPECT_EQ(kSbCPUFeaturesArchitectureUnknown, features.architecture);
EXPECT_NE(nullptr, features.brand);
EXPECT_EQ(0, strlen(features.brand));
- EXPECT_EQ(kFeatureValueInvalid, features.cache_size);
+ EXPECT_EQ(kFeatureValueInvalid, features.icache_line_size);
+ EXPECT_EQ(kFeatureValueInvalid, features.dcache_line_size);
EXPECT_FALSE(features.has_fpu);
EXPECT_EQ(0, features.hwcap);
EXPECT_EQ(0, features.hwcap2);
diff --git a/src/starboard/raspi/shared/gyp_configuration.py b/src/starboard/raspi/shared/gyp_configuration.py
index 21e3c72..e7668ea 100644
--- a/src/starboard/raspi/shared/gyp_configuration.py
+++ b/src/starboard/raspi/shared/gyp_configuration.py
@@ -106,6 +106,10 @@
'player_filter_tests': [
# TODO: debug these failures.
'VideoDecoderTests/VideoDecoderTest.EndOfStreamWithoutAnyInput/0',
- 'VideoDecoderTests/VideoDecoderTest.SingleInvalidInput/0',
+ 'VideoDecoderTests/VideoDecoderTest.MultipleResets/0',
+ 'VideoDecoderTests/VideoDecoderTest.SingleInvalidInput/*',
+ 'VideoDecoderTests/VideoDecoderTest'
+ '.MultipleValidInputsAfterInvalidKeyFrame/*',
+ 'VideoDecoderTests/VideoDecoderTest.MultipleInvalidInput/*',
],
}
diff --git a/src/starboard/raspi/shared/starboard_platform.gypi b/src/starboard/raspi/shared/starboard_platform.gypi
index 4a8b07e..b20edc6 100644
--- a/src/starboard/raspi/shared/starboard_platform.gypi
+++ b/src/starboard/raspi/shared/starboard_platform.gypi
@@ -140,6 +140,7 @@
'<(DEPTH)/starboard/shared/libevent/socket_waiter_wait_timed.cc',
'<(DEPTH)/starboard/shared/libevent/socket_waiter_wake_up.cc',
'<(DEPTH)/starboard/shared/linux/byte_swap.cc',
+ '<(DEPTH)/starboard/shared/linux/cpu_features_get.cc',
'<(DEPTH)/starboard/shared/linux/dev_input/dev_input.cc',
'<(DEPTH)/starboard/shared/linux/get_home_directory.cc',
'<(DEPTH)/starboard/shared/linux/memory_get_stack_bounds.cc',
@@ -352,7 +353,6 @@
'<(DEPTH)/starboard/shared/starboard/window_set_default_options.cc',
'<(DEPTH)/starboard/shared/stub/accessibility_get_display_settings.cc',
'<(DEPTH)/starboard/shared/stub/accessibility_get_text_to_speech_settings.cc',
- '<(DEPTH)/starboard/shared/stub/cpu_features_get.cc',
'<(DEPTH)/starboard/shared/stub/cryptography_create_transformer.cc',
'<(DEPTH)/starboard/shared/stub/cryptography_destroy_transformer.cc',
'<(DEPTH)/starboard/shared/stub/cryptography_get_tag.cc',
diff --git a/src/starboard/raspi/shared/thread_create_priority.cc b/src/starboard/raspi/shared/thread_create_priority.cc
index b068feb..981c9d6 100644
--- a/src/starboard/raspi/shared/thread_create_priority.cc
+++ b/src/starboard/raspi/shared/thread_create_priority.cc
@@ -27,6 +27,19 @@
// This is the maximum priority that will be passed to SetRoundRobinScheduler().
const int kMaxRoundRobinPriority = 2;
+// Permissions are needed to allow usage non-default thread schedulers and
+// thread priorities. Specifically, /etc/security/limits.conf should set
+// "rtprio" and "nice" limits. "rtprio" will allow use of the real-time
+// schedulers, and "nice" will allow use of nice priorities as well as allow
+// SCHED_IDLE threads to increase their priority. If the user is 'pi', then
+// limits.conf should have the following lines:
+// @pi hard rtprio 99
+// @pi soft rtprio 99
+// @pi hard nice -20
+// @pi soft nice -20
+const char kSchedulerErrorMessage[] = "Unable to set scheduler. Please update "
+ "limits.conf to set 'rtprio' limit to 99 and 'nice' limit to -20.";
+
// Note that use of sched_setscheduler() has been found to be more reliably
// supported than pthread_setschedparam(), so we are using that.
@@ -34,14 +47,14 @@
struct sched_param thread_sched_param;
thread_sched_param.sched_priority = 0;
int result = sched_setscheduler(0, SCHED_IDLE, &thread_sched_param);
- SB_CHECK(result == 0);
+ SB_CHECK(result == 0) << kSchedulerErrorMessage;
}
void SetOtherScheduler() {
struct sched_param thread_sched_param;
thread_sched_param.sched_priority = 0;
int result = sched_setscheduler(0, SCHED_OTHER, &thread_sched_param);
- SB_CHECK(result == 0);
+ SB_CHECK(result == 0) << kSchedulerErrorMessage;
}
// Here |priority| is a number >= 0, where the higher the number, the
@@ -83,7 +96,7 @@
std::min(min_priority + priority,
static_cast<int>(rlimit_rtprio.rlim_cur));
int result = sched_setscheduler(0, SCHED_RR, &thread_sched_param);
- SB_CHECK(result == 0);
+ SB_CHECK(result == 0) << kSchedulerErrorMessage;
}
void ThreadSetPriority(SbThreadPriority priority) {
diff --git a/src/starboard/shared/blittergles/blitter_create_default_device.cc b/src/starboard/shared/blittergles/blitter_create_default_device.cc
index e7becb8..abec352 100644
--- a/src/starboard/shared/blittergles/blitter_create_default_device.cc
+++ b/src/starboard/shared/blittergles/blitter_create_default_device.cc
@@ -22,6 +22,8 @@
#include "starboard/common/optional.h"
#include "starboard/shared/blittergles/blitter_context.h"
#include "starboard/shared/blittergles/blitter_internal.h"
+#include "starboard/shared/blittergles/blitter_surface.h"
+#include "starboard/shared/blittergles/color_shader_program.h"
#include "starboard/shared/gles/gl_call.h"
#include "starboard/shared/x11/application_x11.h"
#include "starboard/window.h"
@@ -79,6 +81,21 @@
return starboard::nullopt;
}
+// When using Xvfb, the selected drivers will leak memory on the 1st call to
+// glDrawArrays(). We get that draw out of the way with a dummy draw here.
+void DummyDraw(SbBlitterContext context) {
+ SbBlitterSurface dummy_surface = SbBlitterCreateRenderTargetSurface(
+ context->device, 1, 1, kSbBlitterSurfaceFormatRGBA8);
+ SbBlitterSetRenderTarget(context, dummy_surface->render_target);
+ SbBlitterContextPrivate::ScopedCurrentContext scoped_current_context(context);
+ const starboard::shared::blittergles::ColorShaderProgram&
+ color_shader_program = context->GetColorShaderProgram();
+ color_shader_program.DummyDraw(dummy_surface->render_target);
+ context->current_render_target = kSbBlitterInvalidRenderTarget;
+ context->scissor = SbBlitterMakeRect(0, 0, 0, 0);
+ SbBlitterDestroySurface(dummy_surface);
+}
+
} // namespace
SbBlitterDevice SbBlitterCreateDefaultDevice() {
@@ -97,8 +114,17 @@
SB_DLOG(ERROR) << ": Failed to get EGL display connection.";
return kSbBlitterInvalidDevice;
}
- eglInitialize(device->display, NULL, NULL);
- if (eglGetError() != EGL_SUCCESS) {
+
+ // When running on Xvfb, sometimes ANGLE fails to open the default X display.
+ // By retrying, we increase the chances that eglInitialize() will succeed.
+ // This is a temporary fix.
+ int max_tries = 3, num_tries = 0;
+ bool initialized = false;
+ do {
+ initialized = eglInitialize(device->display, NULL, NULL);
+ ++num_tries;
+ } while (!initialized && num_tries < max_tries);
+ if (!initialized) {
SB_DLOG(ERROR) << ": Failed to initialize device.";
return kSbBlitterInvalidDevice;
}
@@ -120,5 +146,7 @@
starboard::ScopedLock context_lock(context_registry->mutex);
context_registry->context = context.release();
+ DummyDraw(context_registry->context);
+
return device_registry->default_device;
}
diff --git a/src/starboard/shared/blittergles/blitter_create_render_target_surface.cc b/src/starboard/shared/blittergles/blitter_create_render_target_surface.cc
index 7f5d2bf..6ed0927 100644
--- a/src/starboard/shared/blittergles/blitter_create_render_target_surface.cc
+++ b/src/starboard/shared/blittergles/blitter_create_render_target_surface.cc
@@ -46,7 +46,9 @@
surface->info.height = height;
surface->info.format = surface_format;
surface->color_texture_handle = 0;
- surface->SetTexture(NULL);
+ if (!surface->SetTexture(NULL)) {
+ return kSbBlitterInvalidSurface;
+ }
std::unique_ptr<SbBlitterRenderTargetPrivate> render_target(
new SbBlitterRenderTargetPrivate());
render_target->swap_chain = kSbBlitterInvalidSwapChain;
@@ -56,7 +58,9 @@
render_target->device = device;
render_target->framebuffer_handle = 0;
surface->render_target = render_target.release();
- surface->render_target->SetFramebuffer();
+ if (!surface->render_target->SetFramebuffer()) {
+ return kSbBlitterInvalidSurface;
+ }
return surface.release();
}
diff --git a/src/starboard/shared/blittergles/blitter_download_surface_pixels.cc b/src/starboard/shared/blittergles/blitter_download_surface_pixels.cc
index af006fb..2757b65 100644
--- a/src/starboard/shared/blittergles/blitter_download_surface_pixels.cc
+++ b/src/starboard/shared/blittergles/blitter_download_surface_pixels.cc
@@ -101,7 +101,9 @@
dummy_render_target->width = surface->info.width;
dummy_render_target->height = surface->info.height;
dummy_render_target->device = surface->device;
- dummy_render_target->SetFramebuffer();
+ if (!dummy_render_target->SetFramebuffer()) {
+ return false;
+ }
starboard::shared::blittergles::SbBlitterContextRegistry* context_registry =
starboard::shared::blittergles::GetBlitterContextRegistry();
diff --git a/src/starboard/shared/blittergles/blitter_internal.cc b/src/starboard/shared/blittergles/blitter_internal.cc
index fec01db..6661cbc 100644
--- a/src/starboard/shared/blittergles/blitter_internal.cc
+++ b/src/starboard/shared/blittergles/blitter_internal.cc
@@ -150,22 +150,22 @@
} // namespace shared
} // namespace starboard
-void SbBlitterRenderTargetPrivate::SetFramebuffer() {
+bool SbBlitterRenderTargetPrivate::SetFramebuffer() {
if (surface->color_texture_handle == 0) {
- return;
+ return false;
}
SbBlitterContextPrivate::ScopedCurrentContext scoped_current_context;
glGenFramebuffers(1, &framebuffer_handle);
if (framebuffer_handle == 0) {
SB_DLOG(ERROR) << ": Error creating new framebuffer.";
- return;
+ return false;
}
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_handle);
if (glGetError() != GL_NO_ERROR) {
GL_CALL(glDeleteFramebuffers(1, &framebuffer_handle));
framebuffer_handle = 0;
SB_DLOG(ERROR) << ": Error binding framebuffer.";
- return;
+ return false;
}
GL_CALL(glBindTexture(GL_TEXTURE_2D, surface->color_texture_handle));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
@@ -176,7 +176,7 @@
framebuffer_handle = 0;
surface->color_texture_handle = 0;
SB_DLOG(ERROR) << ": Error drawing empty image to framebuffer.";
- return;
+ return false;
}
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
@@ -186,7 +186,8 @@
framebuffer_handle = 0;
surface->color_texture_handle = 0;
SB_DLOG(ERROR) << ": Failed to create framebuffer.";
- return;
+ return false;
}
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
+ return true;
}
diff --git a/src/starboard/shared/blittergles/blitter_internal.h b/src/starboard/shared/blittergles/blitter_internal.h
index f62d717..2cc517a 100644
--- a/src/starboard/shared/blittergles/blitter_internal.h
+++ b/src/starboard/shared/blittergles/blitter_internal.h
@@ -91,8 +91,8 @@
GLuint framebuffer_handle;
// Sets framebuffer_handle and binds the texture from the surface field to it.
- // On failure, sets framebuffer_handle to 0.
- void SetFramebuffer();
+ // On failure, sets framebuffer_handle to 0 and returns false.
+ bool SetFramebuffer();
};
struct SbBlitterSwapChainPrivate {
diff --git a/src/starboard/shared/blittergles/blitter_surface.cc b/src/starboard/shared/blittergles/blitter_surface.cc
index 25054fd..06edbd6 100644
--- a/src/starboard/shared/blittergles/blitter_surface.cc
+++ b/src/starboard/shared/blittergles/blitter_surface.cc
@@ -29,22 +29,22 @@
}
}
-void SbBlitterSurfacePrivate::SetTexture(void* pixel_data) {
+bool SbBlitterSurfacePrivate::SetTexture(void* pixel_data) {
SbBlitterContextPrivate::ScopedCurrentContext scoped_current_context;
if (scoped_current_context.InitializationError()) {
- return;
+ return false;
}
glGenTextures(1, &color_texture_handle);
if (color_texture_handle == 0) {
SB_DLOG(ERROR) << ": Error creating new texture.";
- return;
+ return false;
}
glBindTexture(GL_TEXTURE_2D, color_texture_handle);
if (glGetError() != GL_NO_ERROR) {
GL_CALL(glDeleteTextures(1, &color_texture_handle));
color_texture_handle = 0;
SB_DLOG(ERROR) << ": Error binding new texture.";
- return;
+ return false;
}
GL_CALL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GL_CALL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
@@ -59,8 +59,9 @@
GL_CALL(glDeleteTextures(1, &color_texture_handle));
color_texture_handle = 0;
SB_DLOG(ERROR) << ": Error allocating new texture backing.";
- return;
+ return false;
}
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
+ return true;
}
diff --git a/src/starboard/shared/blittergles/blitter_surface.h b/src/starboard/shared/blittergles/blitter_surface.h
index c1d734b..cf0f29f 100644
--- a/src/starboard/shared/blittergles/blitter_surface.h
+++ b/src/starboard/shared/blittergles/blitter_surface.h
@@ -36,8 +36,8 @@
GLuint color_texture_handle;
// Sets the color_texture_handle field using given pixel_data. On failure,
- // resets color_texture_handle to 0.
- void SetTexture(void* pixel_data);
+ // resets color_texture_handle to 0 and returns false.
+ bool SetTexture(void* pixel_data);
};
#endif // STARBOARD_SHARED_BLITTERGLES_BLITTER_SURFACE_H_
diff --git a/src/starboard/shared/blittergles/color_shader_program.cc b/src/starboard/shared/blittergles/color_shader_program.cc
index d3978d0..38bbd83 100644
--- a/src/starboard/shared/blittergles/color_shader_program.cc
+++ b/src/starboard/shared/blittergles/color_shader_program.cc
@@ -15,6 +15,18 @@
#include "starboard/shared/blittergles/color_shader_program.h"
#include <GLES2/gl2.h>
+#if defined(ADDRESS_SANITIZER)
+// By default, Leak Sanitizer and Address Sanitizer is expected to exist
+// together. However, this is not true for all platforms.
+// HAS_LEAK_SANTIZIER=0 explicitly removes the Leak Sanitizer from code.
+#ifndef HAS_LEAK_SANITIZER
+#define HAS_LEAK_SANITIZER 1
+#endif // HAS_LEAK_SANITIZER
+#endif // defined(ADDRESS_SANITIZER)
+
+#if HAS_LEAK_SANITIZER
+#include <sanitizer/lsan_interface.h>
+#endif // HAS_LEAK_SANITIZER
#include "starboard/blitter.h"
#include "starboard/shared/blittergles/blitter_internal.h"
@@ -75,6 +87,29 @@
return success;
}
+void ColorShaderProgram::DummyDraw(SbBlitterRenderTarget render_target) const {
+ GL_CALL(glUseProgram(GetProgramHandle()));
+
+ float vertices[8];
+ SetNDC(SbBlitterMakeRect(0, 0, 1, 1), render_target->width,
+ render_target->height, vertices);
+ GL_CALL(glVertexAttribPointer(kPositionAttribute, 2, GL_FLOAT, GL_FALSE, 0,
+ vertices));
+ GL_CALL(glEnableVertexAttribArray(kPositionAttribute));
+ GL_CALL(glVertexAttrib4f(kColorAttribute, 0.0f, 0.0f, 0.0f, 0.0f));
+
+#if HAS_LEAK_SANITIZER
+ __lsan_disable();
+#endif // HAS_LEAK_SANITIZER
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+#if HAS_LEAK_SANITIZER
+ __lsan_enable();
+#endif // HAS_LEAK_SANITIZER
+
+ GL_CALL(glDisableVertexAttribArray(kPositionAttribute));
+ GL_CALL(glUseProgram(0));
+}
+
} // namespace blittergles
} // namespace shared
} // namespace starboard
diff --git a/src/starboard/shared/blittergles/color_shader_program.h b/src/starboard/shared/blittergles/color_shader_program.h
index a682a5a..e99dfdd 100644
--- a/src/starboard/shared/blittergles/color_shader_program.h
+++ b/src/starboard/shared/blittergles/color_shader_program.h
@@ -33,6 +33,10 @@
float (&color_rgba)[4],
SbBlitterRect rect) const;
+ // Method that draws a 1x1 transparent rectangle and disables leak sanitizer
+ // around glDrawArrays().
+ void DummyDraw(SbBlitterRenderTarget render_target) const;
+
private:
// Location of the shader attribute "a_position" for the color shader.
static const int kPositionAttribute = 0;
diff --git a/src/starboard/shared/linux/cpu_features_get.cc b/src/starboard/shared/linux/cpu_features_get.cc
new file mode 100644
index 0000000..d8ce245
--- /dev/null
+++ b/src/starboard/shared/linux/cpu_features_get.cc
@@ -0,0 +1,515 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/cpu_features.h"
+
+#include <dlfcn.h> // dlsym, dlclose, dlopen
+#include <linux/auxvec.h> // AT_HWCAP
+#include <stdio.h> // fopen, fclose
+#include <string.h>
+#include <strings.h> // strcasecmp
+#include <sys/auxv.h>
+#include <unistd.h> // sysconf()
+#include <memory>
+
+#include <cstdlib>
+
+#include "starboard/common/log.h"
+#include "starboard/shared/starboard/cpu_features.h"
+
+#if SB_API_VERSION >= 11
+
+namespace {
+
+// See <asm/hwcap.h> kernel header.
+#define HWCAP_VFP (1 << 6)
+#define HWCAP_IWMMXT (1 << 9)
+#define HWCAP_NEON (1 << 12)
+#define HWCAP_VFPv3 (1 << 13)
+#define HWCAP_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */
+#define HWCAP_VFPv4 (1 << 16)
+#define HWCAP_IDIVA (1 << 17)
+#define HWCAP_IDIVT (1 << 18)
+#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */
+#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
+
+// see <uapi/asm/hwcap.h> kernel header
+#define HWCAP2_AES (1 << 0)
+#define HWCAP2_PMULL (1 << 1)
+#define HWCAP2_SHA1 (1 << 2)
+#define HWCAP2_SHA2 (1 << 3)
+#define HWCAP2_CRC32 (1 << 4)
+
+// Preset hwcap for Armv8
+#define HWCAP_SET_FOR_ARMV8 \
+ (HWCAP_VFP | HWCAP_NEON | HWCAP_VFPv3 | HWCAP_VFPv4 | HWCAP_IDIV)
+
+using starboard::shared::SetX86FeaturesInvalid;
+using starboard::shared::SetArmFeaturesInvalid;
+using starboard::shared::SetGeneralFeaturesInvalid;
+
+// Checks if a space-separated list of items |list|, in the form of a string,
+// contains one given item |item|.
+bool HasItemInList(const char* list, const char* flag) {
+ ssize_t flag_length = strlen(flag);
+ const char* list_ptr = list;
+ if (list_ptr == nullptr) {
+ return false;
+ }
+ while (*list_ptr != '\0') {
+ // Skip whitespace.
+ while (isspace(*list_ptr))
+ ++list_ptr;
+
+ // Find end of current list flag.
+ const char* end_ptr = list_ptr;
+ while (*end_ptr != '\0' && !isspace(*end_ptr))
+ ++end_ptr;
+
+ if (flag_length == end_ptr - list_ptr &&
+ memcmp(list_ptr, flag, flag_length) == 0) {
+ return true;
+ }
+
+ // Continue to the next flag.
+ list_ptr = end_ptr;
+ }
+ return false;
+}
+
+// Class that holds the information in system file /proc/cpuinfo.
+class ProcCpuInfo {
+ // Raw data of the file /proc/cpuinfo
+ std::unique_ptr<char[]> file_data_;
+ // Size of the raw data
+ size_t file_data_size_;
+
+ public:
+ explicit ProcCpuInfo(const char* file_path = "/proc/cpuinfo") {
+ file_data_size_ = 0;
+ // Get the size of the cpuinfo file by reading it until the end. This is
+ // required because files under /proc do not always return a valid size
+ // when using fseek(0, SEEK_END) + ftell(). Nor can the be mmap()-ed.
+ FILE* file = fopen(file_path, "r");
+ if (file != nullptr) {
+ for (;;) {
+ char file_buffer[256];
+ size_t data_size = fread(file_buffer, 1, sizeof(file_buffer), file);
+ if (data_size == 0) {
+ break;
+ }
+ file_data_size_ += data_size;
+ }
+ fclose(file);
+ }
+
+ // Read the contents of the cpuinfo file.
+ file_data_ = std::unique_ptr<char[]>(new char[file_data_size_ + 1]);
+ char* file_data_ptr = file_data_.get();
+ memset(file_data_ptr, 0, file_data_size_ + 1);
+
+ file = fopen(file_path, "r");
+ if (file != nullptr) {
+ for (size_t offset = 0; offset < file_data_size_;) {
+ size_t data_size =
+ fread(file_data_ptr + offset, 1, file_data_size_ - offset, file);
+ if (data_size == 0) {
+ break;
+ }
+ offset += data_size;
+ }
+ fclose(file);
+ }
+
+ // Zero-terminate the data.
+ file_data_ptr[file_data_size_] = '\0';
+ }
+ ~ProcCpuInfo() { file_data_.reset(); }
+
+ // Extract the string feature data named by |feature| and store in
+ // |out_feature| whose size is |out_feature_size|.
+ bool ExtractStringFeature(const char* feature,
+ char* out_feature,
+ size_t out_feature_size) {
+ if (feature == nullptr) {
+ return false;
+ }
+
+ // Look for first feature occurrence, and ensure it starts the line.
+ size_t feature_name_size = strlen(feature);
+ const char* feature_ptr = nullptr;
+ char* file_data_ptr = file_data_.get();
+
+ const char* line_start_ptr = file_data_.get();
+ while (line_start_ptr < file_data_ptr + file_data_size_) {
+ // Find the end of the line.
+ const char* line_end_ptr = strchr(line_start_ptr, '\n');
+ if (line_end_ptr == nullptr) {
+ line_end_ptr = file_data_ptr + file_data_size_;
+ }
+
+ char line_buffer[line_end_ptr - line_start_ptr +
+ 1]; // NOLINT(runtime/arrays)
+ memset(line_buffer, 0, sizeof(line_buffer));
+ memcpy(line_buffer, line_start_ptr, line_end_ptr - line_start_ptr);
+ line_buffer[line_end_ptr - line_start_ptr] = '\0';
+
+ // Find the colon
+ const char* colon_ptr = strchr(line_buffer, ':');
+ if (colon_ptr == nullptr || !isspace(colon_ptr[1])) {
+ line_start_ptr = line_end_ptr + 1;
+ continue;
+ }
+
+ line_buffer[colon_ptr - line_buffer] = '\0';
+
+ // Trim trailing white space of the line before colon
+ const char* feature_end_ptr = colon_ptr - 1;
+ while (feature_end_ptr >= line_buffer &&
+ isspace(line_buffer[feature_end_ptr - line_buffer])) {
+ line_buffer[feature_end_ptr - line_buffer] = '\0';
+ feature_end_ptr--;
+ }
+ // Out of boundary
+ if (feature_end_ptr < line_buffer) {
+ line_start_ptr = line_end_ptr + 1;
+ continue;
+ }
+ // Trim leading white space of the line
+ const char* feature_start_ptr = line_buffer;
+ while (feature_start_ptr <= feature_end_ptr &&
+ isspace(line_buffer[feature_start_ptr - line_buffer])) {
+ line_buffer[feature_start_ptr - line_buffer] = '\0';
+ feature_start_ptr++;
+ }
+ // There is no need to check feature_start_ptr out of boundary, because if
+ // feature_start_ptr > feature_end_ptr, it means the line before colon is
+ // all white space, and feature_end_ptr will be out of boundary already.
+
+ if (strcmp(feature_start_ptr, feature) != 0) {
+ line_start_ptr = line_end_ptr + 1;
+ continue;
+ }
+
+ feature_ptr = colon_ptr + 2 - line_buffer + line_start_ptr;
+ break;
+ }
+
+ if (feature_ptr == nullptr) {
+ return false;
+ }
+
+ // Find the end of the line.
+ const char* line_end_ptr = strchr(feature_ptr, '\n');
+ if (line_end_ptr == nullptr) {
+ line_end_ptr = file_data_ptr + file_data_size_;
+ }
+
+ // Get the size of the feature data
+ int feature_size = line_end_ptr - feature_ptr;
+
+ if (out_feature_size < feature_size + 1) {
+ SB_LOG(WARNING) << "CPU Feature " << feature << " is truncated.";
+ feature_size = out_feature_size - 1;
+ }
+ memcpy(out_feature, feature_ptr, feature_size);
+ out_feature[feature_size] = '\0';
+
+ return true;
+ }
+
+ // Extract a integer feature field identified by |feature| from /proc/cpuinfo
+ int ExtractIntegerFeature(const char* feature) {
+ int feature_data = -1;
+ // Allocate 128 bytes for an integer field.
+ char feature_buffer[128] = {0};
+ if (!ExtractStringFeature(
+ feature, feature_buffer,
+ sizeof(feature_buffer) / sizeof(feature_buffer[0]))) {
+ return feature_data;
+ }
+
+ char* end;
+ feature_data = static_cast<int>(strtol(feature_buffer, &end, 0));
+ if (end == feature_buffer) {
+ feature_data = -1;
+ }
+ return feature_data;
+ }
+};
+
+// Check if getauxval() is supported
+bool IsGetauxvalSupported() {
+ // TODO: figure out which linking flags are needed to use
+ // dl* functions. Currently the linker complains symbols
+ // like "__dlopen" undefined, even though "-ldl" and "-lc"
+ // are added to linker flags.
+
+ // dlerror();
+ // void* libc_handle = dlopen("libc.so", RTLD_NOW);
+ // if (!libc_handle) {
+ // printf("Could not dlopen() C library: %s\n", dlerror());
+ // return false;
+ // }
+
+ // typedef unsigned long getauxval_func_t(unsigned long);
+ // getauxval_func_t* func = (getauxval_func_t*)
+ // dlsym(libc_handle, "getauxval");
+ // if (!func) {
+ // printf("Could not find getauxval() in C library\n");
+ // return false;
+ // }
+ // dlclose(libc_handle);
+ return true;
+}
+
+// Get hwcap bitmask by getauxval() or by reading /proc/self/auxv
+uint32_t ReadElfHwcaps(uint32_t hwcap_type) {
+ uint32_t hwcap = 0;
+ if (IsGetauxvalSupported()) {
+ hwcap = static_cast<uint32_t>(getauxval(hwcap_type));
+ } else {
+ // Read the ELF HWCAP flags by parsing /proc/self/auxv.
+ FILE* file_ptr = fopen("/proc/self/auxv", "r");
+ if (file_ptr == nullptr) {
+ return hwcap;
+ }
+ struct {
+ uint32_t tag;
+ uint32_t value;
+ } entry;
+ for (;;) {
+ size_t n = fread(&entry, sizeof(entry), 1, file_ptr);
+ if (n == 0 || (entry.tag == 0 && entry.value == 0)) {
+ break;
+ }
+ if (entry.tag == hwcap_type) {
+ hwcap = entry.value;
+ break;
+ }
+ }
+ fclose(file_ptr);
+ }
+ return hwcap;
+}
+
+// Construct hwcap bitmask by the feature flags in /proc/cpuinfo
+uint32_t ConstructHwcapFromCPUInfo(ProcCpuInfo* cpu_info,
+ int16_t architecture_generation,
+ uint32_t hwcap_type) {
+ if (hwcap_type == AT_HWCAP && architecture_generation >= 8) {
+ // This is a 32-bit ARM binary running on a 64-bit ARM64 kernel.
+ // The 'Features' line only lists the optional features that the
+ // device's CPU supports, compared to its reference architecture
+ // which are of no use for this process.
+ SB_LOG(INFO) << "Faking 32-bit ARM HWCaps on ARMv"
+ << architecture_generation;
+ return HWCAP_SET_FOR_ARMV8;
+ }
+
+ uint32_t hwcap_value = 0;
+
+ // Allocate 1024 bytes for "Features", which is a list of flags.
+ char flags_buffer[1024] = {0};
+ if (!cpu_info->ExtractStringFeature(
+ "Features", flags_buffer,
+ sizeof(flags_buffer) / sizeof(flags_buffer[0]))) {
+ return hwcap_value;
+ }
+
+ if (hwcap_type == AT_HWCAP) {
+ hwcap_value |= HasItemInList(flags_buffer, "vfp") ? HWCAP_VFP : 0;
+ hwcap_value |= HasItemInList(flags_buffer, "vfpv3") ? HWCAP_VFPv3 : 0;
+ hwcap_value |= HasItemInList(flags_buffer, "vfpv3d16") ? HWCAP_VFPv3D16 : 0;
+ hwcap_value |= HasItemInList(flags_buffer, "vfpv4") ? HWCAP_VFPv4 : 0;
+ hwcap_value |= HasItemInList(flags_buffer, "neon") ? HWCAP_NEON : 0;
+ hwcap_value |= HasItemInList(flags_buffer, "idiva") ? HWCAP_IDIVA : 0;
+ hwcap_value |= HasItemInList(flags_buffer, "idivt") ? HWCAP_IDIVT : 0;
+ hwcap_value |=
+ HasItemInList(flags_buffer, "idiv") ? (HWCAP_IDIVA | HWCAP_IDIVT) : 0;
+ hwcap_value |= HasItemInList(flags_buffer, "iwmmxt") ? HWCAP_IWMMXT : 0;
+ } else if (hwcap_type == AT_HWCAP2) {
+ hwcap_value |= HasItemInList(flags_buffer, "aes") ? HWCAP2_AES : 0;
+ hwcap_value |= HasItemInList(flags_buffer, "pmull") ? HWCAP2_PMULL : 0;
+ hwcap_value |= HasItemInList(flags_buffer, "sha1") ? HWCAP2_SHA1 : 0;
+ hwcap_value |= HasItemInList(flags_buffer, "sha2") ? HWCAP2_SHA2 : 0;
+ hwcap_value |= HasItemInList(flags_buffer, "crc32") ? HWCAP2_CRC32 : 0;
+ }
+ return hwcap_value;
+}
+
+bool SbCPUFeaturesGet_ARM(SbCPUFeatures* features) {
+ memset(features, 0, sizeof(*features));
+
+ // Raspi is a 32-bit ARM platform.
+ features->architecture = kSbCPUFeaturesArchitectureArm;
+
+ // Set the default value of the features to be invalid, then fill them in
+ // if appropriate.
+ SetGeneralFeaturesInvalid(features);
+ SetArmFeaturesInvalid(features);
+ SetX86FeaturesInvalid(features);
+
+ ProcCpuInfo cpu_info;
+
+ // Extract CPU implementor, variant, revision and part information, which
+ // are all integers.
+ features->arm.implementer = cpu_info.ExtractIntegerFeature("CPU implementer");
+ features->arm.variant = cpu_info.ExtractIntegerFeature("CPU variant");
+ features->arm.revision = cpu_info.ExtractIntegerFeature("CPU revision");
+ features->arm.part = cpu_info.ExtractIntegerFeature("CPU part");
+
+ // Extract CPU architecture generation from the "CPU Architecture" field.
+ // Allocate 128 bytes for "CPU architecture", which is an integer field.
+ char architecture_buffer[128] = {0};
+ if (cpu_info.ExtractStringFeature(
+ "CPU architecture", architecture_buffer,
+ sizeof(architecture_buffer) / sizeof(architecture_buffer[0]))) {
+ char* end;
+ features->arm.architecture_generation =
+ static_cast<int>(strtol(architecture_buffer, &end, 10));
+ if (end == architecture_buffer) {
+ // Kernels older than 3.18 report "CPU architecture: AArch64" on ARMv8.
+ if (strcasecmp(architecture_buffer, "AArch64") == 0) {
+ features->arm.architecture_generation = 8;
+ } else {
+ features->arm.architecture_generation = -1;
+ }
+ }
+
+ // Unfortunately, it seems that certain ARMv6-based CPUs
+ // report an incorrect architecture number of 7!
+ //
+ // See http://code.google.com/p/android/issues/detail?id=10812
+ //
+ // We try to correct this by looking at the 'elf_platform'
+ // feature reported by the 'Processor' field or 'model name'
+ // field in Linux v3.8, which is of the form of "(v7l)" for an
+ // ARMv7-based CPU, and "(v6l)" for an ARMv6-one. For example,
+ // the Raspberry Pi is one popular ARMv6 device that reports
+ // architecture 7. The 'Processor' or 'model name' fields
+ // also contain processor brand information.
+
+ // Allocate 256 bytes for "Processor"/"model name" field.
+ static char brand_buffer[256] = {0};
+ if (!cpu_info.ExtractStringFeature(
+ "Processor", brand_buffer,
+ sizeof(brand_buffer) / sizeof(brand_buffer[0]))) {
+ if (cpu_info.ExtractStringFeature(
+ "model name", brand_buffer,
+ sizeof(brand_buffer) / sizeof(brand_buffer[0]))) {
+ features->brand = brand_buffer;
+ if (features->arm.architecture_generation == 7 &&
+ HasItemInList(features->brand, "(v6l)")) {
+ features->arm.architecture_generation = 6;
+ }
+ }
+ }
+ }
+
+ // Get hwcap bitmask and extract the CPU feature flags from it.
+ features->hwcap = ReadElfHwcaps(AT_HWCAP);
+ if (features->hwcap == 0) {
+ features->hwcap = ConstructHwcapFromCPUInfo(
+ &cpu_info, features->arm.architecture_generation, AT_HWCAP);
+ }
+
+ features->arm.has_idiva = (features->hwcap & HWCAP_IDIVA) != 0;
+ features->arm.has_neon = (features->hwcap & HWCAP_NEON) != 0;
+ features->arm.has_vfp = (features->hwcap & HWCAP_VFP) != 0;
+ features->arm.has_vfp3 = (features->hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16 |
+ HWCAP_VFPv4 | HWCAP_NEON)) != 0;
+ features->arm.has_vfp3_d32 =
+ (features->arm.has_vfp3 && ((features->hwcap & HWCAP_VFPv3D16) == 0 ||
+ (features->hwcap & HWCAP_VFPD32) != 0));
+ features->arm.has_vfp3_d32 =
+ features->arm.has_vfp3_d32 || features->arm.has_neon;
+
+ // Some old kernels will report vfp not vfpv3. Here we make an attempt
+ // to detect vfpv3 by checking for vfp *and* neon, since neon is only
+ // available on architectures with vfpv3. Checking neon on its own is
+ // not enough as it is possible to have neon without vfp.
+ if (features->arm.has_vfp && features->arm.has_neon) {
+ features->arm.has_vfp3 = true;
+ }
+
+ // VFPv3 implies ARMv7, see ARM DDI 0406B, page A1-6.
+ if (features->arm.architecture_generation < 7 && features->arm.has_vfp3) {
+ features->arm.architecture_generation = 7;
+ }
+
+ // ARMv7 implies Thumb2.
+ if (features->arm.architecture_generation >= 7) {
+ features->arm.has_thumb2 = true;
+ }
+
+ // The earliest architecture with Thumb2 is ARMv6T2.
+ if (features->arm.has_thumb2 && features->arm.architecture_generation < 6) {
+ features->arm.architecture_generation = 6;
+ }
+
+ // We don't support any FPUs other than VFP.
+ features->has_fpu = features->arm.has_vfp;
+
+ // The following flags are always supported by ARMv8, as mandated by the ARM
+ // Architecture Reference Manual.
+ if (features->arm.architecture_generation >= 8) {
+ features->arm.has_idiva = true;
+ features->arm.has_neon = true;
+ features->arm.has_thumb2 = true;
+ features->arm.has_vfp = true;
+ features->arm.has_vfp3 = true;
+ }
+
+ // Read hwcaps2 bitmask and extract the CPU feature flags from it.
+ features->hwcap2 = ReadElfHwcaps(AT_HWCAP2);
+ if (features->hwcap2 == 0) {
+ features->hwcap2 = ConstructHwcapFromCPUInfo(
+ &cpu_info, features->arm.architecture_generation, AT_HWCAP2);
+ }
+
+ features->arm.has_aes = (features->hwcap2 & HWCAP2_AES) != 0;
+ features->arm.has_pmull = (features->hwcap2 & HWCAP2_PMULL) != 0;
+ features->arm.has_sha1 = (features->hwcap2 & HWCAP2_PMULL) != 0;
+ features->arm.has_sha2 = (features->hwcap2 & HWCAP2_SHA2) != 0;
+ features->arm.has_crc32 = (features->hwcap2 & HWCAP2_CRC32) != 0;
+
+ // Get L1 ICACHE and DCACHE line size.
+ features->icache_line_size = sysconf(_SC_LEVEL1_ICACHE_LINESIZE);
+ features->dcache_line_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
+
+ return true;
+}
+
+} // namespace
+
+// TODO: Only ARM is currently implemented and tested
+bool SbCPUFeaturesGet(SbCPUFeatures* features) {
+#if SB_IS(ARCH_ARM)
+ return SbCPUFeaturesGet_ARM(features);
+#else
+ SB_NOTIMPLEMENTED();
+
+ memset(features, 0, sizeof(*features));
+ features->architecture = kSbCPUFeaturesArchitectureUnknown;
+
+ SetGeneralFeaturesInvalid(features);
+ SetArmFeaturesInvalid(features);
+ SetX86FeaturesInvalid(features);
+
+ return false;
+#endif
+}
+
+#endif // SB_API_VERSION >= 11
diff --git a/src/starboard/shared/starboard/audio_sink/audio_sink_create.cc b/src/starboard/shared/starboard/audio_sink/audio_sink_create.cc
index 36fa34b..00605fc 100644
--- a/src/starboard/shared/starboard/audio_sink/audio_sink_create.cc
+++ b/src/starboard/shared/starboard/audio_sink/audio_sink_create.cc
@@ -93,10 +93,14 @@
}
if (auto type = SbAudioSinkPrivate::GetFallbackType()) {
+ SB_LOG(WARNING) << "Primary audio sink failed to create, use fallback.";
return type->Create(channels, sampling_frequency_hz, audio_sample_type,
audio_frame_storage_type, frame_buffers,
frame_buffers_size_in_frames, update_source_status_func,
consume_frames_func, context);
+ } else {
+ SB_LOG(WARNING) << "Primary audio sink failed to create,"
+ << " fallback is not enabled.";
}
return kSbAudioSinkInvalid;
diff --git a/src/starboard/shared/starboard/cpu_features.h b/src/starboard/shared/starboard/cpu_features.h
new file mode 100644
index 0000000..6641ee8
--- /dev/null
+++ b/src/starboard/shared/starboard/cpu_features.h
@@ -0,0 +1,65 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+// Module Overview: Starboard CPU features API
+
+// Provide helper classes, macros and functions useful to the implementations of
+// Starboard CPU features API on all platforms
+
+#ifndef STARBOARD_SHARED_STARBOARD_CPU_FEATURES_H_
+#define STARBOARD_SHARED_STARBOARD_CPU_FEATURES_H_
+
+#include "starboard/cpu_features.h"
+
+#if SB_API_VERSION >= 11
+
+namespace starboard {
+namespace shared {
+
+// Set the general features of SbCPUFeatures to be invalid
+inline void SetGeneralFeaturesInvalid(SbCPUFeatures* features) {
+ features->brand = "";
+ features->icache_line_size = -1;
+ features->dcache_line_size = -1;
+ features->hwcap = 0;
+ features->hwcap2 = 0;
+}
+
+// Set the features of SbCPUFeatures.x86 to be invalid
+inline void SetX86FeaturesInvalid(SbCPUFeatures* features) {
+ features->x86.vendor = "";
+ features->x86.family = -1;
+ features->x86.ext_family = -1;
+ features->x86.model = -1;
+ features->x86.ext_model = -1;
+ features->x86.stepping = -1;
+ features->x86.type = -1;
+ features->x86.signature = -1;
+}
+
+// Set the features of SbCPUFeatures.arm to be invalid
+inline void SetArmFeaturesInvalid(SbCPUFeatures* features) {
+ features->arm.implementer = -1;
+ features->arm.variant = -1;
+ features->arm.revision = -1;
+ features->arm.architecture_generation = -1;
+ features->arm.part = -1;
+}
+
+} // namespace shared
+} // namespace starboard
+
+#endif // SB_API_VERSION >= 11
+
+#endif // STARBOARD_SHARED_STARBOARD_CPU_FEATURES_H_
diff --git a/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.cc b/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.cc
index d85f33e..8b06d66 100644
--- a/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.cc
@@ -14,6 +14,8 @@
#include "starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.h"
+#include "starboard/audio_sink.h"
+#include "starboard/common/log.h"
#include "starboard/common/reset_and_return.h"
namespace starboard {
@@ -25,6 +27,33 @@
using common::ResetAndReturn;
#if SB_API_VERSION >= 11
+SbMediaAudioSampleType GetDefaultSupportedAudioSampleType() {
+ if (SbAudioSinkIsAudioSampleTypeSupported(kSbMediaAudioSampleTypeFloat32)) {
+ return kSbMediaAudioSampleTypeFloat32;
+ }
+ if (SbAudioSinkIsAudioSampleTypeSupported(
+ kSbMediaAudioSampleTypeInt16Deprecated)) {
+ return kSbMediaAudioSampleTypeInt16Deprecated;
+ }
+ SB_NOTREACHED();
+ return kSbMediaAudioSampleTypeFloat32;
+}
+
+SbMediaAudioFrameStorageType GetDefaultSupportedAudioFrameStorageType() {
+ if (SbAudioSinkIsAudioFrameStorageTypeSupported(
+ kSbMediaAudioFrameStorageTypeInterleaved)) {
+ return kSbMediaAudioFrameStorageTypeInterleaved;
+ }
+ SB_NOTREACHED();
+ return kSbMediaAudioFrameStorageTypeInterleaved;
+}
+
+int GetDefaultSupportedAudioSamplesPerSecond() {
+ const int kDefaultOutputSamplesPerSecond = 48000;
+ return SbAudioSinkGetNearestSupportedSampleFrequency(
+ kDefaultOutputSamplesPerSecond);
+}
+
bool IsResetDecoderNecessary(const SbMediaAudioSampleInfo& current_info,
const SbMediaAudioSampleInfo& new_info) {
if (current_info.codec != new_info.codec) {
@@ -118,6 +147,16 @@
if (audio_decoder_) {
audio_decoder_->WriteEndOfStream();
} else {
+ // It's possible that WriteEndOfStream() is called without any
+ // other input. In that case, we need to give |output_sample_type_|,
+ // |output_storage_type_| and |output_samples_per_second_| default
+ // value.
+ if (!first_output_received_) {
+ first_output_received_ = true;
+ output_sample_type_ = GetDefaultSupportedAudioSampleType();
+ output_storage_type_ = GetDefaultSupportedAudioFrameStorageType();
+ output_samples_per_second_ = GetDefaultSupportedAudioSamplesPerSecond();
+ }
decoded_audios_.push(new DecodedAudio);
Schedule(output_cb_);
}
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_internal.cc b/src/starboard/shared/starboard/player/filter/audio_renderer_internal.cc
index 479ce16..996f9aa 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_internal.cc
@@ -518,6 +518,7 @@
max_cached_frames_, this);
if (!audio_renderer_sink_->HasStarted()) {
#if SB_HAS(PLAYER_ERROR_MESSAGE)
+ SB_LOG(ERROR) << "Failed to start audio sink.";
error_cb_(kSbPlayerErrorDecode, "failed to start audio sink");
#else // SB_HAS(PLAYER_ERROR_MESSAGE)
error_cb_();
@@ -721,7 +722,8 @@
<< " time since last check, which is too frequently.";
}
- sink_callbacks_since_last_check_.store(0);
+ auto sink_callbacks_since_last_check =
+ sink_callbacks_since_last_check_.exchange(0);
if (paused_ || playback_rate_ == 0.0) {
return;
@@ -735,7 +737,9 @@
<< elapsed / kSbTimeSecond << " seconds, with "
<< total_frames_sent_to_sink_ -
total_frames_consumed_by_sink_
- << " frames in sink.";
+ << " frames in sink, " << (underflow_ ? "underflow, " : "")
+ << sink_callbacks_since_last_check
+ << " callbacks since last check.";
}
Schedule(std::bind(&AudioRenderer::CheckAudioSinkStatus, this),
kCheckAudioSinkStatusInterval);
diff --git a/src/starboard/shared/starboard/player/filter/player_components.cc b/src/starboard/shared/starboard/player/filter/player_components.cc
new file mode 100644
index 0000000..74e3cb3
--- /dev/null
+++ b/src/starboard/shared/starboard/player/filter/player_components.cc
@@ -0,0 +1,123 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/starboard/player/filter/player_components.h"
+
+#include "starboard/shared/starboard/application.h"
+#include "starboard/shared/starboard/command_line.h"
+#include "starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.h"
+#include "starboard/shared/starboard/player/filter/audio_renderer_sink_impl.h"
+#include "starboard/shared/starboard/player/filter/punchout_video_renderer_sink.h"
+#include "starboard/shared/starboard/player/filter/stub_audio_decoder.h"
+#include "starboard/shared/starboard/player/filter/stub_video_decoder.h"
+#include "starboard/shared/starboard/player/filter/video_render_algorithm_impl.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace player {
+namespace filter {
+
+scoped_ptr<AudioRenderer> PlayerComponents::CreateAudioRenderer(
+ const AudioParameters& audio_parameters) {
+ scoped_ptr<AudioDecoder> audio_decoder;
+ scoped_ptr<AudioRendererSink> audio_renderer_sink;
+
+ auto command_line = shared::starboard::Application::Get()->GetCommandLine();
+ if (command_line->HasSwitch("use_stub_audio_decoder")) {
+ CreateStubAudioComponents(audio_parameters, &audio_decoder,
+ &audio_renderer_sink);
+ } else {
+ CreateAudioComponents(audio_parameters, &audio_decoder,
+ &audio_renderer_sink);
+ }
+ if (!audio_decoder || !audio_renderer_sink) {
+ return scoped_ptr<AudioRenderer>();
+ }
+ int max_cached_frames, max_frames_per_append;
+ GetAudioRendererParams(&max_cached_frames, &max_frames_per_append);
+ return make_scoped_ptr(
+ new AudioRenderer(audio_decoder.Pass(), audio_renderer_sink.Pass(),
+ audio_parameters.audio_sample_info, max_cached_frames,
+ max_frames_per_append));
+}
+
+scoped_ptr<VideoRenderer> PlayerComponents::CreateVideoRenderer(
+ const VideoParameters& video_parameters,
+ MediaTimeProvider* media_time_provider) {
+ scoped_ptr<VideoDecoder> video_decoder;
+ scoped_ptr<VideoRenderAlgorithm> video_render_algorithm;
+ scoped_refptr<VideoRendererSink> video_renderer_sink;
+
+ auto command_line = shared::starboard::Application::Get()->GetCommandLine();
+ if (command_line->HasSwitch("use_stub_video_decoder")) {
+ CreateStubVideoComponents(video_parameters, &video_decoder,
+ &video_render_algorithm, &video_renderer_sink);
+ } else {
+ CreateVideoComponents(video_parameters, &video_decoder,
+ &video_render_algorithm, &video_renderer_sink);
+ }
+ if (!video_decoder || !video_render_algorithm) {
+ return scoped_ptr<VideoRenderer>();
+ }
+ return make_scoped_ptr(
+ new VideoRenderer(video_decoder.Pass(), media_time_provider,
+ video_render_algorithm.Pass(), video_renderer_sink));
+}
+
+void PlayerComponents::CreateStubAudioComponents(
+ const AudioParameters& audio_parameters,
+ scoped_ptr<AudioDecoder>* audio_decoder,
+ scoped_ptr<AudioRendererSink>* audio_renderer_sink) {
+ SB_DCHECK(audio_decoder);
+ SB_DCHECK(audio_renderer_sink);
+
+#if SB_API_VERSION >= 11
+ auto decoder_creator = [](const SbMediaAudioSampleInfo& audio_sample_info,
+ SbDrmSystem drm_system) {
+ return scoped_ptr<AudioDecoder>(
+ new StubAudioDecoder(audio_sample_info.codec, audio_sample_info));
+ };
+ audio_decoder->reset(
+ new AdaptiveAudioDecoder(audio_parameters.audio_sample_info,
+ audio_parameters.drm_system, decoder_creator));
+#else // SB_API_VERSION >= 11
+ audio_decoder->reset(new StubAudioDecoder(
+ audio_parameters.audio_codec, audio_parameters.audio_sample_info));
+#endif // SB_API_VERISON >= 11
+ audio_renderer_sink->reset(new AudioRendererSinkImpl);
+}
+
+void PlayerComponents::CreateStubVideoComponents(
+ const VideoParameters& video_parameters,
+ scoped_ptr<VideoDecoder>* video_decoder,
+ scoped_ptr<VideoRenderAlgorithm>* video_render_algorithm,
+ scoped_refptr<VideoRendererSink>* video_renderer_sink) {
+ const SbTime kVideoSinkRenderInterval = 10 * kSbTimeMillisecond;
+
+ SB_DCHECK(video_decoder);
+ SB_DCHECK(video_render_algorithm);
+ SB_DCHECK(video_renderer_sink);
+
+ video_decoder->reset(new StubVideoDecoder);
+ video_render_algorithm->reset(new VideoRenderAlgorithmImpl);
+ *video_renderer_sink = new PunchoutVideoRendererSink(
+ video_parameters.player, kVideoSinkRenderInterval);
+}
+
+} // namespace filter
+} // namespace player
+} // namespace starboard
+} // namespace shared
+} // namespace starboard
diff --git a/src/starboard/shared/starboard/player/filter/player_components.h b/src/starboard/shared/starboard/player/filter/player_components.h
index 983f207..a73ac46 100644
--- a/src/starboard/shared/starboard/player/filter/player_components.h
+++ b/src/starboard/shared/starboard/player/filter/player_components.h
@@ -22,22 +22,14 @@
#include "starboard/media.h"
#include "starboard/player.h"
#include "starboard/shared/internal_only.h"
-#include "starboard/shared/starboard/application.h"
-#include "starboard/shared/starboard/command_line.h"
#include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
#include "starboard/shared/starboard/player/filter/audio_renderer_internal.h"
#include "starboard/shared/starboard/player/filter/audio_renderer_sink.h"
-#include "starboard/shared/starboard/player/filter/audio_renderer_sink_impl.h"
#include "starboard/shared/starboard/player/filter/media_time_provider.h"
-#include "starboard/shared/starboard/player/filter/punchout_video_renderer_sink.h"
-#include "starboard/shared/starboard/player/filter/stub_audio_decoder.h"
-#include "starboard/shared/starboard/player/filter/stub_video_decoder.h"
#include "starboard/shared/starboard/player/filter/video_decoder_internal.h"
#include "starboard/shared/starboard/player/filter/video_render_algorithm.h"
-#include "starboard/shared/starboard/player/filter/video_render_algorithm_impl.h"
#include "starboard/shared/starboard/player/filter/video_renderer_internal.h"
#include "starboard/shared/starboard/player/filter/video_renderer_sink.h"
-#include "starboard/shared/starboard/player/job_queue.h"
namespace starboard {
namespace shared {
@@ -71,50 +63,11 @@
static scoped_ptr<PlayerComponents> Create();
scoped_ptr<AudioRenderer> CreateAudioRenderer(
- const AudioParameters& audio_parameters) {
- scoped_ptr<AudioDecoder> audio_decoder;
- scoped_ptr<AudioRendererSink> audio_renderer_sink;
+ const AudioParameters& audio_parameters);
- auto command_line = shared::starboard::Application::Get()->GetCommandLine();
- if (command_line->HasSwitch("use_stub_audio_decoder")) {
- CreateStubAudioComponents(audio_parameters, &audio_decoder,
- &audio_renderer_sink);
- } else {
- CreateAudioComponents(audio_parameters, &audio_decoder,
- &audio_renderer_sink);
- }
- if (!audio_decoder || !audio_renderer_sink) {
- return scoped_ptr<AudioRenderer>();
- }
- int max_cached_frames, max_frames_per_append;
- GetAudioRendererParams(&max_cached_frames, &max_frames_per_append);
- return make_scoped_ptr(
- new AudioRenderer(audio_decoder.Pass(), audio_renderer_sink.Pass(),
- audio_parameters.audio_sample_info, max_cached_frames,
- max_frames_per_append));
- }
scoped_ptr<VideoRenderer> CreateVideoRenderer(
const VideoParameters& video_parameters,
- MediaTimeProvider* media_time_provider) {
- scoped_ptr<VideoDecoder> video_decoder;
- scoped_ptr<VideoRenderAlgorithm> video_render_algorithm;
- scoped_refptr<VideoRendererSink> video_renderer_sink;
-
- auto command_line = shared::starboard::Application::Get()->GetCommandLine();
- if (command_line->HasSwitch("use_stub_video_decoder")) {
- CreateStubVideoComponents(video_parameters, &video_decoder,
- &video_render_algorithm, &video_renderer_sink);
- } else {
- CreateVideoComponents(video_parameters, &video_decoder,
- &video_render_algorithm, &video_renderer_sink);
- }
- if (!video_decoder || !video_render_algorithm) {
- return scoped_ptr<VideoRenderer>();
- }
- return make_scoped_ptr(
- new VideoRenderer(video_decoder.Pass(), media_time_provider,
- video_render_algorithm.Pass(), video_renderer_sink));
- }
+ MediaTimeProvider* media_time_provider);
#if COBALT_BUILD_TYPE_GOLD
private:
@@ -143,31 +96,13 @@
void CreateStubAudioComponents(
const AudioParameters& audio_parameters,
scoped_ptr<AudioDecoder>* audio_decoder,
- scoped_ptr<AudioRendererSink>* audio_renderer_sink) {
- SB_DCHECK(audio_decoder);
- SB_DCHECK(audio_renderer_sink);
-
- audio_decoder->reset(
- new StubAudioDecoder(audio_parameters.audio_sample_info));
- audio_renderer_sink->reset(new AudioRendererSinkImpl);
- }
+ scoped_ptr<AudioRendererSink>* audio_renderer_sink);
void CreateStubVideoComponents(
const VideoParameters& video_parameters,
scoped_ptr<VideoDecoder>* video_decoder,
scoped_ptr<VideoRenderAlgorithm>* video_render_algorithm,
- scoped_refptr<VideoRendererSink>* video_renderer_sink) {
- const SbTime kVideoSinkRenderInterval = 10 * kSbTimeMillisecond;
-
- SB_DCHECK(video_decoder);
- SB_DCHECK(video_render_algorithm);
- SB_DCHECK(video_renderer_sink);
-
- video_decoder->reset(new StubVideoDecoder);
- video_render_algorithm->reset(new VideoRenderAlgorithmImpl);
- *video_renderer_sink = new PunchoutVideoRendererSink(
- video_parameters.player, kVideoSinkRenderInterval);
- }
+ scoped_refptr<VideoRendererSink>* video_renderer_sink);
private:
SB_DISALLOW_COPY_AND_ASSIGN(PlayerComponents);
diff --git a/src/starboard/shared/starboard/player/filter/player_filter.gypi b/src/starboard/shared/starboard/player/filter/player_filter.gypi
index a3f40ba..b67a371 100644
--- a/src/starboard/shared/starboard/player/filter/player_filter.gypi
+++ b/src/starboard/shared/starboard/player/filter/player_filter.gypi
@@ -42,6 +42,7 @@
'<(DEPTH)/starboard/shared/starboard/player/filter/media_time_provider_impl.h',
'<(DEPTH)/starboard/shared/starboard/player/filter/mock_audio_decoder.h',
'<(DEPTH)/starboard/shared/starboard/player/filter/mock_audio_renderer_sink.h',
+ '<(DEPTH)/starboard/shared/starboard/player/filter/player_components.cc',
'<(DEPTH)/starboard/shared/starboard/player/filter/player_components.h',
'<(DEPTH)/starboard/shared/starboard/player/filter/punchout_video_renderer_sink.cc',
'<(DEPTH)/starboard/shared/starboard/player/filter/punchout_video_renderer_sink.h',
@@ -61,4 +62,4 @@
'<(DEPTH)/starboard/shared/starboard/player/filter/wsola_internal.h',
],
},
-}
\ No newline at end of file
+}
diff --git a/src/starboard/shared/starboard/player/filter/stub_audio_decoder.cc b/src/starboard/shared/starboard/player/filter/stub_audio_decoder.cc
index 5358ae3..b5888c1 100644
--- a/src/starboard/shared/starboard/player/filter/stub_audio_decoder.cc
+++ b/src/starboard/shared/starboard/player/filter/stub_audio_decoder.cc
@@ -35,8 +35,10 @@
} // namespace
StubAudioDecoder::StubAudioDecoder(
+ SbMediaAudioCodec audio_codec,
const SbMediaAudioSampleInfo& audio_sample_info)
: sample_type_(GetSupportedSampleType()),
+ audio_codec_(audio_codec),
audio_sample_info_(audio_sample_info),
stream_ended_(false) {}
@@ -67,10 +69,15 @@
size_t size = diff * GetSamplesPerSecond() * sample_size *
audio_sample_info_.number_of_channels / kSbTimeSecond;
size -= size % (sample_size * audio_sample_info_.number_of_channels);
+ if (audio_codec_ == kSbMediaAudioCodecAac) {
+ // Frame size for AAC is fixed at 1024, so fake the output size such that
+ // number of frames matches up.
+ size = sample_size * audio_sample_info_.number_of_channels * 1024;
+ }
- decoded_audios_.push(new DecodedAudio(audio_sample_info_.number_of_channels,
- GetSampleType(), GetStorageType(),
- input_buffer->timestamp(), size));
+ decoded_audios_.push(new DecodedAudio(
+ audio_sample_info_.number_of_channels, GetSampleType(),
+ GetStorageType(), last_input_buffer_->timestamp(), size));
if (fill_type == kSilence) {
SbMemorySet(decoded_audios_.back()->buffer(), 0, size);
@@ -100,9 +107,13 @@
size_t fake_size = 4 * last_input_buffer_->size();
size_t sample_size =
GetSampleType() == kSbMediaAudioSampleTypeInt16Deprecated ? 2 : 4;
- fake_size +=
+ fake_size -=
fake_size % (sample_size * audio_sample_info_.number_of_channels);
-
+ if (audio_codec_ == kSbMediaAudioCodecAac) {
+ // Frame size for AAC is fixed at 1024, so fake the output size such that
+ // number of frames matches up.
+ fake_size = sample_size * audio_sample_info_.number_of_channels * 1024;
+ }
decoded_audios_.push(new DecodedAudio(
audio_sample_info_.number_of_channels, GetSampleType(),
GetStorageType(), last_input_buffer_->timestamp(), fake_size));
diff --git a/src/starboard/shared/starboard/player/filter/stub_audio_decoder.h b/src/starboard/shared/starboard/player/filter/stub_audio_decoder.h
index bcfdf8f..d42ecd0 100644
--- a/src/starboard/shared/starboard/player/filter/stub_audio_decoder.h
+++ b/src/starboard/shared/starboard/player/filter/stub_audio_decoder.h
@@ -30,7 +30,8 @@
class StubAudioDecoder : public AudioDecoder, private JobQueue::JobOwner {
public:
- explicit StubAudioDecoder(const SbMediaAudioSampleInfo& audio_sample_info);
+ StubAudioDecoder(SbMediaAudioCodec audio_codec,
+ const SbMediaAudioSampleInfo& audio_sample_info);
void Initialize(const OutputCB& output_cb, const ErrorCB& error_cb) override;
@@ -52,6 +53,7 @@
private:
OutputCB output_cb_;
SbMediaAudioSampleType sample_type_;
+ SbMediaAudioCodec audio_codec_;
SbMediaAudioSampleInfo audio_sample_info_;
bool stream_ended_;
std::queue<scoped_refptr<DecodedAudio> > decoded_audios_;
diff --git a/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc b/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc
index baa83fa..2947df4 100644
--- a/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc
+++ b/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/common/log.h"
+#include "starboard/shared/starboard/player/filter/stub_player_components_impl.h"
+
#include "starboard/shared/starboard/player/filter/player_components.h"
namespace starboard {
@@ -21,37 +22,9 @@
namespace player {
namespace filter {
-class PlayerComponentsImpl : public PlayerComponents {
- void CreateAudioComponents(
- const AudioParameters& audio_parameters,
- scoped_ptr<AudioDecoder>* audio_decoder,
- scoped_ptr<AudioRendererSink>* audio_renderer_sink) override {
- CreateStubAudioComponents(audio_parameters, audio_decoder,
- audio_renderer_sink);
- }
-
- void CreateVideoComponents(
- const VideoParameters& video_parameters,
- scoped_ptr<VideoDecoder>* video_decoder,
- scoped_ptr<VideoRenderAlgorithm>* video_render_algorithm,
- scoped_refptr<VideoRendererSink>* video_renderer_sink) override {
- CreateStubVideoComponents(video_parameters, video_decoder,
- video_render_algorithm, video_renderer_sink);
- }
-
- void GetAudioRendererParams(int* max_cached_frames,
- int* max_frames_per_append) const override {
- SB_DCHECK(max_cached_frames);
- SB_DCHECK(max_frames_per_append);
-
- *max_cached_frames = 128 * 1024;
- *max_frames_per_append = 16384;
- }
-};
-
// static
scoped_ptr<PlayerComponents> PlayerComponents::Create() {
- return make_scoped_ptr<PlayerComponents>(new PlayerComponentsImpl);
+ return make_scoped_ptr<PlayerComponents>(new StubPlayerComponentsImpl);
}
// static
diff --git a/src/starboard/shared/starboard/player/filter/stub_player_components_impl.h b/src/starboard/shared/starboard/player/filter/stub_player_components_impl.h
new file mode 100644
index 0000000..3e2013a
--- /dev/null
+++ b/src/starboard/shared/starboard/player/filter/stub_player_components_impl.h
@@ -0,0 +1,61 @@
+// Copyright 2017 The Cobalt Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_STUB_PLAYER_COMPONENTS_IMPL_H_
+#define STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_STUB_PLAYER_COMPONENTS_IMPL_H_
+
+#include "starboard/shared/starboard/player/filter/player_components.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace player {
+namespace filter {
+
+class StubPlayerComponentsImpl : public PlayerComponents {
+ public:
+ void CreateAudioComponents(
+ const AudioParameters& audio_parameters,
+ scoped_ptr<AudioDecoder>* audio_decoder,
+ scoped_ptr<AudioRendererSink>* audio_renderer_sink) override {
+ CreateStubAudioComponents(audio_parameters, audio_decoder,
+ audio_renderer_sink);
+ }
+
+ void CreateVideoComponents(
+ const VideoParameters& video_parameters,
+ scoped_ptr<VideoDecoder>* video_decoder,
+ scoped_ptr<VideoRenderAlgorithm>* video_render_algorithm,
+ scoped_refptr<VideoRendererSink>* video_renderer_sink) override {
+ CreateStubVideoComponents(video_parameters, video_decoder,
+ video_render_algorithm, video_renderer_sink);
+ }
+
+ void GetAudioRendererParams(int* max_cached_frames,
+ int* max_frames_per_append) const override {
+ SB_DCHECK(max_cached_frames);
+ SB_DCHECK(max_frames_per_append);
+
+ *max_cached_frames = 128 * 1024;
+ *max_frames_per_append = 16384;
+ }
+};
+
+} // namespace filter
+} // namespace player
+} // namespace starboard
+} // namespace shared
+} // namespace starboard
+
+#endif // STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_STUB_PLAYER_COMPONENTS_IMPL_H_
diff --git a/src/starboard/shared/starboard/player/filter/stub_video_decoder.cc b/src/starboard/shared/starboard/player/filter/stub_video_decoder.cc
index 344d364..38b84a6 100644
--- a/src/starboard/shared/starboard/player/filter/stub_video_decoder.cc
+++ b/src/starboard/shared/starboard/player/filter/stub_video_decoder.cc
@@ -52,17 +52,40 @@
video_sample_info_.value() != video_sample_info) {
SB_LOG(INFO) << "New video sample info: " << video_sample_info;
video_sample_info_ = video_sample_info;
+#if SB_API_VERSION < 11
+ color_metadata_ = *video_sample_info.color_metadata;
+ video_sample_info_->color_metadata = &color_metadata_;
+#endif // SB_API_VERSION < 11
}
}
- decoder_status_cb_(kNeedMoreInput, new VideoFrame(input_buffer->timestamp()));
+ output_event_frame_times_.insert(input_buffer->timestamp());
+ // Defer sending frames out until we've accumulated a reasonable number.
+ // This allows for input buffers to be out of order, and we expect that
+ // after buffering 8 (arbitrarily chosen) that the first timestamp in the
+ // sorted buffer will be the "correct" timestamp to send out.
+ const int kMaxFramesToDelay = 8;
+ scoped_refptr<VideoFrame> output_frame = NULL;
+ if (output_event_frame_times_.size() > kMaxFramesToDelay) {
+ output_frame = new VideoFrame(*output_event_frame_times_.begin());
+ output_event_frame_times_.erase(output_event_frame_times_.begin());
+ }
+ decoder_status_cb_(kNeedMoreInput, output_frame);
}
void StubVideoDecoder::WriteEndOfStream() {
+ // If there are any remaining frames we need to output, send them all out
+ // before writing EOS.
+ for (const auto& time : output_event_frame_times_) {
+ decoder_status_cb_(kBufferFull, new VideoFrame(time));
+ }
decoder_status_cb_(kBufferFull, VideoFrame::CreateEOSFrame());
}
-void StubVideoDecoder::Reset() {}
+void StubVideoDecoder::Reset() {
+ output_event_frame_times_.clear();
+ video_sample_info_ = nullopt;
+}
SbDecodeTarget StubVideoDecoder::GetCurrentDecodeTarget() {
return kSbDecodeTargetInvalid;
diff --git a/src/starboard/shared/starboard/player/filter/stub_video_decoder.h b/src/starboard/shared/starboard/player/filter/stub_video_decoder.h
index fd64fdc..b320b32 100644
--- a/src/starboard/shared/starboard/player/filter/stub_video_decoder.h
+++ b/src/starboard/shared/starboard/player/filter/stub_video_decoder.h
@@ -15,6 +15,8 @@
#ifndef STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_STUB_VIDEO_DECODER_H_
#define STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_STUB_VIDEO_DECODER_H_
+#include <set>
+
#include "starboard/common/optional.h"
#include "starboard/shared/internal_only.h"
#include "starboard/shared/starboard/player/filter/video_decoder_internal.h"
@@ -50,6 +52,12 @@
private:
DecoderStatusCB decoder_status_cb_;
optional<SbMediaVideoSampleInfo> video_sample_info_;
+#if SB_API_VERSION < 11
+ SbMediaColorMetadata color_metadata_;
+#endif // SB_API_VERSION < 11
+
+ // std::set<> keeps frame timestamps sorted in ascending order.
+ std::set<SbTime> output_event_frame_times_;
};
} // namespace filter
diff --git a/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc b/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
index 4730e34..c68e925 100644
--- a/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
@@ -21,6 +21,7 @@
#include "starboard/shared/starboard/media/media_support_internal.h"
#include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
#include "starboard/shared/starboard/player/filter/player_components.h"
+#include "starboard/shared/starboard/player/filter/stub_player_components_impl.h"
#include "starboard/shared/starboard/player/video_dmp_reader.h"
#include "starboard/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -37,6 +38,8 @@
namespace testing {
namespace {
+using ::testing::Bool;
+using ::testing::Combine;
using ::testing::ValuesIn;
using std::vector;
using std::string;
@@ -88,13 +91,14 @@
// TODO: Avoid reading same dmp file repeatly.
class AdaptiveAudioDecoderTest
- : public ::testing::TestWithParam<vector<const char*>> {
+ : public ::testing::TestWithParam<std::tuple<vector<const char*>, bool>> {
protected:
enum Event { kConsumed, kOutput, kError };
- AdaptiveAudioDecoderTest() {
- vector<const char*> params = GetParam();
- for (auto filename : params) {
+ AdaptiveAudioDecoderTest()
+ : test_filenames_(std::get<0>(GetParam())),
+ using_stub_decoder_(std::get<1>(GetParam())) {
+ for (auto filename : test_filenames_) {
dmp_readers_.emplace_back(
new VideoDmpReader(ResolveTestFileName(filename).c_str()));
}
@@ -105,9 +109,11 @@
}
return std::move(accumulated) + "->" + str;
};
- string description = std::accumulate(params.begin(), params.end(), string(),
- accumulate_operation);
- SB_LOG(INFO) << "Testing: " << description;
+ string description =
+ std::accumulate(test_filenames_.begin(), test_filenames_.end(),
+ string(), accumulate_operation);
+ SB_LOG(INFO) << "Testing: " << description
+ << (using_stub_decoder_ ? " (with stub decoder)." : ".");
}
void SetUp() override {
@@ -121,8 +127,14 @@
dmp_readers_[0]->audio_codec(), dmp_readers_[0]->audio_sample_info(),
kSbDrmSystemInvalid};
- scoped_ptr<PlayerComponents> components = PlayerComponents::Create();
scoped_ptr<AudioRendererSink> audio_renderer_sink;
+ scoped_ptr<PlayerComponents> components;
+ if (using_stub_decoder_) {
+ components = make_scoped_ptr<StubPlayerComponentsImpl>(
+ new StubPlayerComponentsImpl);
+ } else {
+ components = PlayerComponents::Create();
+ }
components->CreateAudioComponents(audio_parameters, &audio_decoder_,
&audio_renderer_sink);
ASSERT_TRUE(audio_decoder_);
@@ -202,6 +214,16 @@
}
}
+ void AssertExpectedAndOutputFramesMatch(int expected_output_frames) {
+ if (using_stub_decoder_) {
+ // The number of output frames is not applicable in the case of the
+ // StubAudioDecoder, because it is not actually doing any decoding work.
+ return;
+ }
+ ASSERT_LE(abs(expected_output_frames - num_of_output_frames_),
+ dmp_readers_.size());
+ }
+
vector<std::unique_ptr<VideoDmpReader>> dmp_readers_;
scoped_refptr<DecodedAudio> last_decoded_audio_;
int num_of_output_frames_ = 0;
@@ -262,6 +284,13 @@
num_of_output_frames_ += last_decoded_audio_->frames();
}
+ // Test parameter for the filenames to load with the VideoDmpReader.
+ std::vector<const char*> test_filenames_;
+
+ // Test parameter to configure whether the test is run with the
+ // StubAudioDecoder, or the platform-specific AudioDecoderImpl.
+ bool using_stub_decoder_;
+
JobQueue job_queue_;
scoped_ptr<AudioDecoder> audio_decoder_;
@@ -300,8 +329,7 @@
// |expected_output_frames|. Each time to switch decoder, it may have one
// sample difference in output due to integer conversion. The total difference
// should not exceed the length of |dmp_readers_|.
- ASSERT_LE(abs(expected_output_frames - num_of_output_frames_),
- dmp_readers_.size());
+ AssertExpectedAndOutputFramesMatch(expected_output_frames);
}
TEST_P(AdaptiveAudioDecoderTest, MultipleInput) {
@@ -334,8 +362,7 @@
// |expected_output_frames|. Each time to switch decoder, it may have one
// sample difference in ouput due to integer conversion. The total difference
// should not exceed the length of |dmp_readers_|.
- ASSERT_LE(abs(expected_output_frames - num_of_output_frames_),
- dmp_readers_.size());
+ AssertExpectedAndOutputFramesMatch(expected_output_frames);
}
vector<vector<const char*>> GetSupportedTests() {
@@ -391,7 +418,7 @@
INSTANTIATE_TEST_CASE_P(AdaptiveAudioDecoderTests,
AdaptiveAudioDecoderTest,
- ValuesIn(GetSupportedTests()));
+ Combine(ValuesIn(GetSupportedTests()), Bool()));
} // namespace
} // namespace testing
diff --git a/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc b/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
index cd73cfc..9b8e5ce 100644
--- a/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
@@ -25,6 +25,7 @@
#include "starboard/shared/starboard/media/media_support_internal.h"
#include "starboard/shared/starboard/media/media_util.h"
#include "starboard/shared/starboard/player/filter/player_components.h"
+#include "starboard/shared/starboard/player/filter/stub_player_components_impl.h"
#include "starboard/shared/starboard/player/video_dmp_reader.h"
#include "starboard/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -40,6 +41,8 @@
namespace testing {
namespace {
+using ::testing::Bool;
+using ::testing::Combine;
using ::testing::ValuesIn;
using video_dmp::VideoDmpReader;
@@ -74,10 +77,15 @@
return GetTestInputDirectory() + SB_FILE_SEP_CHAR + filename;
}
-class AudioDecoderTest : public ::testing::TestWithParam<const char*> {
+class AudioDecoderTest
+ : public ::testing::TestWithParam<std::tuple<const char*, bool> > {
public:
- AudioDecoderTest() : dmp_reader_(ResolveTestFileName(GetParam()).c_str()) {
- SB_LOG(INFO) << "Testing " << GetParam();
+ AudioDecoderTest()
+ : test_filename_(std::get<0>(GetParam())),
+ using_stub_decoder_(std::get<1>(GetParam())),
+ dmp_reader_(ResolveTestFileName(test_filename_).c_str()) {
+ SB_LOG(INFO) << "Testing " << test_filename_
+ << (using_stub_decoder_ ? " with stub audio decoder." : ".");
}
void SetUp() override {
ASSERT_NE(dmp_reader_.audio_codec(), kSbMediaAudioCodecNone);
@@ -87,7 +95,13 @@
dmp_reader_.audio_codec(), dmp_reader_.audio_sample_info(),
kSbDrmSystemInvalid};
- scoped_ptr<PlayerComponents> components = PlayerComponents::Create();
+ scoped_ptr<PlayerComponents> components;
+ if (using_stub_decoder_) {
+ components = make_scoped_ptr<StubPlayerComponentsImpl>(
+ new StubPlayerComponentsImpl);
+ } else {
+ components = PlayerComponents::Create();
+ }
components->CreateAudioComponents(audio_parameters, &audio_decoder_,
&audio_renderer_sink_);
ASSERT_TRUE(audio_decoder_);
@@ -151,6 +165,8 @@
last_input_buffer_ = GetAudioInputBuffer(index);
+ outstanding_inputs_.insert(last_input_buffer_->timestamp());
+
audio_decoder_->Decode(last_input_buffer_, consumed_cb());
}
@@ -265,6 +281,8 @@
can_accept_more_input_ = true;
last_input_buffer_ = NULL;
last_decoded_audio_ = NULL;
+ outstanding_inputs_.clear();
+ eos_written_ = false;
}
void WaitForDecodedAudio() {
@@ -296,9 +314,38 @@
#endif // SB_API_VERSION >= 11
}
+ void WriteEndOfStream() {
+ SB_DCHECK(!eos_written_);
+ audio_decoder_->WriteEndOfStream();
+ eos_written_ = true;
+ }
+
+ void AssertInvalidOutputFormat() {
+ SbMediaAudioSampleType output_sample_type = audio_decoder_->GetSampleType();
+ ASSERT_TRUE(output_sample_type == kSbMediaAudioSampleTypeFloat32 ||
+ output_sample_type == kSbMediaAudioSampleTypeInt16Deprecated);
+
+ SbMediaAudioFrameStorageType output_storage_type =
+ audio_decoder_->GetStorageType();
+ ASSERT_TRUE(output_storage_type ==
+ kSbMediaAudioFrameStorageTypeInterleaved ||
+ output_storage_type == kSbMediaAudioFrameStorageTypePlanar);
+
+ int output_samples_per_second = audio_decoder_->GetSamplesPerSecond();
+ ASSERT_TRUE(output_samples_per_second > 0 &&
+ output_samples_per_second <= 480000);
+ }
+
Mutex event_queue_mutex_;
std::deque<Event> event_queue_;
+ // Test parameter for the filename to load with the VideoDmpReader.
+ const char* test_filename_;
+
+ // Test parameter to configure whether the test is run with the
+ // StubAudioDecoder, or the platform-specific AudioDecoderImpl
+ bool using_stub_decoder_;
+
JobQueue job_queue_;
VideoDmpReader dmp_reader_;
scoped_ptr<AudioDecoder> audio_decoder_;
@@ -307,6 +354,12 @@
bool can_accept_more_input_ = true;
scoped_refptr<InputBuffer> last_input_buffer_;
scoped_refptr<DecodedAudio> last_decoded_audio_;
+
+ // List of timestamps of InputBuffers provided to the Decoder so far, sorted
+ // in ascending order.
+ std::set<SbTime> outstanding_inputs_;
+
+ bool eos_written_ = false;
};
TEST_P(AudioDecoderTest, ThreeMoreDecoders) {
@@ -332,10 +385,11 @@
TEST_P(AudioDecoderTest, SingleInput) {
ASSERT_NO_FATAL_FAILURE(WriteSingleInput(0));
- audio_decoder_->WriteEndOfStream();
+ WriteEndOfStream();
ASSERT_NO_FATAL_FAILURE(DrainOutputs());
ASSERT_TRUE(last_decoded_audio_);
+ ASSERT_NO_FATAL_FAILURE(AssertInvalidOutputFormat());
}
TEST_P(AudioDecoderTest, SingleInputHEAAC) {
@@ -346,10 +400,11 @@
}
ASSERT_NO_FATAL_FAILURE(WriteSingleInput(0));
- audio_decoder_->WriteEndOfStream();
+ WriteEndOfStream();
ASSERT_NO_FATAL_FAILURE(DrainOutputs());
ASSERT_TRUE(last_decoded_audio_);
+ ASSERT_NO_FATAL_FAILURE(AssertInvalidOutputFormat());
if (last_decoded_audio_->frames() == kAacFrameSize) {
return;
}
@@ -367,7 +422,7 @@
static_cast<int>(content.size()));
audio_decoder_->Decode(last_input_buffer_, consumed_cb());
- audio_decoder_->WriteEndOfStream();
+ WriteEndOfStream();
bool error_occurred = false;
ASSERT_NO_FATAL_FAILURE(DrainOutputs(&error_occurred));
@@ -381,20 +436,22 @@
}
TEST_P(AudioDecoderTest, EndOfStreamWithoutAnyInput) {
- audio_decoder_->WriteEndOfStream();
+ WriteEndOfStream();
ASSERT_NO_FATAL_FAILURE(DrainOutputs());
ASSERT_FALSE(last_decoded_audio_);
+ ASSERT_NO_FATAL_FAILURE(AssertInvalidOutputFormat());
}
TEST_P(AudioDecoderTest, ResetBeforeInput) {
ResetDecoder();
ASSERT_NO_FATAL_FAILURE(WriteSingleInput(0));
- audio_decoder_->WriteEndOfStream();
+ WriteEndOfStream();
ASSERT_NO_FATAL_FAILURE(DrainOutputs());
ASSERT_TRUE(last_decoded_audio_);
+ ASSERT_NO_FATAL_FAILURE(AssertInvalidOutputFormat());
}
TEST_P(AudioDecoderTest, MultipleInputs) {
@@ -404,10 +461,11 @@
ASSERT_NO_FATAL_FAILURE(WriteMultipleInputs(0, number_of_inputs_to_write));
- audio_decoder_->WriteEndOfStream();
+ WriteEndOfStream();
ASSERT_NO_FATAL_FAILURE(DrainOutputs());
ASSERT_TRUE(last_decoded_audio_);
+ ASSERT_NO_FATAL_FAILURE(AssertInvalidOutputFormat());
}
#if SB_API_VERSION >= 11
@@ -421,7 +479,7 @@
ASSERT_NO_FATAL_FAILURE(WriteTimeLimitedInputs(&start_index, duration));
if (start_index >= dmp_reader_.number_of_audio_buffers()) {
- audio_decoder_->WriteEndOfStream();
+ WriteEndOfStream();
}
// Wait for decoded audio.
@@ -456,9 +514,10 @@
ASSERT_FALSE(decoded_audio->is_end_of_stream());
}
}
- audio_decoder_->WriteEndOfStream();
+ WriteEndOfStream();
ASSERT_NO_FATAL_FAILURE(DrainOutputs());
ASSERT_TRUE(last_decoded_audio_);
+ ASSERT_NO_FATAL_FAILURE(AssertInvalidOutputFormat());
}
#endif // SB_API_VERSION >= 11
@@ -488,7 +547,7 @@
INSTANTIATE_TEST_CASE_P(AudioDecoderTests,
AudioDecoderTest,
- ValuesIn(GetSupportedTests()));
+ Combine(ValuesIn(GetSupportedTests()), Bool()));
} // namespace
} // namespace testing
diff --git a/src/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc b/src/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc
index 19f8fcc..c977332 100644
--- a/src/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc
@@ -17,6 +17,7 @@
#include <algorithm>
#include <deque>
#include <functional>
+#include <map>
#include <set>
#include "starboard/common/condition_variable.h"
@@ -28,7 +29,7 @@
#include "starboard/memory.h"
#include "starboard/shared/starboard/media/media_support_internal.h"
#include "starboard/shared/starboard/media/media_util.h"
-#include "starboard/shared/starboard/player/filter/player_components.h"
+#include "starboard/shared/starboard/player/filter/stub_player_components_impl.h"
#include "starboard/shared/starboard/player/job_queue.h"
#include "starboard/shared/starboard/player/video_dmp_reader.h"
#include "starboard/testing/fake_graphics_context_provider.h"
@@ -55,6 +56,8 @@
using ::testing::AssertionFailure;
using ::testing::AssertionResult;
using ::testing::AssertionSuccess;
+using ::testing::Bool;
+using ::testing::Combine;
using ::testing::ValuesIn;
using video_dmp::VideoDmpReader;
@@ -102,11 +105,16 @@
<< "time " << time1 << " doesn't match with time " << time2;
}
-class VideoDecoderTest : public ::testing::TestWithParam<TestParam> {
+class VideoDecoderTest
+ : public ::testing::TestWithParam<std::tuple<TestParam, bool>> {
public:
VideoDecoderTest()
- : dmp_reader_(ResolveTestFileName(GetParam().filename).c_str()) {
- SB_LOG(INFO) << "Testing " << GetParam().filename;
+ : test_filename_(std::get<0>(GetParam()).filename),
+ output_mode_(std::get<0>(GetParam()).output_mode),
+ using_stub_decoder_(std::get<1>(GetParam())),
+ dmp_reader_(ResolveTestFileName(test_filename_).c_str()) {
+ SB_LOG(INFO) << "Testing " << test_filename_
+ << (using_stub_decoder_ ? " with stub video decoder." : ".");
}
~VideoDecoderTest() { video_decoder_->Reset(); }
@@ -116,7 +124,7 @@
ASSERT_GT(dmp_reader_.number_of_video_buffers(), 0);
ASSERT_TRUE(GetVideoInputBuffer(0)->video_sample_info().is_key_frame);
- SbPlayerOutputMode output_mode = GetParam().output_mode;
+ SbPlayerOutputMode output_mode = output_mode_;
ASSERT_TRUE(VideoDecoder::OutputModeSupported(
output_mode, dmp_reader_.video_codec(), kSbDrmSystemInvalid));
@@ -127,7 +135,13 @@
output_mode,
fake_graphics_context_provider_.decoder_target_provider()};
- scoped_ptr<PlayerComponents> components = PlayerComponents::Create();
+ scoped_ptr<PlayerComponents> components;
+ if (using_stub_decoder_) {
+ components = make_scoped_ptr<StubPlayerComponentsImpl>(
+ new StubPlayerComponentsImpl);
+ } else {
+ components = PlayerComponents::Create();
+ }
components->CreateVideoComponents(video_parameters, &video_decoder_,
&video_render_algorithm_,
&video_renderer_sink_);
@@ -172,7 +186,7 @@
#if SB_HAS(GLES2)
void AssertInvalidDecodeTarget() {
- if (GetParam().output_mode == kSbPlayerOutputModeDecodeToTexture) {
+ if (output_mode_ == kSbPlayerOutputModeDecodeToTexture) {
auto decode_target = video_decoder_->GetCurrentDecodeTarget();
ASSERT_FALSE(SbDecodeTargetIsValid(decode_target));
fake_graphics_context_provider_.ReleaseDecodeTarget(decode_target);
@@ -239,10 +253,20 @@
return !event_queue_.empty();
}
+ void GetDecodeTargetWhenSupported() {
+#if SB_HAS(GLES2)
+ if (output_mode_ == kSbPlayerOutputModeDecodeToTexture) {
+ SbDecodeTarget decode_target = video_decoder_->GetCurrentDecodeTarget();
+ fake_graphics_context_provider_.ReleaseDecodeTarget(decode_target);
+ }
+#endif // SB_HAS(GLES2)
+ }
+
void AssertValidDecodeTargetWhenSupported() {
#if SB_HAS(GLES2)
- if (GetParam().output_mode == kSbPlayerOutputModeDecodeToTexture) {
- auto decode_target = video_decoder_->GetCurrentDecodeTarget();
+ if (output_mode_ == kSbPlayerOutputModeDecodeToTexture &&
+ !using_stub_decoder_) {
+ SbDecodeTarget decode_target = video_decoder_->GetCurrentDecodeTarget();
ASSERT_TRUE(SbDecodeTargetIsValid(decode_target));
fake_graphics_context_provider_.ReleaseDecodeTarget(decode_target);
}
@@ -290,6 +314,14 @@
ASSERT_NO_FATAL_FAILURE(WriteSingleInput(start_index));
++start_index;
--number_of_inputs_to_write;
+ } else if (event.status == kError) {
+ // Assume that the caller does't expect an error when |event_cb| isn't
+ // provided.
+ ASSERT_TRUE(event_cb);
+ bool continue_process = true;
+ event_cb(event, &continue_process);
+ ASSERT_FALSE(continue_process);
+ return;
} else {
ASSERT_EQ(event.status, kBufferFull);
}
@@ -335,7 +367,16 @@
if (event.frame) {
if (event.frame->is_end_of_stream()) {
end_of_stream_decoded = true;
- ASSERT_TRUE(outstanding_inputs_.empty());
+ if (!outstanding_inputs_.empty()) {
+ if (error_occurred) {
+ *error_occurred = true;
+ } else {
+ // |error_occurred| is NULL indicates that the caller doesn't
+ // expect an error, use the following redundant ASSERT to trigger
+ // a failure.
+ ASSERT_TRUE(outstanding_inputs_.empty());
+ }
+ }
} else {
if (!decoded_frames_.empty()) {
ASSERT_LT(decoded_frames_.back()->timestamp(),
@@ -371,11 +412,24 @@
auto video_sample_info =
dmp_reader_.GetPlayerSampleInfo(kSbMediaTypeVideo, index);
#if SB_API_VERSION >= 11
- return new InputBuffer(DeallocateSampleFunc, NULL, NULL, video_sample_info);
+ auto input_buffer =
+ new InputBuffer(DeallocateSampleFunc, NULL, NULL, video_sample_info);
#else // SB_API_VERSION >= 11
- return new InputBuffer(kSbMediaTypeVideo, DeallocateSampleFunc, NULL, NULL,
- video_sample_info, NULL);
+ auto input_buffer = new InputBuffer(kSbMediaTypeVideo, DeallocateSampleFunc,
+ NULL, NULL, video_sample_info, NULL);
#endif // SB_API_VERSION >= 11
+ auto iter = invalid_inputs_.find(index);
+ if (iter != invalid_inputs_.end()) {
+ std::vector<uint8_t> content(input_buffer->size(), iter->second);
+ // Replace the content with invalid data.
+ input_buffer->SetDecryptedContent(content.data(),
+ static_cast<int>(content.size()));
+ }
+ return input_buffer;
+ }
+
+ void UseInvalidDataForInput(size_t index, uint8_t byte_to_fill) {
+ invalid_inputs_[index] = byte_to_fill;
}
JobQueue job_queue_;
@@ -383,6 +437,16 @@
Mutex mutex_;
std::deque<Event> event_queue_;
+ // Test parameter filename for the VideoDmpReader to load and test with.
+ const char* test_filename_;
+
+ // Test parameter for OutputMode.
+ SbPlayerOutputMode output_mode_;
+
+ // Test parameter for whether or not to use the StubVideoDecoder, or the
+ // platform-specific VideoDecoderImpl.
+ bool using_stub_decoder_;
+
FakeGraphicsContextProvider fake_graphics_context_provider_;
VideoDmpReader dmp_reader_;
scoped_ptr<VideoDecoder> video_decoder_;
@@ -397,6 +461,8 @@
scoped_refptr<VideoRendererSink> video_renderer_sink_;
bool end_of_stream_written_ = false;
+
+ std::map<size_t, uint8_t> invalid_inputs_;
};
TEST_P(VideoDecoderTest, PrerollFrameCount) {
@@ -440,8 +506,11 @@
#if SB_HAS(GLES2)
TEST_P(VideoDecoderTest, GetCurrentDecodeTargetBeforeWriteInputBuffer) {
- if (GetParam().output_mode == kSbPlayerOutputModeDecodeToTexture) {
+ if (output_mode_ == kSbPlayerOutputModeDecodeToTexture) {
AssertInvalidDecodeTarget();
+ SbDecodeTarget decode_target = video_decoder_->GetCurrentDecodeTarget();
+ EXPECT_FALSE(SbDecodeTargetIsValid(decode_target));
+ fake_graphics_context_provider_.ReleaseDecodeTarget(decode_target);
}
}
#endif // SB_HAS(GLES2)
@@ -529,28 +598,81 @@
ASSERT_FALSE(error_occurred);
}
-TEST_P(VideoDecoderTest, SingleInvalidInput) {
- need_more_input_ = false;
- auto input_buffer = GetVideoInputBuffer(0);
- outstanding_inputs_.insert(input_buffer->timestamp());
- std::vector<uint8_t> content(input_buffer->size(), 0xab);
- // Replace the content with invalid data.
- input_buffer->SetDecryptedContent(content.data(),
- static_cast<int>(content.size()));
- video_decoder_->WriteInputBuffer(input_buffer);
+TEST_P(VideoDecoderTest, SingleInvalidKeyFrame) {
+ UseInvalidDataForInput(0, 0xab);
+ WriteSingleInput(0);
WriteEndOfStream();
bool error_occurred = true;
ASSERT_NO_FATAL_FAILURE(DrainOutputs(&error_occurred));
- if (error_occurred) {
- ASSERT_TRUE(decoded_frames_.empty());
- } else {
- // We don't expect the video decoder to recover from a bad input but some
- // decoders may just return an empty frame.
- ASSERT_FALSE(decoded_frames_.empty());
- AssertValidDecodeTargetWhenSupported();
+ // We don't expect the video decoder can always recover from a bad key frame
+ // and to raise an error, but it shouldn't crash or hang.
+ GetDecodeTargetWhenSupported();
+}
+
+TEST_P(VideoDecoderTest, MultipleValidInputsAfterInvalidKeyFrame) {
+ const size_t kMaxNumberOfInputToWrite = 10;
+ const size_t number_of_input_to_write =
+ std::min(kMaxNumberOfInputToWrite, dmp_reader_.number_of_video_buffers());
+
+ UseInvalidDataForInput(0, 0xab);
+
+ bool error_occurred = false;
+
+ // Write first few frames. The first one is invalid and the rest are valid.
+ WriteMultipleInputs(0, number_of_input_to_write,
+ [&](const Event& event, bool* continue_process) {
+ if (event.status == kError) {
+ error_occurred = true;
+ *continue_process = false;
+ return;
+ }
+
+ *continue_process = event.status != kBufferFull;
+ });
+
+ if (!error_occurred) {
+ GetDecodeTargetWhenSupported();
+ WriteEndOfStream();
+ ASSERT_NO_FATAL_FAILURE(DrainOutputs(&error_occurred));
}
+ // We don't expect the video decoder can always recover from a bad key frame
+ // and to raise an error, but it shouldn't crash or hang.
+ GetDecodeTargetWhenSupported();
+}
+
+TEST_P(VideoDecoderTest, MultipleInvalidInput) {
+ const size_t kMaxNumberOfInputToWrite = 128;
+ const size_t number_of_input_to_write =
+ std::min(kMaxNumberOfInputToWrite, dmp_reader_.number_of_video_buffers());
+ // Replace the content of the first few input buffers with invalid data.
+ // Every test instance loads its own copy of data so this won't affect other
+ // tests.
+ for (size_t i = 0; i < number_of_input_to_write; ++i) {
+ UseInvalidDataForInput(i, static_cast<uint8_t>(0xab + i));
+ }
+
+ bool error_occurred = false;
+ WriteMultipleInputs(0, number_of_input_to_write,
+ [&](const Event& event, bool* continue_process) {
+ if (event.status == kError) {
+ error_occurred = true;
+ *continue_process = false;
+ return;
+ }
+
+ *continue_process = event.status != kBufferFull;
+ });
+
+ if (!error_occurred) {
+ GetDecodeTargetWhenSupported();
+ WriteEndOfStream();
+ ASSERT_NO_FATAL_FAILURE(DrainOutputs(&error_occurred));
+ }
+ // We don't expect the video decoder can always recover from a bad key frame
+ // and to raise an error, but it shouldn't crash or hang.
+ GetDecodeTargetWhenSupported();
}
TEST_P(VideoDecoderTest, EndOfStreamWithoutAnyInput) {
@@ -744,7 +866,7 @@
INSTANTIATE_TEST_CASE_P(VideoDecoderTests,
VideoDecoderTest,
- ValuesIn(GetSupportedTests()));
+ Combine(ValuesIn(GetSupportedTests()), Bool()));
} // namespace
} // namespace testing
diff --git a/src/starboard/shared/starboard/player/testdata/beneath_the_canopy_avc_aac.dmp b/src/starboard/shared/starboard/player/testdata/beneath_the_canopy_avc_aac.dmp
deleted file mode 100644
index bec6752..0000000
--- a/src/starboard/shared/starboard/player/testdata/beneath_the_canopy_avc_aac.dmp
+++ /dev/null
Binary files differ
diff --git a/src/starboard/shared/starboard/player/testdata/beneath_the_canopy_vp9_opus.dmp b/src/starboard/shared/starboard/player/testdata/beneath_the_canopy_vp9_opus.dmp
deleted file mode 100644
index 4d663f9..0000000
--- a/src/starboard/shared/starboard/player/testdata/beneath_the_canopy_vp9_opus.dmp
+++ /dev/null
Binary files differ
diff --git a/src/starboard/shared/starboard/player/testdata/heaac.dmp b/src/starboard/shared/starboard/player/testdata/heaac.dmp
deleted file mode 100644
index 133a9c1..0000000
--- a/src/starboard/shared/starboard/player/testdata/heaac.dmp
+++ /dev/null
Binary files differ
diff --git a/src/starboard/shared/starboard/player/video_dmp_reader.cc b/src/starboard/shared/starboard/player/video_dmp_reader.cc
index 2ae52a0..250a0f7 100644
--- a/src/starboard/shared/starboard/player/video_dmp_reader.cc
+++ b/src/starboard/shared/starboard/player/video_dmp_reader.cc
@@ -120,13 +120,13 @@
switch (type) {
case kSbMediaTypeAudio: {
SB_DCHECK(index < audio_access_units_.size());
- const AudioAccessUnit& aau = audio_access_units_[index];
- return ConvertToPlayerSampleInfo(aau);
+ const AudioAccessUnit& audio_au = audio_access_units_[index];
+ return ConvertToPlayerSampleInfo(audio_au);
}
case kSbMediaTypeVideo: {
SB_DCHECK(index < video_access_units_.size());
- const VideoAccessUnit& vau = video_access_units_[index];
- return ConvertToPlayerSampleInfo(vau);
+ const VideoAccessUnit& video_au = video_access_units_[index];
+ return ConvertToPlayerSampleInfo(video_au);
}
}
SB_NOTREACHED() << "Unhandled SbMediaType";
diff --git a/src/starboard/shared/stub/cpu_features_get.cc b/src/starboard/shared/stub/cpu_features_get.cc
index 21c289f..a550da2 100644
--- a/src/starboard/shared/stub/cpu_features_get.cc
+++ b/src/starboard/shared/stub/cpu_features_get.cc
@@ -13,34 +13,23 @@
// limitations under the License.
#include "starboard/cpu_features.h"
+#include "starboard/shared/starboard/cpu_features.h"
#include <string.h>
#if SB_API_VERSION >= 11
+using starboard::shared::SetArmFeaturesInvalid;
+using starboard::shared::SetGeneralFeaturesInvalid;
+using starboard::shared::SetX86FeaturesInvalid;
+
bool SbCPUFeaturesGet(SbCPUFeatures* features) {
memset(features, 0, sizeof(*features));
features->architecture = kSbCPUFeaturesArchitectureUnknown;
- features->brand = "";
- features->cache_size = -1;
- features->has_fpu = false;
- features->hwcap = 0;
- features->hwcap2 = 0;
- features->arm.implementer = -1;
- features->arm.variant = -1;
- features->arm.revision = -1;
- features->arm.architecture_generation = -1;
- features->arm.part = -1;
-
- features->x86.vendor = "";
- features->x86.family = -1;
- features->x86.ext_family = -1;
- features->x86.model = -1;
- features->x86.ext_model = -1;
- features->x86.stepping = -1;
- features->x86.type = -1;
- features->x86.signature = -1;
+ SetGeneralFeaturesInvalid(features);
+ SetArmFeaturesInvalid(features);
+ SetX86FeaturesInvalid(features);
return false;
}
diff --git a/src/starboard/tools/testing/test_runner.py b/src/starboard/tools/testing/test_runner.py
index f5af1ca..ee3b7d7 100755
--- a/src/starboard/tools/testing/test_runner.py
+++ b/src/starboard/tools/testing/test_runner.py
@@ -473,6 +473,11 @@
total_flaky_failed_count = 0
total_filtered_count = 0
+ print # Explicit print for empty formatting line.
+ logging.info("TEST RUN COMPLETE.")
+ if results:
+ print # Explicit print for empty formatting line.
+
# If the number of run tests from a test binary cannot be
# determined, assume an error occurred while running it.
error = False
@@ -513,8 +518,7 @@
for test_case in flaky_failed_tests:
for retry in range(_FLAKY_RETRY_LIMIT):
retry_result = self._RunTest(target_name, test_case)
- # Explicit print used to have an empty newline for formatting.
- print
+ print # Explicit print for empty formatting line.
if retry_result[2] == 1:
flaky_passed_tests.append(test_case)
logging.info("%s succeeded on run #%d!\n", test_case, retry + 2)
@@ -529,20 +533,17 @@
else:
logging.info("") # formatting newline.
- logging.info("TEST RUN COMPLETE. RESULTS BELOW:")
- logging.info("") # formatting newline.
-
test_status = "SUCCEEDED"
- # If |return_code| is non-zero, the tests either crashed or failed.
- if return_code != 0:
- # If |run_count| is zero the tests crashed.
- if run_count == 0 or actual_failed_count > 0 or flaky_failed_count > 0:
- error = True
- test_status = "FAILED"
+
+ # Always mark as FAILED if we have a non-zero return code, or failing
+ # test.
+ if return_code != 0 or actual_failed_count > 0 or flaky_failed_count > 0:
+ error = True
+ test_status = "FAILED"
failed_test_groups.append(target_name)
logging.info("%s: %s.", target_name, test_status)
- if return_code != 0 and run_count == 0:
+ if return_code != 0 and run_count == 0 and filtered_count == 0:
logging.info(" Results not available. Did the test crash?")
logging.info("") # formatting newline.
continue
@@ -579,6 +580,8 @@
for line in filtered_tests:
logging.info(" %s", line)
logging.info("") # formatting newline.
+ logging.info(" RETURN CODE: %d", return_code)
+ logging.info("") # formatting newline.
overall_status = "SUCCEEDED"
result = True
diff --git a/src/third_party/boringssl/boringssl.gyp b/src/third_party/boringssl/boringssl.gyp
index 1edb8cd..a6cd7c8 100644
--- a/src/third_party/boringssl/boringssl.gyp
+++ b/src/third_party/boringssl/boringssl.gyp
@@ -44,6 +44,7 @@
],
'sources': [
'<(boringssl_root)/crypto/rand_extra/starboard.c',
+ '<(boringssl_root)/crypto/cpu-starboard.c',
],
'sources!': [
'<(boringssl_root)/crypto/bio/connect.c',
diff --git a/src/third_party/boringssl/boringssl.gypi b/src/third_party/boringssl/boringssl.gypi
index e8c5445..c1e4e2e 100644
--- a/src/third_party/boringssl/boringssl.gypi
+++ b/src/third_party/boringssl/boringssl.gypi
@@ -105,6 +105,7 @@
'<(boringssl_root)/crypto/chacha/chacha.c',
'<(boringssl_root)/crypto/cipher_extra/cipher_extra.c',
'<(boringssl_root)/crypto/cipher_extra/derive_key.c',
+ '<(boringssl_root)/crypto/cipher_extra/e_aesccm.c',
'<(boringssl_root)/crypto/cipher_extra/e_aesctrhmac.c',
'<(boringssl_root)/crypto/cipher_extra/e_aesgcmsiv.c',
'<(boringssl_root)/crypto/cipher_extra/e_chacha20poly1305.c',
diff --git a/src/third_party/boringssl/boringssl_tool.gyp b/src/third_party/boringssl/boringssl_tool.gyp
new file mode 100644
index 0000000..8397b22
--- /dev/null
+++ b/src/third_party/boringssl/boringssl_tool.gyp
@@ -0,0 +1,47 @@
+# Copyright 2019 Google Inc. All Rights Reserved.
+{
+ 'variables': {
+ 'boringssl_root%': '<(DEPTH)/third_party/boringssl/src',
+ },
+ 'targets': [
+ {
+ 'target_name': 'crypto_tool',
+ 'type': '<(final_executable_type)',
+ 'include_dirs': [
+ '<(boringssl_root)/include',
+ ],
+ 'defines': [
+ 'OPENSSL_NO_SOCK'
+ ],
+ 'sources' : [
+ '<(boringssl_root)/tool/args.cc',
+ '<(boringssl_root)/tool/ciphers.cc',
+ '<(boringssl_root)/tool/const.cc',
+ '<(boringssl_root)/tool/digest.cc',
+ '<(boringssl_root)/tool/file.cc',
+ '<(boringssl_root)/tool/generate_ed25519.cc',
+ '<(boringssl_root)/tool/genrsa.cc',
+ '<(boringssl_root)/tool/pkcs12.cc',
+ '<(boringssl_root)/tool/rand.cc',
+ '<(boringssl_root)/tool/sign.cc',
+ '<(boringssl_root)/tool/speed.cc',
+ '<(boringssl_root)/tool/tool.cc',
+ ],
+ 'dependencies' : [
+ '<(DEPTH)/third_party/boringssl/boringssl.gyp:crypto',
+ '<(DEPTH)/starboard/starboard.gyp:starboard'
+ ]
+ },
+ {
+ 'target_name': 'crypto_tool_deploy',
+ 'type': 'none',
+ 'dependencies': [
+ 'crypto_tool',
+ ],
+ 'variables': {
+ 'executable_name': 'crypto_tool',
+ },
+ 'includes': [ '../../starboard/build/deploy.gypi' ],
+ },
+ ],
+}
diff --git a/src/third_party/boringssl/src/config/starboard/openssl/opensslconf.h b/src/third_party/boringssl/src/config/starboard/openssl/opensslconf.h
index 3734c4d..6edf989 100644
--- a/src/third_party/boringssl/src/config/starboard/openssl/opensslconf.h
+++ b/src/third_party/boringssl/src/config/starboard/openssl/opensslconf.h
@@ -36,9 +36,10 @@
# define OPENSSL_NO_POSIX_IO
#endif
-#ifndef OPENSSL_NO_FP_API
-# define OPENSSL_NO_FP_API
-#endif
+// Benchmarking tool requires FP API to read certs and keys
+//#ifndef OPENSSL_NO_FP_API
+// # define OPENSSL_NO_FP_API
+//#endif
#ifndef OPENSSL_NO_DSO
# define OPENSSL_NO_DSO
diff --git a/src/third_party/boringssl/src/crypto/cpu-starboard.c b/src/third_party/boringssl/src/crypto/cpu-starboard.c
new file mode 100644
index 0000000..2f7609c
--- /dev/null
+++ b/src/third_party/boringssl/src/crypto/cpu-starboard.c
@@ -0,0 +1,124 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <openssl/opensslconf.h>
+#include <openssl/cpu.h>
+#include "../../crypto/internal.h"
+#include <starboard/cpu_features.h>
+#include <starboard/string.h>
+
+#if defined(STARBOARD) && (SB_API_VERSION >= 11)
+
+#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
+
+#define CPUID_01_REG_EDX 0
+#define CPUID_01_REG_ECX 1
+#define CPUID_07_REG_EBX 2
+#define CPUID_07_REG_ECX 3
+
+#define ID_01_EDX_IS_INTEL_BIT 30
+#define ID_01_ECX_SSSE3_BIT 9
+#define ID_01_ECX_AESNI_BIT 25
+#define ID_01_ECX_AVX_BIT 28
+
+static bool starboard_cpuid_setup_x86(void) {
+ OPENSSL_ia32cap_P[CPUID_01_REG_EDX] = 0;
+ OPENSSL_ia32cap_P[CPUID_01_REG_ECX] = 0;
+ OPENSSL_ia32cap_P[CPUID_07_REG_EBX] = 0;
+ OPENSSL_ia32cap_P[CPUID_07_REG_ECX] = 0;
+
+ SbCPUFeatures features;
+ if (!SbCPUFeaturesGet(&features)) {
+ return false;
+ }
+
+ if(features.architecture != kSbCPUFeaturesArchitectureX86_64 &&
+ features.architecture != kSbCPUFeaturesArchitectureX86) {
+ return false;
+ }
+
+ // OpenSSL has optimized AVX codepath enabled only on Intel CPUs
+ // The flag is passed as a "synthetic" value in reserved bit, i.e. CPUID
+ // never returns it. See https://github.com/openssl/openssl/commit/0c14980
+ if (!SbStringCompareAll(features.x86.vendor,"GenuineIntel")) {
+ OPENSSL_ia32cap_P[CPUID_01_REG_EDX] |= (1 << ID_01_EDX_IS_INTEL_BIT);
+ }
+
+ // Enables AESNI acceleration
+ if (features.x86.has_aesni)
+ OPENSSL_ia32cap_P[CPUID_01_REG_ECX] |= (1 << ID_01_ECX_AESNI_BIT);
+ // Enables AESNI and SHAx acceleration
+ if (features.x86.has_avx)
+ OPENSSL_ia32cap_P[CPUID_01_REG_ECX] |= (1 << ID_01_ECX_AVX_BIT);
+ // Enables alternate SHA acceleration
+ if (features.x86.has_ssse3)
+ OPENSSL_ia32cap_P[CPUID_01_REG_ECX] |= (1 << ID_01_ECX_SSSE3_BIT);
+
+ return true;
+}
+
+#else
+static bool starboard_cpuid_setup_x86(void) { return true; }
+#endif // defined(OPENSSL_X86 || OPENSSL_X86_64)
+
+#if defined(OPENSSL_ARM)
+
+#include <openssl/arm_arch.h>
+
+// This global provides ARM assembly routines capability flags
+extern uint32_t OPENSSL_armcap_P;
+
+static bool starboard_cpuid_setup_arm() {
+ OPENSSL_armcap_P = 0; // Reset the flags
+
+ SbCPUFeatures features;
+ if (!SbCPUFeaturesGet(&features)) {
+ return false;
+ }
+
+ if(features.architecture != kSbCPUFeaturesArchitectureArm64 &&
+ features.architecture != kSbCPUFeaturesArchitectureArm) {
+ return false;
+ }
+
+ if (features.arm.has_aes)
+ OPENSSL_armcap_P |= ARMV8_AES;
+ if (features.arm.has_sha1)
+ OPENSSL_armcap_P |= ARMV8_SHA1;
+ if (features.arm.has_sha2)
+ OPENSSL_armcap_P |= ARMV8_SHA256;
+ if (features.arm.has_pmull)
+ OPENSSL_armcap_P |= ARMV8_PMULL;
+ if (features.arm.has_neon)
+ OPENSSL_armcap_P |= ARMV7_NEON;
+
+ return true;
+}
+
+#else
+static bool starboard_cpuid_setup_arm(void) { return true; }
+#endif // OPENSSL_ARM
+
+void OPENSSL_cpuid_setup_starboard(void) {
+ if (!starboard_cpuid_setup_arm() ||
+ !starboard_cpuid_setup_x86() ) {
+#if !SB_IS(EVERGREEN)
+ // Fall back on original implementation if the platform
+ // does not yet support Starboard CPU detection
+ OPENSSL_cpuid_setup();
+#endif
+ }
+}
+
+#endif // STARBOARD
diff --git a/src/third_party/boringssl/src/crypto/crypto.c b/src/third_party/boringssl/src/crypto/crypto.c
index 93e2f82..4e9d316 100644
--- a/src/third_party/boringssl/src/crypto/crypto.c
+++ b/src/third_party/boringssl/src/crypto/crypto.c
@@ -148,8 +148,12 @@
// WARNING: this function may only configure the capability variables. See the
// note above about the linker bug.
#if defined(NEED_CPUID)
+#if defined(STARBOARD) && (SB_API_VERSION >= 11)
+ OPENSSL_cpuid_setup_starboard();
+#else
OPENSSL_cpuid_setup();
#endif
+#endif
}
void CRYPTO_library_init(void) {
diff --git a/src/third_party/boringssl/src/crypto/internal.h b/src/third_party/boringssl/src/crypto/internal.h
index 643c389..4b88bcf 100644
--- a/src/third_party/boringssl/src/crypto/internal.h
+++ b/src/third_party/boringssl/src/crypto/internal.h
@@ -155,6 +155,9 @@
defined(OPENSSL_AARCH64) || defined(OPENSSL_PPC64LE)
// OPENSSL_cpuid_setup initializes the platform-specific feature cache.
void OPENSSL_cpuid_setup(void);
+#if defined(STARBOARD)
+void OPENSSL_cpuid_setup_starboard(void);
+#endif
#endif
diff --git a/src/third_party/boringssl/src/tool/digest.cc b/src/third_party/boringssl/src/tool/digest.cc
index 7b6c88b..6020c99 100644
--- a/src/third_party/boringssl/src/tool/digest.cc
+++ b/src/third_party/boringssl/src/tool/digest.cc
@@ -37,8 +37,10 @@
OPENSSL_MSVC_PRAGMA(warning(pop))
#include <io.h>
#define PATH_MAX MAX_PATH
+#if !defined(STARBOARD)
typedef int ssize_t;
#endif
+#endif
#include <openssl/digest.h>
diff --git a/src/third_party/boringssl/src/tool/pkcs12.cc b/src/third_party/boringssl/src/tool/pkcs12.cc
index a8ddb0e..8440096 100644
--- a/src/third_party/boringssl/src/tool/pkcs12.cc
+++ b/src/third_party/boringssl/src/tool/pkcs12.cc
@@ -111,7 +111,7 @@
off < sizeof(password) - 1) ||
(n == -1 && errno == EINTR));
- char *newline = reinterpret_cast<char *>(OPENSSL_memchr(password, '\n', off));
+ char *newline = const_cast<char *>(reinterpret_cast<const char *>(OPENSSL_memchr(password, '\n', off)));
if (newline == NULL) {
return false;
}
diff --git a/src/third_party/boringssl/src/tool/speed.cc b/src/third_party/boringssl/src/tool/speed.cc
index 2175baa..194b618 100644
--- a/src/third_party/boringssl/src/tool/speed.cc
+++ b/src/third_party/boringssl/src/tool/speed.cc
@@ -32,6 +32,7 @@
#include <openssl/ecdsa.h>
#include <openssl/ec_key.h>
#include <openssl/evp.h>
+#include <openssl/mem.h>
#include <openssl/nid.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
diff --git a/src/third_party/boringssl/src/tool/tool.cc b/src/third_party/boringssl/src/tool/tool.cc
index 670d4e7..313da33 100644
--- a/src/third_party/boringssl/src/tool/tool.cc
+++ b/src/third_party/boringssl/src/tool/tool.cc
@@ -19,12 +19,18 @@
#include <openssl/err.h>
#include <openssl/ssl.h>
+#ifdef STARBOARD
+#include <starboard/client_porting/wrap_main/wrap_main.h>
+#endif
+
#if defined(OPENSSL_WINDOWS)
#include <fcntl.h>
#include <io.h>
#else
+#if defined(_POSIX_C_SOURCE) || defined(__ANDROID_API_)
#include <libgen.h>
#endif
+#endif
#include "internal.h"
@@ -43,16 +49,20 @@
static const Tool kTools[] = {
{ "ciphers", Ciphers },
+#ifndef OPENSSL_NO_SOCK
{ "client", Client },
+#endif
{ "isfips", IsFIPS },
{ "generate-ed25519", GenerateEd25519Key },
{ "genrsa", GenerateRSAKey },
{ "md5sum", MD5Sum },
{ "pkcs12", DoPKCS12 },
{ "rand", Rand },
+#ifndef OPENSSL_NO_SOCK
{ "s_client", Client },
{ "s_server", Server },
{ "server", Server },
+#endif
{ "sha1sum", SHA1Sum },
{ "sha224sum", SHA224Sum },
{ "sha256sum", SHA256Sum },
@@ -86,7 +96,11 @@
}
}
+#ifdef STARBOARD
+int crypto_tool_main(int argc, char **argv) {
+#else
int main(int argc, char **argv) {
+#endif
#if defined(OPENSSL_WINDOWS)
// Read and write in binary mode. This makes bssl on Windows consistent with
// bssl on other platforms, and also makes it consistent with MSYS's commands
@@ -111,8 +125,10 @@
int starting_arg = 1;
tool_func_t tool = nullptr;
#if !defined(OPENSSL_WINDOWS)
+#if defined(_POSIX_C_SOURCE) || defined(__ANDROID_API_)
tool = FindTool(basename(argv[0]));
#endif
+#endif
if (tool == nullptr) {
starting_arg++;
if (argc > 1) {
@@ -136,3 +152,7 @@
return 0;
}
+
+#ifdef STARBOARD
+STARBOARD_WRAP_SIMPLE_MAIN(crypto_tool_main);
+#endif
diff --git a/src/third_party/llvm-project/libcxxabi/libcxxabi.gyp b/src/third_party/llvm-project/libcxxabi/libcxxabi.gyp
index 7133871..bcf2e83 100644
--- a/src/third_party/llvm-project/libcxxabi/libcxxabi.gyp
+++ b/src/third_party/llvm-project/libcxxabi/libcxxabi.gyp
@@ -47,9 +47,6 @@
'-Wno-unused-command-line-argument',
],
'defines' : [
- # If not defined, this symbol is used to detect this function's presence in the C library
- # at runtime.
- 'HAVE___CXA_THREAD_ATEXIT_IMPL',
# This macro is used to disable extern template declarations in the libc++
# headers. The intended use case is for clients who wish to use the libc++
# headers without taking a dependency on the libc++ library itself.
@@ -75,7 +72,6 @@
'src/cxa_handlers.cpp',
'src/cxa_handlers.hpp',
'src/cxa_personality.cpp',
- 'src/cxa_thread_atexit.cpp',
'src/cxa_unexpected.cpp',
'src/cxa_vector.cpp',
'src/cxa_virtual.cpp',
@@ -96,6 +92,9 @@
'sources!': [
# We utilize exception handling and the following file breaks the build.
'src/cxa_noexception.cpp',
+
+ # Not needed and leaks __cxa_thread_atexit_impl.
+ 'src/cxa_thread_atexit.cpp',
],
'all_dependent_settings': {
'defines': [
diff --git a/src/third_party/llvm-project/libunwind/libunwind.gyp b/src/third_party/llvm-project/libunwind/libunwind.gyp
index 0802c24..833ca4a 100644
--- a/src/third_party/llvm-project/libunwind/libunwind.gyp
+++ b/src/third_party/llvm-project/libunwind/libunwind.gyp
@@ -53,6 +53,9 @@
# Build libunwind with concurrency built upon Starboard mutexes and
# condition variables.
'_LIBUNWIND_HAS_STARBOARD_THREADS',
+ 'LIBUNWIND_PRINT_APIS',
+ 'LIBUNWIND_PRINT_DWARF',
+ 'LIBUNWIND_PRINT_UNWINDING',
'LLVM_PATH="<(DEPTH)/third_party/llvm-project/llvm/"',
],
'sources': [
diff --git a/src/third_party/llvm-project/libunwind/src/libunwind.cpp b/src/third_party/llvm-project/libunwind/src/libunwind.cpp
index 3bd8ef1..a0fdecb 100644
--- a/src/third_party/llvm-project/libunwind/src/libunwind.cpp
+++ b/src/third_party/llvm-project/libunwind/src/libunwind.cpp
@@ -374,7 +374,12 @@
static bool checked = false;
static bool log = false;
if (!checked) {
- log = (getenv("LIBUNWIND_PRINT_APIS") != NULL);
+ log =
+#if defined(LIBUNWIND_PRINT_APIS)
+ true;
+#else // !defined(LIBUNWIND_PRINT_APIS)
+ false;
+#endif // defined(LIBUNWIND_PRINT_APIS)
checked = true;
}
return log;
@@ -386,7 +391,12 @@
static bool checked = false;
static bool log = false;
if (!checked) {
- log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL);
+ log =
+#if defined(LIBUNWIND_PRINT_UNWINDING)
+ true;
+#else // !defined(LIBUNWIND_PRINT_UNWINDING)
+ false;
+#endif // defined(LIBUNWIND_PRINT_UNWINDING)
checked = true;
}
return log;
@@ -398,7 +408,12 @@
static bool checked = false;
static bool log = false;
if (!checked) {
- log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL);
+ log =
+#if defined(LIBUNWIND_PRINT_DWARF)
+ true;
+#else // !defined(LIBUNWIND_PRINT_DWARF)
+ false;
+#endif // defined(LIBUNWIND_PRINT_DWARF)
checked = true;
}
return log;
diff --git a/src/third_party/musl/musl.gyp b/src/third_party/musl/musl.gyp
index f2ac88a..58afe2f 100644
--- a/src/third_party/musl/musl.gyp
+++ b/src/third_party/musl/musl.gyp
@@ -116,6 +116,7 @@
'include_dirs+': [
'src/starboard/internal',
'src/errno',
+ 'src/multibyte',
'src/time',
],
'sources': [
@@ -144,8 +145,13 @@
'src/starboard/time/__tz.c',
'src/starboard/time/clock_gettime.c',
+ 'src/ctype/iswspace.c',
'src/errno/strerror.c',
'src/exit/assert.c',
+ 'src/exit/atexit.c',
+ 'src/internal/floatscan.c',
+ 'src/internal/intscan.c',
+ 'src/internal/shgetc.c',
'src/locale/strcoll.c',
'src/locale/strcoll.c',
'src/locale/strxfrm.c',
@@ -154,7 +160,24 @@
'src/locale/wcscoll.c',
'src/locale/wcsxfrm.c',
'src/locale/wcsxfrm.c',
+ 'src/math/copysignl.c',
+ 'src/math/scalbnl.c',
+ 'src/multibyte/btowc.c',
+ 'src/multibyte/internal.c',
+ 'src/multibyte/mbrlen.c',
+ 'src/multibyte/mbrtowc.c',
+ 'src/multibyte/mbsnrtowcs.c',
+ 'src/multibyte/mbsrtowcs.c',
+ 'src/multibyte/mbtowc.c',
+ 'src/multibyte/wcrtomb.c',
+ 'src/multibyte/wcsnrtombs.c',
+ 'src/multibyte/wcsrtombs.c',
+ 'src/multibyte/wcstombs.c',
+ 'src/multibyte/wctob.c',
+ 'src/stdio/__toread.c',
+ 'src/stdio/__uflow.c',
'src/stdio/fprintf.c',
+ 'src/stdio/fwrite.c',
'src/stdio/printf.c',
'src/stdio/snprintf.c',
'src/stdio/sscanf.c',
@@ -164,6 +187,8 @@
'src/stdlib/abs.c',
'src/stdlib/labs.c',
'src/stdlib/llabs.c',
+ 'src/stdlib/wcstod.c',
+ 'src/stdlib/wcstol.c',
'src/string/strerror_r.c',
'src/time/__month_to_secs.c',
'src/time/__tm_to_secs.c',
diff --git a/src/third_party/musl/src/exit/atexit.c b/src/third_party/musl/src/exit/atexit.c
index cd3b0a6..5b51b4b 100644
--- a/src/third_party/musl/src/exit/atexit.c
+++ b/src/third_party/musl/src/exit/atexit.c
@@ -2,6 +2,13 @@
#include <stdint.h>
#include "libc.h"
+#ifdef STARBOARD
+#include "starboard/common/log.h"
+#include "starboard/mutex.h"
+#include "starboard/thread_types.h"
+#include "starboard/types.h"
+#endif // STARBOARD
+
/* Ensure that at least 32 atexit handlers can be registered without malloc */
#define COUNT 32
@@ -13,7 +20,19 @@
} builtin, *head;
static int slot;
+#ifdef STARBOARD
+static SbMutex lock = SB_MUTEX_INITIALIZER;
+#define LOCK(x) \
+ do { \
+ SB_DCHECK(SbMutexAcquire(&x) == kSbMutexAcquired); \
+ } while (0)
+#define UNLOCK(x) \
+ do { \
+ SB_DCHECK(SbMutexRelease(&x)); \
+ } while (0)
+#else // !STARBOARD
static volatile int lock[1];
+#endif // STARBOARD
void __funcs_on_exit()
{
diff --git a/src/third_party/musl/src/internal/libc.h b/src/third_party/musl/src/internal/libc.h
index 5e14518..1fa9243 100644
--- a/src/third_party/musl/src/internal/libc.h
+++ b/src/third_party/musl/src/internal/libc.h
@@ -51,8 +51,10 @@
void __unlock(volatile int *) ATTR_LIBC_VISIBILITY;
int __lockfile(FILE *) ATTR_LIBC_VISIBILITY;
void __unlockfile(FILE *) ATTR_LIBC_VISIBILITY;
+#ifndef STARBOARD
#define LOCK(x) __lock(x)
#define UNLOCK(x) __unlock(x)
+#endif // STARBOARD
void __synccall(void (*)(void *), void *);
int __setxid(int, int, int, int);
diff --git a/src/third_party/musl/src/internal/stdio_impl.h b/src/third_party/musl/src/internal/stdio_impl.h
index 1127a49..d3ce332 100644
--- a/src/third_party/musl/src/internal/stdio_impl.h
+++ b/src/third_party/musl/src/internal/stdio_impl.h
@@ -2,14 +2,20 @@
#define _STDIO_IMPL_H
#include <stdio.h>
-#include "syscall.h"
#include "libc.h"
+// When STARBOARD is defined we only want to include the definition of _IO_FILE,
+// a.k.a. FILE, along with a few constants used when working with wide strings.
+
+#ifndef STARBOARD
+#include "syscall.h"
+
#define UNGET 8
#define FFINALLOCK(f) ((f)->lock>=0 ? __lockfile((f)) : 0)
#define FLOCK(f) int __need_unlock = ((f)->lock>=0 ? __lockfile((f)) : 0)
#define FUNLOCK(f) do { if (__need_unlock) __unlockfile((f)); } while (0)
+#endif // STARBOARD
#define F_PERM 1
#define F_NORD 4
@@ -50,6 +56,7 @@
struct __locale_struct *locale;
};
+#ifndef STARBOARD
size_t __stdio_read(FILE *, unsigned char *, size_t);
size_t __stdio_write(FILE *, const unsigned char *, size_t);
size_t __stdout_write(FILE *, const unsigned char *, size_t);
@@ -93,5 +100,6 @@
/* Caller-allocated FILE * operations */
FILE *__fopen_rb_ca(const char *, FILE *, unsigned char *, size_t);
int __fclose_ca(FILE *);
+#endif // STARBOARD
#endif
diff --git a/src/third_party/musl/src/starboard/internal/stdio_impl.h b/src/third_party/musl/src/starboard/internal/stdio_impl.h
deleted file mode 100644
index 57133a2..0000000
--- a/src/third_party/musl/src/starboard/internal/stdio_impl.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef _STDIO_IMPL_H
-#define _STDIO_IMPL_H
-
-#include <stdio.h>
-#include "libc.h"
-
-// Slimmed version of stdio_impl.h that only provides the definition of
-// _IO_FILE, a.k.a. FILE.
-
-struct _IO_FILE {
- unsigned flags;
- unsigned char *rpos, *rend;
- int (*close)(FILE *);
- unsigned char *wend, *wpos;
- unsigned char *mustbezero_1;
- unsigned char *wbase;
- size_t (*read)(FILE *, unsigned char *, size_t);
- size_t (*write)(FILE *, const unsigned char *, size_t);
- off_t (*seek)(FILE *, off_t, int);
- unsigned char *buf;
- size_t buf_size;
- FILE *prev, *next;
- int fd;
- int pipe_pid;
- long lockcount;
- short dummy3;
- signed char mode;
- signed char lbf;
- volatile int lock;
- volatile int waiters;
- void *cookie;
- off_t off;
- char *getln_buf;
- void *mustbezero_2;
- unsigned char *shend;
- off_t shlim, shcnt;
- FILE *prev_locked, *next_locked;
- struct __locale_struct *locale;
-};
-
-#endif
diff --git a/src/third_party/musl/src/stdio/__toread.c b/src/third_party/musl/src/stdio/__toread.c
index 35f67b8..20fef0a 100644
--- a/src/third_party/musl/src/stdio/__toread.c
+++ b/src/third_party/musl/src/stdio/__toread.c
@@ -13,9 +13,12 @@
return (f->flags & F_EOF) ? EOF : 0;
}
+// This function is unused, and leaks __stdio_exit_needed.
+#ifndef STARBOARD
void __stdio_exit_needed(void);
void __toread_needs_stdio_exit()
{
__stdio_exit_needed();
}
+#endif // STARBOARD
diff --git a/src/third_party/musl/src/stdio/fwrite.c b/src/third_party/musl/src/stdio/fwrite.c
index 7a567b2..8a5d9c5 100644
--- a/src/third_party/musl/src/stdio/fwrite.c
+++ b/src/third_party/musl/src/stdio/fwrite.c
@@ -1,6 +1,11 @@
#include "stdio_impl.h"
#include <string.h>
+#ifdef STARBOARD
+#include "starboard/common/log.h"
+#endif // STARBOARD
+
+#ifndef STARBOARD
size_t __fwritex(const unsigned char *restrict s, size_t l, FILE *restrict f)
{
size_t i=0;
@@ -24,15 +29,21 @@
f->wpos += l;
return l+i;
}
+#endif
size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f)
{
+#ifdef STARBOARD
+ SB_NOTREACHED();
+ return 0;
+#else // !STARBOARD
size_t k, l = size*nmemb;
if (!size) nmemb = 0;
FLOCK(f);
k = __fwritex(src, l, f);
FUNLOCK(f);
return k==l ? nmemb : k/size;
+#endif // STARBOARD
}
weak_alias(fwrite, fwrite_unlocked);
diff --git a/src/third_party/openssl/openssl/Makefile b/src/third_party/openssl/openssl/Makefile
deleted file mode 100644
index d5db11b..0000000
--- a/src/third_party/openssl/openssl/Makefile
+++ /dev/null
@@ -1,685 +0,0 @@
-### Generated automatically from Makefile.org by Configure.
-
-##
-## Makefile for OpenSSL
-##
-
-VERSION=1.0.1c
-MAJOR=1
-MINOR=0.1
-SHLIB_VERSION_NUMBER=1.0.0
-SHLIB_VERSION_HISTORY=
-SHLIB_MAJOR=1
-SHLIB_MINOR=0.0
-SHLIB_EXT=
-PLATFORM=dist
-OPTIONS= no-ec_nistp_64_gcc_128 no-gmp no-jpake no-krb5 no-md2 no-rc5 no-rfc3779 no-sctp no-shared no-store no-zlib no-zlib-dynamic static-engine
-CONFIGURE_ARGS=dist
-SHLIB_TARGET=
-
-# HERE indicates where this Makefile lives. This can be used to indicate
-# where sub-Makefiles are expected to be. Currently has very limited usage,
-# and should probably not be bothered with at all.
-HERE=.
-
-# INSTALL_PREFIX is for package builders so that they can configure
-# for, say, /usr/ and yet have everything installed to /tmp/somedir/usr/.
-# Normally it is left empty.
-INSTALL_PREFIX=
-INSTALLTOP=/usr/local/ssl
-
-# Do not edit this manually. Use Configure --openssldir=DIR do change this!
-OPENSSLDIR=/usr/local/ssl
-
-# NO_IDEA - Define to build without the IDEA algorithm
-# NO_RC4 - Define to build without the RC4 algorithm
-# NO_RC2 - Define to build without the RC2 algorithm
-# THREADS - Define when building with threads, you will probably also need any
-# system defines as well, i.e. _REENTERANT for Solaris 2.[34]
-# TERMIO - Define the termio terminal subsystem, needed if sgtty is missing.
-# TERMIOS - Define the termios terminal subsystem, Silicon Graphics.
-# LONGCRYPT - Define to use HPUX 10.x's long password modification to crypt(3).
-# DEVRANDOM - Give this the value of the 'random device' if your OS supports
-# one. 32 bytes will be read from this when the random
-# number generator is initalised.
-# SSL_FORBID_ENULL - define if you want the server to be not able to use the
-# NULL encryption ciphers.
-#
-# LOCK_DEBUG - turns on lots of lock debug output :-)
-# REF_CHECK - turn on some xyz_free() assertions.
-# REF_PRINT - prints some stuff on structure free.
-# CRYPTO_MDEBUG - turns on my 'memory leak' detecting stuff
-# MFUNC - Make all Malloc/Free/Realloc calls call
-# CRYPTO_malloc/CRYPTO_free/CRYPTO_realloc which can be setup to
-# call application defined callbacks via CRYPTO_set_mem_functions()
-# MD5_ASM needs to be defined to use the x86 assembler for MD5
-# SHA1_ASM needs to be defined to use the x86 assembler for SHA1
-# RMD160_ASM needs to be defined to use the x86 assembler for RIPEMD160
-# Do not define B_ENDIAN or L_ENDIAN if 'unsigned long' == 8. It must
-# equal 4.
-# PKCS1_CHECK - pkcs1 tests.
-
-CC= cc
-CFLAG= -O
-DEPFLAG= -DOPENSSL_NO_EC_NISTP_64_GCC_128 -DOPENSSL_NO_GMP -DOPENSSL_NO_JPAKE -DOPENSSL_NO_MD2 -DOPENSSL_NO_RC5 -DOPENSSL_NO_RFC3779 -DOPENSSL_NO_SCTP -DOPENSSL_NO_STORE
-PEX_LIBS=
-EX_LIBS=
-EXE_EXT=
-ARFLAGS=
-AR= ar $(ARFLAGS) r
-RANLIB= /usr/bin/ranlib
-NM= nm
-PERL= /usr/bin/perl
-TAR= tar
-TARFLAGS= --no-recursion
-MAKEDEPPROG=makedepend
-LIBDIR=lib
-
-# We let the C compiler driver to take care of .s files. This is done in
-# order to be excused from maintaining a separate set of architecture
-# dependent assembler flags. E.g. if you throw -mcpu=ultrasparc at SPARC
-# gcc, then the driver will automatically translate it to -xarch=v8plus
-# and pass it down to assembler.
-AS=$(CC) -c
-ASFLAG=$(CFLAG)
-
-# For x86 assembler: Set PROCESSOR to 386 if you want to support
-# the 80386.
-PROCESSOR=
-
-# CPUID module collects small commonly used assembler snippets
-CPUID_OBJ= mem_clr.o
-BN_ASM= bn_asm.o
-DES_ENC= des_enc.o fcrypt_b.o
-AES_ENC= aes_core.o aes_cbc.o
-BF_ENC= bf_enc.o
-CAST_ENC= c_enc.o
-RC4_ENC= rc4_enc.o rc4_skey.o
-RC5_ENC= rc5_enc.o
-MD5_ASM_OBJ=
-SHA1_ASM_OBJ=
-RMD160_ASM_OBJ=
-WP_ASM_OBJ= wp_block.o
-CMLL_ENC= camellia.o cmll_misc.o cmll_cbc.o
-MODES_ASM_OBJ=
-ENGINES_ASM_OBJ=
-PERLASM_SCHEME=
-
-# KRB5 stuff
-KRB5_INCLUDES=
-LIBKRB5=
-
-# Zlib stuff
-ZLIB_INCLUDE=
-LIBZLIB=
-
-# TOP level FIPS install directory.
-FIPSDIR=/usr/local/ssl/fips-2.0
-
-# This is the location of fipscanister.o and friends.
-# The FIPS module build will place it $(INSTALLTOP)/lib
-# but since $(INSTALLTOP) can only take the default value
-# when the module is built it will be in /usr/local/ssl/lib
-# $(INSTALLTOP) for this build may be different so hard
-# code the path.
-
-FIPSLIBDIR=
-
-# The location of the library which contains fipscanister.o
-# normally it will be libcrypto unless fipsdso is set in which
-# case it will be libfips. If not compiling in FIPS mode at all
-# this is empty making it a useful test for a FIPS compile.
-
-FIPSCANLIB=
-
-# Shared library base address. Currently only used on Windows.
-#
-
-BASEADDR=0xFB00000
-
-DIRS= crypto ssl engines apps test tools
-ENGDIRS= ccgost
-SHLIBDIRS= crypto ssl
-
-# dirs in crypto to build
-SDIRS= \
- objects \
- md4 md5 sha mdc2 hmac ripemd whrlpool \
- des aes rc2 rc4 idea bf cast camellia seed modes \
- bn ec rsa dsa ecdsa dh ecdh dso engine \
- buffer bio stack lhash rand err \
- evp asn1 pem x509 x509v3 conf txt_db pkcs7 pkcs12 comp ocsp ui krb5 \
- cms pqueue ts srp cmac
-# keep in mind that the above list is adjusted by ./Configure
-# according to no-xxx arguments...
-
-# tests to perform. "alltests" is a special word indicating that all tests
-# should be performed.
-TESTS = alltests
-
-MAKEFILE= Makefile
-
-MANDIR=$(OPENSSLDIR)/man
-MAN1=1
-MAN3=3
-MANSUFFIX=
-HTMLSUFFIX=html
-HTMLDIR=$(OPENSSLDIR)/html
-SHELL=/bin/sh
-
-TOP= .
-ONEDIRS=out tmp
-EDIRS= times doc bugs util include certs ms shlib mt demos perl sf dep VMS
-WDIRS= windows
-LIBS= libcrypto.a libssl.a
-SHARED_CRYPTO=libcrypto$(SHLIB_EXT)
-SHARED_SSL=libssl$(SHLIB_EXT)
-SHARED_LIBS=
-SHARED_LIBS_LINK_EXTS=
-SHARED_LDFLAGS=
-
-GENERAL= Makefile
-BASENAME= openssl
-NAME= $(BASENAME)-$(VERSION)
-TARFILE= $(NAME).tar
-WTARFILE= $(NAME)-win.tar
-EXHEADER= e_os2.h
-HEADER= e_os.h
-
-all: Makefile build_all openssl.pc libssl.pc libcrypto.pc
-
-# as we stick to -e, CLEARENV ensures that local variables in lower
-# Makefiles remain local and variable. $${VAR+VAR} is tribute to Korn
-# shell, which [annoyingly enough] terminates unset with error if VAR
-# is not present:-( TOP= && unset TOP is tribute to HP-UX /bin/sh,
-# which terminates unset with error if no variable was present:-(
-CLEARENV= TOP= && unset TOP $${LIB+LIB} $${LIBS+LIBS} \
- $${INCLUDE+INCLUDE} $${INCLUDES+INCLUDES} \
- $${DIR+DIR} $${DIRS+DIRS} $${SRC+SRC} \
- $${LIBSRC+LIBSRC} $${LIBOBJ+LIBOBJ} $${ALL+ALL} \
- $${EXHEADER+EXHEADER} $${HEADER+HEADER} \
- $${GENERAL+GENERAL} $${CFLAGS+CFLAGS} \
- $${ASFLAGS+ASFLAGS} $${AFLAGS+AFLAGS} \
- $${LDCMD+LDCMD} $${LDFLAGS+LDFLAGS} $${SCRIPTS+SCRIPTS} \
- $${SHAREDCMD+SHAREDCMD} $${SHAREDFLAGS+SHAREDFLAGS} \
- $${SHARED_LIB+SHARED_LIB} $${LIBEXTRAS+LIBEXTRAS}
-
-BUILDENV= PLATFORM='$(PLATFORM)' PROCESSOR='$(PROCESSOR)' \
- CC='$(CC)' CFLAG='$(CFLAG)' \
- AS='$(CC)' ASFLAG='$(CFLAG) -c' \
- AR='$(AR)' NM='$(NM)' RANLIB='$(RANLIB)' \
- CROSS_COMPILE='$(CROSS_COMPILE)' \
- PERL='$(PERL)' ENGDIRS='$(ENGDIRS)' \
- SDIRS='$(SDIRS)' LIBRPATH='$(INSTALLTOP)/$(LIBDIR)' \
- INSTALL_PREFIX='$(INSTALL_PREFIX)' \
- INSTALLTOP='$(INSTALLTOP)' OPENSSLDIR='$(OPENSSLDIR)' \
- LIBDIR='$(LIBDIR)' \
- MAKEDEPEND='$$$${TOP}/util/domd $$$${TOP} -MD $(MAKEDEPPROG)' \
- DEPFLAG='-DOPENSSL_NO_DEPRECATED $(DEPFLAG)' \
- MAKEDEPPROG='$(MAKEDEPPROG)' \
- SHARED_LDFLAGS='$(SHARED_LDFLAGS)' \
- KRB5_INCLUDES='$(KRB5_INCLUDES)' LIBKRB5='$(LIBKRB5)' \
- ZLIB_INCLUDE='$(ZLIB_INCLUDE)' LIBZLIB='$(LIBZLIB)' \
- EXE_EXT='$(EXE_EXT)' SHARED_LIBS='$(SHARED_LIBS)' \
- SHLIB_EXT='$(SHLIB_EXT)' SHLIB_TARGET='$(SHLIB_TARGET)' \
- PEX_LIBS='$(PEX_LIBS)' EX_LIBS='$(EX_LIBS)' \
- CPUID_OBJ='$(CPUID_OBJ)' \
- BN_ASM='$(BN_ASM)' DES_ENC='$(DES_ENC)' \
- AES_ENC='$(AES_ENC)' CMLL_ENC='$(CMLL_ENC)' \
- BF_ENC='$(BF_ENC)' CAST_ENC='$(CAST_ENC)' \
- RC4_ENC='$(RC4_ENC)' RC5_ENC='$(RC5_ENC)' \
- SHA1_ASM_OBJ='$(SHA1_ASM_OBJ)' \
- MD5_ASM_OBJ='$(MD5_ASM_OBJ)' \
- RMD160_ASM_OBJ='$(RMD160_ASM_OBJ)' \
- WP_ASM_OBJ='$(WP_ASM_OBJ)' \
- MODES_ASM_OBJ='$(MODES_ASM_OBJ)' \
- ENGINES_ASM_OBJ='$(ENGINES_ASM_OBJ)' \
- PERLASM_SCHEME='$(PERLASM_SCHEME)' \
- FIPSLIBDIR='${FIPSLIBDIR}' \
- FIPSDIR='${FIPSDIR}' \
- FIPSCANLIB="$${FIPSCANLIB:-$(FIPSCANLIB)}" \
- THIS=$${THIS:-$@} MAKEFILE=Makefile MAKEOVERRIDES=
-# MAKEOVERRIDES= effectively "equalizes" GNU-ish and SysV-ish make flavors,
-# which in turn eliminates ambiguities in variable treatment with -e.
-
-# BUILD_CMD is a generic macro to build a given target in a given
-# subdirectory. The target must be given through the shell variable
-# `target' and the subdirectory to build in must be given through `dir'.
-# This macro shouldn't be used directly, use RECURSIVE_BUILD_CMD or
-# BUILD_ONE_CMD instead.
-#
-# BUILD_ONE_CMD is a macro to build a given target in a given
-# subdirectory if that subdirectory is part of $(DIRS). It requires
-# exactly the same shell variables as BUILD_CMD.
-#
-# RECURSIVE_BUILD_CMD is a macro to build a given target in all
-# subdirectories defined in $(DIRS). It requires that the target
-# is given through the shell variable `target'.
-BUILD_CMD= if [ -d "$$dir" ]; then \
- ( cd $$dir && echo "making $$target in $$dir..." && \
- $(CLEARENV) && $(MAKE) -e $(BUILDENV) TOP=.. DIR=$$dir $$target \
- ) || exit 1; \
- fi
-RECURSIVE_BUILD_CMD=for dir in $(DIRS); do $(BUILD_CMD); done
-BUILD_ONE_CMD=\
- if expr " $(DIRS) " : ".* $$dir " >/dev/null 2>&1; then \
- $(BUILD_CMD); \
- fi
-
-reflect:
- @[ -n "$(THIS)" ] && $(CLEARENV) && $(MAKE) $(THIS) -e $(BUILDENV)
-
-sub_all: build_all
-build_all: build_libs build_apps build_tests build_tools
-
-build_libs: build_crypto build_ssl build_engines
-
-build_crypto:
- @dir=crypto; target=all; $(BUILD_ONE_CMD)
-build_ssl:
- @dir=ssl; target=all; $(BUILD_ONE_CMD)
-build_engines:
- @dir=engines; target=all; $(BUILD_ONE_CMD)
-build_apps:
- @dir=apps; target=all; $(BUILD_ONE_CMD)
-build_tests:
- @dir=test; target=all; $(BUILD_ONE_CMD)
-build_tools:
- @dir=tools; target=all; $(BUILD_ONE_CMD)
-
-all_testapps: build_libs build_testapps
-build_testapps:
- @dir=crypto; target=testapps; $(BUILD_ONE_CMD)
-
-fips_premain_dso$(EXE_EXT): libcrypto.a
- [ -z "$(FIPSCANLIB)" ] || $(CC) $(CFLAG) -Iinclude \
- -DFINGERPRINT_PREMAIN_DSO_LOAD -o $@ \
- $(FIPSLIBDIR)fips_premain.c $(FIPSLIBDIR)fipscanister.o \
- libcrypto.a $(EX_LIBS)
-
-libcrypto$(SHLIB_EXT): libcrypto.a fips_premain_dso$(EXE_EXT)
- @if [ "$(SHLIB_TARGET)" != "" ]; then \
- if [ "$(FIPSCANLIB)" = "libcrypto" ]; then \
- FIPSLD_LIBCRYPTO=libcrypto.a ; \
- FIPSLD_CC="$(CC)"; CC=$(FIPSDIR)/bin/fipsld; \
- export CC FIPSLD_CC FIPSLD_LIBCRYPTO; \
- fi; \
- $(MAKE) -e SHLIBDIRS=crypto build-shared; \
- else \
- echo "There's no support for shared libraries on this platform" >&2; \
- exit 1; \
- fi
-
-libssl$(SHLIB_EXT): libcrypto$(SHLIB_EXT) libssl.a
- @if [ "$(SHLIB_TARGET)" != "" ]; then \
- $(MAKE) SHLIBDIRS=ssl SHLIBDEPS='-lcrypto' build-shared; \
- else \
- echo "There's no support for shared libraries on this platform" >&2; \
- exit 1; \
- fi
-
-clean-shared:
- @set -e; for i in $(SHLIBDIRS); do \
- if [ -n "$(SHARED_LIBS_LINK_EXTS)" ]; then \
- tmp="$(SHARED_LIBS_LINK_EXTS)"; \
- for j in $${tmp:-x}; do \
- ( set -x; rm -f lib$$i$$j ); \
- done; \
- fi; \
- ( set -x; rm -f lib$$i$(SHLIB_EXT) ); \
- if [ "$(PLATFORM)" = "Cygwin" ]; then \
- ( set -x; rm -f cyg$$i$(SHLIB_EXT) lib$$i$(SHLIB_EXT).a ); \
- fi; \
- done
-
-link-shared:
- @ set -e; for i in $(SHLIBDIRS); do \
- $(MAKE) -f $(HERE)/Makefile.shared -e $(BUILDENV) \
- LIBNAME=$$i LIBVERSION=$(SHLIB_MAJOR).$(SHLIB_MINOR) \
- LIBCOMPATVERSIONS=";$(SHLIB_VERSION_HISTORY)" \
- symlink.$(SHLIB_TARGET); \
- libs="$$libs -l$$i"; \
- done
-
-build-shared: do_$(SHLIB_TARGET) link-shared
-
-do_$(SHLIB_TARGET):
- @ set -e; libs='-L. $(SHLIBDEPS)'; for i in $(SHLIBDIRS); do \
- if [ "$$i" = "ssl" -a -n "$(LIBKRB5)" ]; then \
- libs="$(LIBKRB5) $$libs"; \
- fi; \
- $(CLEARENV) && $(MAKE) -f Makefile.shared -e $(BUILDENV) \
- LIBNAME=$$i LIBVERSION=$(SHLIB_MAJOR).$(SHLIB_MINOR) \
- LIBCOMPATVERSIONS=";$(SHLIB_VERSION_HISTORY)" \
- LIBDEPS="$$libs $(EX_LIBS)" \
- link_a.$(SHLIB_TARGET); \
- libs="-l$$i $$libs"; \
- done
-
-libcrypto.pc: Makefile
- @ ( echo 'prefix=$(INSTALLTOP)'; \
- echo 'exec_prefix=$${prefix}'; \
- echo 'libdir=$${exec_prefix}/$(LIBDIR)'; \
- echo 'includedir=$${prefix}/include'; \
- echo ''; \
- echo 'Name: OpenSSL-libcrypto'; \
- echo 'Description: OpenSSL cryptography library'; \
- echo 'Version: '$(VERSION); \
- echo 'Requires: '; \
- echo 'Libs: -L$${libdir} -lcrypto'; \
- echo 'Libs.private: $(EX_LIBS)'; \
- echo 'Cflags: -I$${includedir} $(KRB5_INCLUDES)' ) > libcrypto.pc
-
-libssl.pc: Makefile
- @ ( echo 'prefix=$(INSTALLTOP)'; \
- echo 'exec_prefix=$${prefix}'; \
- echo 'libdir=$${exec_prefix}/$(LIBDIR)'; \
- echo 'includedir=$${prefix}/include'; \
- echo ''; \
- echo 'Name: OpenSSL'; \
- echo 'Description: Secure Sockets Layer and cryptography libraries'; \
- echo 'Version: '$(VERSION); \
- echo 'Requires: '; \
- echo 'Libs: -L$${libdir} -lssl -lcrypto'; \
- echo 'Libs.private: $(EX_LIBS)'; \
- echo 'Cflags: -I$${includedir} $(KRB5_INCLUDES)' ) > libssl.pc
-
-openssl.pc: Makefile
- @ ( echo 'prefix=$(INSTALLTOP)'; \
- echo 'exec_prefix=$${prefix}'; \
- echo 'libdir=$${exec_prefix}/$(LIBDIR)'; \
- echo 'includedir=$${prefix}/include'; \
- echo ''; \
- echo 'Name: OpenSSL'; \
- echo 'Description: Secure Sockets Layer and cryptography libraries and tools'; \
- echo 'Version: '$(VERSION); \
- echo 'Requires: '; \
- echo 'Libs: -L$${libdir} -lssl -lcrypto'; \
- echo 'Libs.private: $(EX_LIBS)'; \
- echo 'Cflags: -I$${includedir} $(KRB5_INCLUDES)' ) > openssl.pc
-
-Makefile: Makefile.org Configure config
- @echo "Makefile is older than Makefile.org, Configure or config."
- @echo "Reconfigure the source tree (via './config' or 'perl Configure'), please."
- @false
-
-libclean:
- rm -f *.map *.so *.so.* *.dylib *.dll engines/*.so engines/*.dll engines/*.dylib *.a engines/*.a */lib */*/lib
-
-clean: libclean
- rm -f shlib/*.o *.o core a.out fluff rehash.time testlog make.log cctest cctest.c
- @set -e; target=clean; $(RECURSIVE_BUILD_CMD)
- rm -f $(LIBS)
- rm -f openssl.pc libssl.pc libcrypto.pc
- rm -f speed.* .pure
- rm -f $(TARFILE)
- @set -e; for i in $(ONEDIRS) ;\
- do \
- rm -fr $$i/*; \
- done
-
-makefile.one: files
- $(PERL) util/mk1mf.pl >makefile.one; \
- sh util/do_ms.sh
-
-files:
- $(PERL) $(TOP)/util/files.pl Makefile > $(TOP)/MINFO
- @set -e; target=files; $(RECURSIVE_BUILD_CMD)
-
-links:
- @$(PERL) $(TOP)/util/mkdir-p.pl include/openssl
- @$(PERL) $(TOP)/util/mklink.pl include/openssl $(EXHEADER)
- @set -e; target=links; $(RECURSIVE_BUILD_CMD)
-
-gentests:
- @(cd test && echo "generating dummy tests (if needed)..." && \
- $(CLEARENV) && $(MAKE) -e $(BUILDENV) TESTS='$(TESTS)' OPENSSL_DEBUG_MEMORY=on generate );
-
-dclean:
- rm -rf *.bak include/openssl certs/.0
- @set -e; target=dclean; $(RECURSIVE_BUILD_CMD)
-
-rehash: rehash.time
-rehash.time: certs apps
- @if [ -z "$(CROSS_COMPILE)" ]; then \
- (OPENSSL="`pwd`/util/opensslwrap.sh"; \
- [ -x "apps/openssl.exe" ] && OPENSSL="apps/openssl.exe" || :; \
- OPENSSL_DEBUG_MEMORY=on; \
- export OPENSSL OPENSSL_DEBUG_MEMORY; \
- $(PERL) tools/c_rehash certs) && \
- touch rehash.time; \
- else :; fi
-
-test: tests
-
-tests: rehash
- @(cd test && echo "testing..." && \
- $(CLEARENV) && $(MAKE) -e $(BUILDENV) TOP=.. TESTS='$(TESTS)' OPENSSL_DEBUG_MEMORY=on OPENSSL_CONF=../apps/openssl.cnf tests );
- OPENSSL_CONF=apps/openssl.cnf util/opensslwrap.sh version -a
-
-report:
- @$(PERL) util/selftest.pl
-
-depend:
- @set -e; target=depend; $(RECURSIVE_BUILD_CMD)
-
-lint:
- @set -e; target=lint; $(RECURSIVE_BUILD_CMD)
-
-tags:
- rm -f TAGS
- find . -name '[^.]*.[ch]' | xargs etags -a
-
-errors:
- $(PERL) util/ck_errf.pl -strict */*.c */*/*.c
- $(PERL) util/mkerr.pl -recurse -write
- (cd engines; $(MAKE) PERL=$(PERL) errors)
-
-stacks:
- $(PERL) util/mkstack.pl -write
-
-util/libeay.num::
- $(PERL) util/mkdef.pl crypto update
-
-util/ssleay.num::
- $(PERL) util/mkdef.pl ssl update
-
-crypto/objects/obj_dat.h: crypto/objects/obj_dat.pl crypto/objects/obj_mac.h
- $(PERL) crypto/objects/obj_dat.pl crypto/objects/obj_mac.h crypto/objects/obj_dat.h
-crypto/objects/obj_mac.h: crypto/objects/objects.pl crypto/objects/objects.txt crypto/objects/obj_mac.num
- $(PERL) crypto/objects/objects.pl crypto/objects/objects.txt crypto/objects/obj_mac.num crypto/objects/obj_mac.h
-crypto/objects/obj_xref.h: crypto/objects/objxref.pl crypto/objects/obj_xref.txt crypto/objects/obj_mac.num
- $(PERL) crypto/objects/objxref.pl crypto/objects/obj_mac.num crypto/objects/obj_xref.txt >crypto/objects/obj_xref.h
-
-apps/openssl-vms.cnf: apps/openssl.cnf
- $(PERL) VMS/VMSify-conf.pl < apps/openssl.cnf > apps/openssl-vms.cnf
-
-crypto/bn/bn_prime.h: crypto/bn/bn_prime.pl
- $(PERL) crypto/bn/bn_prime.pl >crypto/bn/bn_prime.h
-
-
-TABLE: Configure
- (echo 'Output of `Configure TABLE'"':"; \
- $(PERL) Configure TABLE) > TABLE
-
-update: errors stacks util/libeay.num util/ssleay.num crypto/objects/obj_dat.h crypto/objects/obj_xref.h apps/openssl-vms.cnf crypto/bn/bn_prime.h TABLE depend
-
-# Build distribution tar-file. As the list of files returned by "find" is
-# pretty long, on several platforms a "too many arguments" error or similar
-# would occur. Therefore the list of files is temporarily stored into a file
-# and read directly, requiring GNU-Tar. Call "make TAR=gtar dist" if the normal
-# tar does not support the --files-from option.
-tar:
- find . -type d -print | xargs chmod 755
- find . -type f -print | xargs chmod a+r
- find . -type f -perm -0100 -print | xargs chmod a+x
- find * \! -path CVS/\* \! -path \*/CVS/\* \! -name CVS \! -name .cvsignore \! -name STATUS \! -name TABLE | sort > ../$(TARFILE).list; \
- $(TAR) $(TARFLAGS) --files-from ../$(TARFILE).list -cvf - | \
- tardy --user_number=0 --user_name=openssl \
- --group_number=0 --group_name=openssl \
- --prefix=openssl-$(VERSION) - |\
- gzip --best >../$(TARFILE).gz; \
- rm -f ../$(TARFILE).list; \
- ls -l ../$(TARFILE).gz
-
-tar-snap:
- @$(TAR) $(TARFLAGS) -cvf - \
- `find * \! -path CVS/\* \! -path \*/CVS/\* \! -name CVS \! -name .cvsignore \! -name STATUS \! -name TABLE \! -name '*.o' \! -name '*.a' \! -name '*.so' \! -name '*.so.*' \! -name 'openssl' \! -name '*test' \! -name '.#*' \! -name '*~' | sort` |\
- tardy --user_number=0 --user_name=openssl \
- --group_number=0 --group_name=openssl \
- --prefix=openssl-$(VERSION) - > ../$(TARFILE);\
- ls -l ../$(TARFILE)
-
-dist:
- $(PERL) Configure dist
- @$(MAKE) dist_pem_h
- @$(MAKE) SDIRS='$(SDIRS)' clean
- @$(MAKE) TAR='$(TAR)' TARFLAGS='$(TARFLAGS)' tar
-
-dist_pem_h:
- (cd crypto/pem; $(MAKE) -e $(BUILDENV) pem.h; $(MAKE) clean)
-
-install: all install_docs install_sw
-
-install_sw:
- @$(PERL) $(TOP)/util/mkdir-p.pl $(INSTALL_PREFIX)$(INSTALLTOP)/bin \
- $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR) \
- $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines \
- $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/pkgconfig \
- $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl \
- $(INSTALL_PREFIX)$(OPENSSLDIR)/misc \
- $(INSTALL_PREFIX)$(OPENSSLDIR)/certs \
- $(INSTALL_PREFIX)$(OPENSSLDIR)/private
- @set -e; headerlist="$(EXHEADER)"; for i in $$headerlist;\
- do \
- (cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i; \
- chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i ); \
- done;
- @set -e; target=install; $(RECURSIVE_BUILD_CMD)
- @set -e; liblist="$(LIBS)"; for i in $$liblist ;\
- do \
- if [ -f "$$i" ]; then \
- ( echo installing $$i; \
- cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/$$i.new; \
- $(RANLIB) $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/$$i.new; \
- chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/$$i.new; \
- mv -f $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/$$i.new $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/$$i ); \
- fi; \
- done;
- @set -e; if [ -n "$(SHARED_LIBS)" ]; then \
- tmp="$(SHARED_LIBS)"; \
- for i in $${tmp:-x}; \
- do \
- if [ -f "$$i" -o -f "$$i.a" ]; then \
- ( echo installing $$i; \
- if [ "$(PLATFORM)" != "Cygwin" ]; then \
- cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/$$i.new; \
- chmod 555 $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/$$i.new; \
- mv -f $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/$$i.new $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/$$i; \
- else \
- c=`echo $$i | sed 's/^lib\(.*\)\.dll\.a/cyg\1-$(SHLIB_VERSION_NUMBER).dll/'`; \
- cp $$c $(INSTALL_PREFIX)$(INSTALLTOP)/bin/$$c.new; \
- chmod 755 $(INSTALL_PREFIX)$(INSTALLTOP)/bin/$$c.new; \
- mv -f $(INSTALL_PREFIX)$(INSTALLTOP)/bin/$$c.new $(INSTALL_PREFIX)$(INSTALLTOP)/bin/$$c; \
- cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/$$i.new; \
- chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/$$i.new; \
- mv -f $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/$$i.new $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/$$i; \
- fi ); \
- if expr $(PLATFORM) : 'mingw' > /dev/null; then \
- ( case $$i in \
- *crypto*) i=libeay32.dll;; \
- *ssl*) i=ssleay32.dll;; \
- esac; \
- echo installing $$i; \
- cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/bin/$$i.new; \
- chmod 755 $(INSTALL_PREFIX)$(INSTALLTOP)/bin/$$i.new; \
- mv -f $(INSTALL_PREFIX)$(INSTALLTOP)/bin/$$i.new $(INSTALL_PREFIX)$(INSTALLTOP)/bin/$$i ); \
- fi; \
- fi; \
- done; \
- ( here="`pwd`"; \
- cd $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR); \
- $(MAKE) -f $$here/Makefile HERE="$$here" link-shared ); \
- if [ "$(INSTALLTOP)" != "/usr" ]; then \
- echo 'OpenSSL shared libraries have been installed in:'; \
- echo ' $(INSTALLTOP)'; \
- echo ''; \
- sed -e '1,/^$$/d' doc/openssl-shared.txt; \
- fi; \
- fi
- cp libcrypto.pc $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/pkgconfig
- chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/pkgconfig/libcrypto.pc
- cp libssl.pc $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/pkgconfig
- chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/pkgconfig/libssl.pc
- cp openssl.pc $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/pkgconfig
- chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/pkgconfig/openssl.pc
-
-install_html_docs:
- here="`pwd`"; \
- for subdir in apps crypto ssl; do \
- mkdir -p $(INSTALL_PREFIX)$(HTMLDIR)/$$subdir; \
- for i in doc/$$subdir/*.pod; do \
- fn=`basename $$i .pod`; \
- echo "installing html/$$fn.$(HTMLSUFFIX)"; \
- cat $$i \
- | sed -r 's/L<([^)]*)(\([0-9]\))?\|([^)]*)(\([0-9]\))?>/L<\1|\3>/g' \
- | pod2html --podroot=doc --htmlroot=.. --podpath=apps:crypto:ssl \
- | sed -r 's/<!DOCTYPE.*//g' \
- > $(INSTALL_PREFIX)$(HTMLDIR)/$$subdir/$$fn.$(HTMLSUFFIX); \
- $(PERL) util/extract-names.pl < $$i | \
- grep -v $$filecase "^$$fn\$$" | \
- (cd $(INSTALL_PREFIX)$(HTMLDIR)/$$subdir; \
- while read n; do \
- PLATFORM=$(PLATFORM) $$here/util/point.sh $$fn.$(HTMLSUFFIX) "$$n".$(HTMLSUFFIX); \
- done); \
- done; \
- done
-
-install_docs:
- @$(PERL) $(TOP)/util/mkdir-p.pl \
- $(INSTALL_PREFIX)$(MANDIR)/man1 \
- $(INSTALL_PREFIX)$(MANDIR)/man3 \
- $(INSTALL_PREFIX)$(MANDIR)/man5 \
- $(INSTALL_PREFIX)$(MANDIR)/man7
- @pod2man="`cd ./util; ./pod2mantest $(PERL)`"; \
- here="`pwd`"; \
- filecase=; \
- if [ "$(PLATFORM)" = "DJGPP" -o "$(PLATFORM)" = "Cygwin" -o "$(PLATFORM)" = "mingw" ]; then \
- filecase=-i; \
- fi; \
- set -e; for i in doc/apps/*.pod; do \
- fn=`basename $$i .pod`; \
- sec=`$(PERL) util/extract-section.pl 1 < $$i`; \
- echo "installing man$$sec/$$fn.$${sec}$(MANSUFFIX)"; \
- (cd `$(PERL) util/dirname.pl $$i`; \
- sh -c "$$pod2man \
- --section=$$sec --center=OpenSSL \
- --release=$(VERSION) `basename $$i`") \
- > $(INSTALL_PREFIX)$(MANDIR)/man$$sec/$$fn.$${sec}$(MANSUFFIX); \
- $(PERL) util/extract-names.pl < $$i | \
- (grep -v $$filecase "^$$fn\$$"; true) | \
- (grep -v "[ ]"; true) | \
- (cd $(INSTALL_PREFIX)$(MANDIR)/man$$sec/; \
- while read n; do \
- PLATFORM=$(PLATFORM) $$here/util/point.sh $$fn.$${sec}$(MANSUFFIX) "$$n".$${sec}$(MANSUFFIX); \
- done); \
- done; \
- set -e; for i in doc/crypto/*.pod doc/ssl/*.pod; do \
- fn=`basename $$i .pod`; \
- sec=`$(PERL) util/extract-section.pl 3 < $$i`; \
- echo "installing man$$sec/$$fn.$${sec}$(MANSUFFIX)"; \
- (cd `$(PERL) util/dirname.pl $$i`; \
- sh -c "$$pod2man \
- --section=$$sec --center=OpenSSL \
- --release=$(VERSION) `basename $$i`") \
- > $(INSTALL_PREFIX)$(MANDIR)/man$$sec/$$fn.$${sec}$(MANSUFFIX); \
- $(PERL) util/extract-names.pl < $$i | \
- (grep -v $$filecase "^$$fn\$$"; true) | \
- (grep -v "[ ]"; true) | \
- (cd $(INSTALL_PREFIX)$(MANDIR)/man$$sec/; \
- while read n; do \
- PLATFORM=$(PLATFORM) $$here/util/point.sh $$fn.$${sec}$(MANSUFFIX) "$$n".$${sec}$(MANSUFFIX); \
- done); \
- done
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/third_party/openssl/openssl/apps/CA.pl b/src/third_party/openssl/openssl/apps/CA.pl
deleted file mode 100644
index a3965ec..0000000
--- a/src/third_party/openssl/openssl/apps/CA.pl
+++ /dev/null
@@ -1,189 +0,0 @@
-#!/usr/bin/perl
-#
-# CA - wrapper around ca to make it easier to use ... basically ca requires
-# some setup stuff to be done before you can use it and this makes
-# things easier between now and when Eric is convinced to fix it :-)
-#
-# CA -newca ... will setup the right stuff
-# CA -newreq[-nodes] ... will generate a certificate request
-# CA -sign ... will sign the generated request and output
-#
-# At the end of that grab newreq.pem and newcert.pem (one has the key
-# and the other the certificate) and cat them together and that is what
-# you want/need ... I'll make even this a little cleaner later.
-#
-#
-# 12-Jan-96 tjh Added more things ... including CA -signcert which
-# converts a certificate to a request and then signs it.
-# 10-Jan-96 eay Fixed a few more bugs and added the SSLEAY_CONFIG
-# environment variable so this can be driven from
-# a script.
-# 25-Jul-96 eay Cleaned up filenames some more.
-# 11-Jun-96 eay Fixed a few filename missmatches.
-# 03-May-96 eay Modified to use 'ssleay cmd' instead of 'cmd'.
-# 18-Apr-96 tjh Original hacking
-#
-# Tim Hudson
-# tjh@cryptsoft.com
-#
-
-# 27-Apr-98 snh Translation into perl, fix existing CA bug.
-#
-#
-# Steve Henson
-# shenson@bigfoot.com
-
-# default openssl.cnf file has setup as per the following
-# demoCA ... where everything is stored
-
-my $openssl;
-if(defined $ENV{OPENSSL}) {
- $openssl = $ENV{OPENSSL};
-} else {
- $openssl = "openssl";
- $ENV{OPENSSL} = $openssl;
-}
-
-$SSLEAY_CONFIG=$ENV{"SSLEAY_CONFIG"};
-$DAYS="-days 365"; # 1 year
-$CADAYS="-days 1095"; # 3 years
-$REQ="$openssl req $SSLEAY_CONFIG";
-$CA="$openssl ca $SSLEAY_CONFIG";
-$VERIFY="$openssl verify";
-$X509="$openssl x509";
-$PKCS12="$openssl pkcs12";
-
-$CATOP="./demoCA";
-$CAKEY="cakey.pem";
-$CAREQ="careq.pem";
-$CACERT="cacert.pem";
-
-$DIRMODE = 0777;
-
-$RET = 0;
-
-foreach (@ARGV) {
- if ( /^(-\?|-h|-help)$/ ) {
- print STDERR "usage: CA -newcert|-newreq|-newreq-nodes|-newca|-sign|-verify\n";
- exit 0;
- } elsif (/^-newcert$/) {
- # create a certificate
- system ("$REQ -new -x509 -keyout newkey.pem -out newcert.pem $DAYS");
- $RET=$?;
- print "Certificate is in newcert.pem, private key is in newkey.pem\n"
- } elsif (/^-newreq$/) {
- # create a certificate request
- system ("$REQ -new -keyout newkey.pem -out newreq.pem $DAYS");
- $RET=$?;
- print "Request is in newreq.pem, private key is in newkey.pem\n";
- } elsif (/^-newreq-nodes$/) {
- # create a certificate request
- system ("$REQ -new -nodes -keyout newkey.pem -out newreq.pem $DAYS");
- $RET=$?;
- print "Request is in newreq.pem, private key is in newkey.pem\n";
- } elsif (/^-newca$/) {
- # if explicitly asked for or it doesn't exist then setup the
- # directory structure that Eric likes to manage things
- $NEW="1";
- if ( "$NEW" || ! -f "${CATOP}/serial" ) {
- # create the directory hierarchy
- mkdir $CATOP, $DIRMODE;
- mkdir "${CATOP}/certs", $DIRMODE;
- mkdir "${CATOP}/crl", $DIRMODE ;
- mkdir "${CATOP}/newcerts", $DIRMODE;
- mkdir "${CATOP}/private", $DIRMODE;
- open OUT, ">${CATOP}/index.txt";
- close OUT;
- open OUT, ">${CATOP}/crlnumber";
- print OUT "01\n";
- close OUT;
- }
- if ( ! -f "${CATOP}/private/$CAKEY" ) {
- print "CA certificate filename (or enter to create)\n";
- $FILE = <STDIN>;
-
- chop $FILE;
-
- # ask user for existing CA certificate
- if ($FILE) {
- cp_pem($FILE,"${CATOP}/private/$CAKEY", "PRIVATE");
- cp_pem($FILE,"${CATOP}/$CACERT", "CERTIFICATE");
- $RET=$?;
- } else {
- print "Making CA certificate ...\n";
- system ("$REQ -new -keyout " .
- "${CATOP}/private/$CAKEY -out ${CATOP}/$CAREQ");
- system ("$CA -create_serial " .
- "-out ${CATOP}/$CACERT $CADAYS -batch " .
- "-keyfile ${CATOP}/private/$CAKEY -selfsign " .
- "-extensions v3_ca " .
- "-infiles ${CATOP}/$CAREQ ");
- $RET=$?;
- }
- }
- } elsif (/^-pkcs12$/) {
- my $cname = $ARGV[1];
- $cname = "My Certificate" unless defined $cname;
- system ("$PKCS12 -in newcert.pem -inkey newkey.pem " .
- "-certfile ${CATOP}/$CACERT -out newcert.p12 " .
- "-export -name \"$cname\"");
- $RET=$?;
- print "PKCS #12 file is in newcert.p12\n";
- exit $RET;
- } elsif (/^-xsign$/) {
- system ("$CA -policy policy_anything -infiles newreq.pem");
- $RET=$?;
- } elsif (/^(-sign|-signreq)$/) {
- system ("$CA -policy policy_anything -out newcert.pem " .
- "-infiles newreq.pem");
- $RET=$?;
- print "Signed certificate is in newcert.pem\n";
- } elsif (/^(-signCA)$/) {
- system ("$CA -policy policy_anything -out newcert.pem " .
- "-extensions v3_ca -infiles newreq.pem");
- $RET=$?;
- print "Signed CA certificate is in newcert.pem\n";
- } elsif (/^-signcert$/) {
- system ("$X509 -x509toreq -in newreq.pem -signkey newreq.pem " .
- "-out tmp.pem");
- system ("$CA -policy policy_anything -out newcert.pem " .
- "-infiles tmp.pem");
- $RET = $?;
- print "Signed certificate is in newcert.pem\n";
- } elsif (/^-verify$/) {
- if (shift) {
- foreach $j (@ARGV) {
- system ("$VERIFY -CAfile $CATOP/$CACERT $j");
- $RET=$? if ($? != 0);
- }
- exit $RET;
- } else {
- system ("$VERIFY -CAfile $CATOP/$CACERT newcert.pem");
- $RET=$?;
- exit 0;
- }
- } else {
- print STDERR "Unknown arg $_\n";
- print STDERR "usage: CA -newcert|-newreq|-newreq-nodes|-newca|-sign|-verify\n";
- exit 1;
- }
-}
-
-exit $RET;
-
-sub cp_pem {
-my ($infile, $outfile, $bound) = @_;
-open IN, $infile;
-open OUT, ">$outfile";
-my $flag = 0;
-while (<IN>) {
- $flag = 1 if (/^-----BEGIN.*$bound/) ;
- print OUT $_ if ($flag);
- if (/^-----END.*$bound/) {
- close IN;
- close OUT;
- return;
- }
-}
-}
-
diff --git a/src/third_party/openssl/openssl/apps/md4.c b/src/third_party/openssl/openssl/apps/md4.c
deleted file mode 120000
index 7f457b2..0000000
--- a/src/third_party/openssl/openssl/apps/md4.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/md4/md4.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/crypto/opensslconf.h b/src/third_party/openssl/openssl/crypto/opensslconf.h
deleted file mode 100644
index f17eaa9..0000000
--- a/src/third_party/openssl/openssl/crypto/opensslconf.h
+++ /dev/null
@@ -1,262 +0,0 @@
-/* opensslconf.h */
-/* WARNING: Generated automatically from opensslconf.h.in by Configure. */
-
-/* OpenSSL was configured with the following options: */
-#ifndef OPENSSL_DOING_MAKEDEPEND
-
-
-#ifndef OPENSSL_NO_CAST
-# define OPENSSL_NO_CAST
-#endif
-#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
-# define OPENSSL_NO_EC_NISTP_64_GCC_128
-#endif
-#ifndef OPENSSL_NO_GMP
-# define OPENSSL_NO_GMP
-#endif
-#ifndef OPENSSL_NO_IDEA
-# define OPENSSL_NO_IDEA
-#endif
-#ifndef OPENSSL_NO_JPAKE
-# define OPENSSL_NO_JPAKE
-#endif
-#ifndef OPENSSL_NO_KRB5
-# define OPENSSL_NO_KRB5
-#endif
-#ifndef OPENSSL_NO_MD2
-# define OPENSSL_NO_MD2
-#endif
-#ifndef OPENSSL_NO_RC5
-# define OPENSSL_NO_RC5
-#endif
-#ifndef OPENSSL_NO_RFC3779
-# define OPENSSL_NO_RFC3779
-#endif
-#ifndef OPENSSL_NO_SCTP
-# define OPENSSL_NO_SCTP
-#endif
-#ifndef OPENSSL_NO_SEED
-# define OPENSSL_NO_SEED
-#endif
-#ifndef OPENSSL_NO_SHA0
-# define OPENSSL_NO_SHA0
-#endif
-#ifndef OPENSSL_NO_STORE
-# define OPENSSL_NO_STORE
-#endif
-#ifndef OPENSSL_NO_WHRLPOOL
-# define OPENSSL_NO_WHRLPOOL
-#endif
-
-#endif /* OPENSSL_DOING_MAKEDEPEND */
-
-#ifndef OPENSSL_THREADS
-# define OPENSSL_THREADS
-#endif
-#ifndef OPENSSL_NO_DYNAMIC_ENGINE
-# define OPENSSL_NO_DYNAMIC_ENGINE
-#endif
-
-/* The OPENSSL_NO_* macros are also defined as NO_* if the application
- asks for it. This is a transient feature that is provided for those
- who haven't had the time to do the appropriate changes in their
- applications. */
-#ifdef OPENSSL_ALGORITHM_DEFINES
-# if defined(OPENSSL_NO_CAST) && !defined(NO_CAST)
-# define NO_CAST
-# endif
-# if defined(OPENSSL_NO_EC_NISTP_64_GCC_128) && !defined(NO_EC_NISTP_64_GCC_128)
-# define NO_EC_NISTP_64_GCC_128
-# endif
-# if defined(OPENSSL_NO_GMP) && !defined(NO_GMP)
-# define NO_GMP
-# endif
-# if defined(OPENSSL_NO_IDEA) && !defined(NO_IDEA)
-# define NO_IDEA
-# endif
-# if defined(OPENSSL_NO_JPAKE) && !defined(NO_JPAKE)
-# define NO_JPAKE
-# endif
-# if defined(OPENSSL_NO_KRB5) && !defined(NO_KRB5)
-# define NO_KRB5
-# endif
-# if defined(OPENSSL_NO_MD2) && !defined(NO_MD2)
-# define NO_MD2
-# endif
-# if defined(OPENSSL_NO_RC5) && !defined(NO_RC5)
-# define NO_RC5
-# endif
-# if defined(OPENSSL_NO_RFC3779) && !defined(NO_RFC3779)
-# define NO_RFC3779
-# endif
-# if defined(OPENSSL_NO_SCTP) && !defined(NO_SCTP)
-# define NO_SCTP
-# endif
-# if defined(OPENSSL_NO_SEED) && !defined(NO_SEED)
-# define NO_SEED
-# endif
-# if defined(OPENSSL_NO_SHA0) && !defined(NO_SHA0)
-# define NO_SHA0
-# endif
-# if defined(OPENSSL_NO_STORE) && !defined(NO_STORE)
-# define NO_STORE
-# endif
-# if defined(OPENSSL_NO_WHRLPOOL) && !defined(NO_WHRLPOOL)
-# define NO_WHRLPOOL
-# endif
-#endif
-
-/* crypto/opensslconf.h.in */
-
-/* Generate 80386 code? */
-#undef I386_ONLY
-
-#if !(defined(VMS) || defined(__VMS)) /* VMS uses logical names instead */
-#if defined(HEADER_CRYPTLIB_H) && !defined(OPENSSLDIR)
-#define ENGINESDIR "/usr/local/ssl/lib/engines"
-#define OPENSSLDIR "/usr/local/ssl"
-#endif
-#endif
-
-#undef OPENSSL_UNISTD
-#define OPENSSL_UNISTD <unistd.h>
-
-#undef OPENSSL_EXPORT_VAR_AS_FUNCTION
-
-#if defined(HEADER_IDEA_H) && !defined(IDEA_INT)
-#define IDEA_INT unsigned int
-#endif
-
-#if defined(HEADER_MD2_H) && !defined(MD2_INT)
-#define MD2_INT unsigned int
-#endif
-
-#if defined(HEADER_RC2_H) && !defined(RC2_INT)
-/* I need to put in a mod for the alpha - eay */
-#define RC2_INT unsigned int
-#endif
-
-#if defined(HEADER_RC4_H)
-#if !defined(RC4_INT)
-/* using int types make the structure larger but make the code faster
- * on most boxes I have tested - up to %20 faster. */
-/*
- * I don't know what does "most" mean, but declaring "int" is a must on:
- * - Intel P6 because partial register stalls are very expensive;
- * - elder Alpha because it lacks byte load/store instructions;
- */
-#define RC4_INT unsigned char
-#endif
-#if !defined(RC4_CHUNK)
-/*
- * This enables code handling data aligned at natural CPU word
- * boundary. See crypto/rc4/rc4_enc.c for further details.
- */
-#define RC4_CHUNK unsigned long
-#endif
-#endif
-
-#if (defined(HEADER_NEW_DES_H) || defined(HEADER_DES_H)) && !defined(DES_LONG)
-/* If this is set to 'unsigned int' on a DEC Alpha, this gives about a
- * %20 speed up (longs are 8 bytes, int's are 4). */
-#ifndef DES_LONG
-#define DES_LONG unsigned int
-#endif
-#endif
-
-#if defined(HEADER_BN_H) && !defined(CONFIG_HEADER_BN_H)
-#define CONFIG_HEADER_BN_H
-#define BN_LLONG
-
-/* Should we define BN_DIV2W here? */
-
-/* Only one for the following should be defined */
-#undef SIXTY_FOUR_BIT_LONG
-#undef SIXTY_FOUR_BIT
-#define THIRTY_TWO_BIT
-#endif
-
-#if defined(HEADER_RC4_LOCL_H) && !defined(CONFIG_HEADER_RC4_LOCL_H)
-#define CONFIG_HEADER_RC4_LOCL_H
-/* if this is defined data[i] is used instead of *data, this is a %20
- * speedup on x86 */
-#undef RC4_INDEX
-#endif
-
-#if defined(HEADER_BF_LOCL_H) && !defined(CONFIG_HEADER_BF_LOCL_H)
-#define CONFIG_HEADER_BF_LOCL_H
-#define BF_PTR
-#endif /* HEADER_BF_LOCL_H */
-
-#if defined(HEADER_DES_LOCL_H) && !defined(CONFIG_HEADER_DES_LOCL_H)
-#define CONFIG_HEADER_DES_LOCL_H
-#ifndef DES_DEFAULT_OPTIONS
-/* the following is tweaked from a config script, that is why it is a
- * protected undef/define */
-#ifndef DES_PTR
-#undef DES_PTR
-#endif
-
-/* This helps C compiler generate the correct code for multiple functional
- * units. It reduces register dependancies at the expense of 2 more
- * registers */
-#ifndef DES_RISC1
-#undef DES_RISC1
-#endif
-
-#ifndef DES_RISC2
-#undef DES_RISC2
-#endif
-
-#if defined(DES_RISC1) && defined(DES_RISC2)
-YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!!
-#endif
-
-/* Unroll the inner loop, this sometimes helps, sometimes hinders.
- * Very mucy CPU dependant */
-#ifndef DES_UNROLL
-#define DES_UNROLL
-#endif
-
-/* These default values were supplied by
- * Peter Gutman <pgut001@cs.auckland.ac.nz>
- * They are only used if nothing else has been defined */
-#if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL)
-/* Special defines which change the way the code is built depending on the
- CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find
- even newer MIPS CPU's, but at the moment one size fits all for
- optimization options. Older Sparc's work better with only UNROLL, but
- there's no way to tell at compile time what it is you're running on */
-
-#if defined( sun ) /* Newer Sparc's */
-# define DES_PTR
-# define DES_RISC1
-# define DES_UNROLL
-#elif defined( __ultrix ) /* Older MIPS */
-# define DES_PTR
-# define DES_RISC2
-# define DES_UNROLL
-#elif defined( __osf1__ ) /* Alpha */
-# define DES_PTR
-# define DES_RISC2
-#elif defined ( _AIX ) /* RS6000 */
- /* Unknown */
-#elif defined( __hpux ) /* HP-PA */
- /* Unknown */
-#elif defined( __aux ) /* 68K */
- /* Unknown */
-#elif defined( __dgux ) /* 88K (but P6 in latest boxes) */
-# define DES_UNROLL
-#elif defined( __sgi ) /* Newer MIPS */
-# define DES_PTR
-# define DES_RISC2
-# define DES_UNROLL
-#elif defined(i386) || defined(__i386__) /* x86 boxes, should be gcc */
-# define DES_PTR
-# define DES_RISC1
-# define DES_UNROLL
-#endif /* Systems-specific speed defines */
-#endif
-
-#endif /* DES_DEFAULT_OPTIONS */
-#endif /* HEADER_DES_LOCL_H */
diff --git a/src/third_party/openssl/openssl/include/openssl/aes.h b/src/third_party/openssl/openssl/include/openssl/aes.h
deleted file mode 100644
index f646d41..0000000
--- a/src/third_party/openssl/openssl/include/openssl/aes.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/aes/aes.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/asn1.h b/src/third_party/openssl/openssl/include/openssl/asn1.h
deleted file mode 100644
index 5432ed8..0000000
--- a/src/third_party/openssl/openssl/include/openssl/asn1.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/asn1/asn1.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/asn1_mac.h b/src/third_party/openssl/openssl/include/openssl/asn1_mac.h
deleted file mode 100644
index 214787c..0000000
--- a/src/third_party/openssl/openssl/include/openssl/asn1_mac.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/asn1/asn1_mac.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/asn1t.h b/src/third_party/openssl/openssl/include/openssl/asn1t.h
deleted file mode 100644
index 4de87a9..0000000
--- a/src/third_party/openssl/openssl/include/openssl/asn1t.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/asn1/asn1t.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/bio.h b/src/third_party/openssl/openssl/include/openssl/bio.h
deleted file mode 100644
index 34f8a2d..0000000
--- a/src/third_party/openssl/openssl/include/openssl/bio.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/bio/bio.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/blowfish.h b/src/third_party/openssl/openssl/include/openssl/blowfish.h
deleted file mode 100644
index 8d515fe..0000000
--- a/src/third_party/openssl/openssl/include/openssl/blowfish.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/bf/blowfish.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/bn.h b/src/third_party/openssl/openssl/include/openssl/bn.h
deleted file mode 100644
index f47d65a..0000000
--- a/src/third_party/openssl/openssl/include/openssl/bn.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/bn/bn.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/buffer.h b/src/third_party/openssl/openssl/include/openssl/buffer.h
deleted file mode 100644
index 1d2c2a2..0000000
--- a/src/third_party/openssl/openssl/include/openssl/buffer.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/buffer/buffer.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/camellia.h b/src/third_party/openssl/openssl/include/openssl/camellia.h
deleted file mode 100644
index 5a0a141..0000000
--- a/src/third_party/openssl/openssl/include/openssl/camellia.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/camellia/camellia.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/cast.h b/src/third_party/openssl/openssl/include/openssl/cast.h
deleted file mode 100644
index 12cf92c..0000000
--- a/src/third_party/openssl/openssl/include/openssl/cast.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/cast/cast.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/cmac.h b/src/third_party/openssl/openssl/include/openssl/cmac.h
deleted file mode 100644
index a7579ae..0000000
--- a/src/third_party/openssl/openssl/include/openssl/cmac.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/cmac/cmac.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/cms.h b/src/third_party/openssl/openssl/include/openssl/cms.h
deleted file mode 100644
index 8687c7f..0000000
--- a/src/third_party/openssl/openssl/include/openssl/cms.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/cms/cms.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/comp.h b/src/third_party/openssl/openssl/include/openssl/comp.h
deleted file mode 100644
index d14e36c..0000000
--- a/src/third_party/openssl/openssl/include/openssl/comp.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/comp/comp.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/conf.h b/src/third_party/openssl/openssl/include/openssl/conf.h
deleted file mode 100644
index 3882c82..0000000
--- a/src/third_party/openssl/openssl/include/openssl/conf.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/conf/conf.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/conf_api.h b/src/third_party/openssl/openssl/include/openssl/conf_api.h
deleted file mode 100644
index 0393357..0000000
--- a/src/third_party/openssl/openssl/include/openssl/conf_api.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/conf/conf_api.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/crypto.h b/src/third_party/openssl/openssl/include/openssl/crypto.h
deleted file mode 100644
index 7e3d91e..0000000
--- a/src/third_party/openssl/openssl/include/openssl/crypto.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/crypto.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/des.h b/src/third_party/openssl/openssl/include/openssl/des.h
deleted file mode 100644
index 1d6631e..0000000
--- a/src/third_party/openssl/openssl/include/openssl/des.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/des/des.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/des_old.h b/src/third_party/openssl/openssl/include/openssl/des_old.h
deleted file mode 100644
index e582873..0000000
--- a/src/third_party/openssl/openssl/include/openssl/des_old.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/des/des_old.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/dh.h b/src/third_party/openssl/openssl/include/openssl/dh.h
deleted file mode 100644
index f70a767..0000000
--- a/src/third_party/openssl/openssl/include/openssl/dh.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/dh/dh.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/dsa.h b/src/third_party/openssl/openssl/include/openssl/dsa.h
deleted file mode 100644
index 0365acf..0000000
--- a/src/third_party/openssl/openssl/include/openssl/dsa.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/dsa/dsa.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/dso.h b/src/third_party/openssl/openssl/include/openssl/dso.h
deleted file mode 100644
index f3c8de2..0000000
--- a/src/third_party/openssl/openssl/include/openssl/dso.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/dso/dso.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/dtls1.h b/src/third_party/openssl/openssl/include/openssl/dtls1.h
deleted file mode 100644
index ac8ab57..0000000
--- a/src/third_party/openssl/openssl/include/openssl/dtls1.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../ssl/dtls1.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/e_os2.h b/src/third_party/openssl/openssl/include/openssl/e_os2.h
deleted file mode 100644
index ab3f1ee..0000000
--- a/src/third_party/openssl/openssl/include/openssl/e_os2.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../e_os2.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ebcdic.h b/src/third_party/openssl/openssl/include/openssl/ebcdic.h
deleted file mode 100644
index 6dedc70..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ebcdic.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/ebcdic.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ec.h b/src/third_party/openssl/openssl/include/openssl/ec.h
deleted file mode 100644
index 7d20614..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ec.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/ec/ec.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ecdh.h b/src/third_party/openssl/openssl/include/openssl/ecdh.h
deleted file mode 100644
index ad6e3dc..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ecdh.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/ecdh/ecdh.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ecdsa.h b/src/third_party/openssl/openssl/include/openssl/ecdsa.h
deleted file mode 100644
index da45123..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ecdsa.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/ecdsa/ecdsa.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/engine.h b/src/third_party/openssl/openssl/include/openssl/engine.h
deleted file mode 100644
index 2dceaac..0000000
--- a/src/third_party/openssl/openssl/include/openssl/engine.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/engine/engine.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/err.h b/src/third_party/openssl/openssl/include/openssl/err.h
deleted file mode 100644
index caf89a9..0000000
--- a/src/third_party/openssl/openssl/include/openssl/err.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/err/err.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/evp.h b/src/third_party/openssl/openssl/include/openssl/evp.h
deleted file mode 100644
index dd7bcda..0000000
--- a/src/third_party/openssl/openssl/include/openssl/evp.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/evp/evp.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/hmac.h b/src/third_party/openssl/openssl/include/openssl/hmac.h
deleted file mode 100644
index 202128b..0000000
--- a/src/third_party/openssl/openssl/include/openssl/hmac.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/hmac/hmac.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/idea.h b/src/third_party/openssl/openssl/include/openssl/idea.h
deleted file mode 100644
index bdf697d..0000000
--- a/src/third_party/openssl/openssl/include/openssl/idea.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/idea/idea.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/krb5_asn.h b/src/third_party/openssl/openssl/include/openssl/krb5_asn.h
deleted file mode 100644
index 0d3feea..0000000
--- a/src/third_party/openssl/openssl/include/openssl/krb5_asn.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/krb5/krb5_asn.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/kssl.h b/src/third_party/openssl/openssl/include/openssl/kssl.h
deleted file mode 100644
index 719634a..0000000
--- a/src/third_party/openssl/openssl/include/openssl/kssl.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../ssl/kssl.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/lhash.h b/src/third_party/openssl/openssl/include/openssl/lhash.h
deleted file mode 100644
index 2d3db87..0000000
--- a/src/third_party/openssl/openssl/include/openssl/lhash.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/lhash/lhash.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/md2.h b/src/third_party/openssl/openssl/include/openssl/md2.h
deleted file mode 100644
index 4c3398c..0000000
--- a/src/third_party/openssl/openssl/include/openssl/md2.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/md2/md2.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/md4.h b/src/third_party/openssl/openssl/include/openssl/md4.h
deleted file mode 100644
index 611806e..0000000
--- a/src/third_party/openssl/openssl/include/openssl/md4.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/md4/md4.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/md5.h b/src/third_party/openssl/openssl/include/openssl/md5.h
deleted file mode 100644
index aa8cd0b..0000000
--- a/src/third_party/openssl/openssl/include/openssl/md5.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/md5/md5.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/mdc2.h b/src/third_party/openssl/openssl/include/openssl/mdc2.h
deleted file mode 100644
index ac284a1..0000000
--- a/src/third_party/openssl/openssl/include/openssl/mdc2.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/mdc2/mdc2.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/modes.h b/src/third_party/openssl/openssl/include/openssl/modes.h
deleted file mode 100644
index f57fcfe..0000000
--- a/src/third_party/openssl/openssl/include/openssl/modes.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/modes/modes.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/obj_mac.h b/src/third_party/openssl/openssl/include/openssl/obj_mac.h
deleted file mode 100644
index 3890fa9..0000000
--- a/src/third_party/openssl/openssl/include/openssl/obj_mac.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/objects/obj_mac.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/objects.h b/src/third_party/openssl/openssl/include/openssl/objects.h
deleted file mode 100644
index 5365a04..0000000
--- a/src/third_party/openssl/openssl/include/openssl/objects.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/objects/objects.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ocsp.h b/src/third_party/openssl/openssl/include/openssl/ocsp.h
deleted file mode 100644
index 50e2885..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ocsp.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/ocsp/ocsp.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/opensslv.h b/src/third_party/openssl/openssl/include/openssl/opensslv.h
deleted file mode 100644
index c39a0c3..0000000
--- a/src/third_party/openssl/openssl/include/openssl/opensslv.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/opensslv.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ossl_typ.h b/src/third_party/openssl/openssl/include/openssl/ossl_typ.h
deleted file mode 100644
index ddd7e58..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ossl_typ.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/ossl_typ.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/pem.h b/src/third_party/openssl/openssl/include/openssl/pem.h
deleted file mode 100644
index 5bcc5c5..0000000
--- a/src/third_party/openssl/openssl/include/openssl/pem.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/pem/pem.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/pem2.h b/src/third_party/openssl/openssl/include/openssl/pem2.h
deleted file mode 100644
index bcd3acf..0000000
--- a/src/third_party/openssl/openssl/include/openssl/pem2.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/pem/pem2.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/pkcs12.h b/src/third_party/openssl/openssl/include/openssl/pkcs12.h
deleted file mode 100644
index 0b5fbbf..0000000
--- a/src/third_party/openssl/openssl/include/openssl/pkcs12.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/pkcs12/pkcs12.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/pkcs7.h b/src/third_party/openssl/openssl/include/openssl/pkcs7.h
deleted file mode 100644
index 2e19d7c..0000000
--- a/src/third_party/openssl/openssl/include/openssl/pkcs7.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/pkcs7/pkcs7.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/pqueue.h b/src/third_party/openssl/openssl/include/openssl/pqueue.h
deleted file mode 100644
index 9681ff5..0000000
--- a/src/third_party/openssl/openssl/include/openssl/pqueue.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/pqueue/pqueue.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/rand.h b/src/third_party/openssl/openssl/include/openssl/rand.h
deleted file mode 100644
index 9d1521b..0000000
--- a/src/third_party/openssl/openssl/include/openssl/rand.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/rand/rand.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/rc2.h b/src/third_party/openssl/openssl/include/openssl/rc2.h
deleted file mode 100644
index f2f2bd1..0000000
--- a/src/third_party/openssl/openssl/include/openssl/rc2.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/rc2/rc2.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/rc4.h b/src/third_party/openssl/openssl/include/openssl/rc4.h
deleted file mode 100644
index 306de2f..0000000
--- a/src/third_party/openssl/openssl/include/openssl/rc4.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/rc4/rc4.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ripemd.h b/src/third_party/openssl/openssl/include/openssl/ripemd.h
deleted file mode 100644
index 11351fc..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ripemd.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/ripemd/ripemd.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/rsa.h b/src/third_party/openssl/openssl/include/openssl/rsa.h
deleted file mode 100644
index 975e5d3..0000000
--- a/src/third_party/openssl/openssl/include/openssl/rsa.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/rsa/rsa.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/safestack.h b/src/third_party/openssl/openssl/include/openssl/safestack.h
deleted file mode 100644
index 8a282b8..0000000
--- a/src/third_party/openssl/openssl/include/openssl/safestack.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/stack/safestack.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/seed.h b/src/third_party/openssl/openssl/include/openssl/seed.h
deleted file mode 100644
index bbbf596..0000000
--- a/src/third_party/openssl/openssl/include/openssl/seed.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/seed/seed.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/sha.h b/src/third_party/openssl/openssl/include/openssl/sha.h
deleted file mode 100644
index ab9d94c..0000000
--- a/src/third_party/openssl/openssl/include/openssl/sha.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/sha/sha.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/srp.h b/src/third_party/openssl/openssl/include/openssl/srp.h
deleted file mode 100644
index 8217476..0000000
--- a/src/third_party/openssl/openssl/include/openssl/srp.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/srp/srp.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/srtp.h b/src/third_party/openssl/openssl/include/openssl/srtp.h
deleted file mode 100644
index e185494..0000000
--- a/src/third_party/openssl/openssl/include/openssl/srtp.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../ssl/srtp.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ssl.h b/src/third_party/openssl/openssl/include/openssl/ssl.h
deleted file mode 100644
index 0b0589c..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ssl.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../ssl/ssl.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ssl2.h b/src/third_party/openssl/openssl/include/openssl/ssl2.h
deleted file mode 100644
index 11b2205..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ssl2.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../ssl/ssl2.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ssl23.h b/src/third_party/openssl/openssl/include/openssl/ssl23.h
deleted file mode 100644
index fe4dae6..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ssl23.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../ssl/ssl23.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ssl3.h b/src/third_party/openssl/openssl/include/openssl/ssl3.h
deleted file mode 100644
index 0fb66a6..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ssl3.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../ssl/ssl3.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/stack.h b/src/third_party/openssl/openssl/include/openssl/stack.h
deleted file mode 100644
index 295968c..0000000
--- a/src/third_party/openssl/openssl/include/openssl/stack.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/stack/stack.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/store.h b/src/third_party/openssl/openssl/include/openssl/store.h
deleted file mode 100644
index 84dc39f..0000000
--- a/src/third_party/openssl/openssl/include/openssl/store.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/store/store.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/symhacks.h b/src/third_party/openssl/openssl/include/openssl/symhacks.h
deleted file mode 100644
index f946f4f..0000000
--- a/src/third_party/openssl/openssl/include/openssl/symhacks.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/symhacks.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/tls1.h b/src/third_party/openssl/openssl/include/openssl/tls1.h
deleted file mode 100644
index c43a70f..0000000
--- a/src/third_party/openssl/openssl/include/openssl/tls1.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../ssl/tls1.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ts.h b/src/third_party/openssl/openssl/include/openssl/ts.h
deleted file mode 100644
index fe8a2cb..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ts.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/ts/ts.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/txt_db.h b/src/third_party/openssl/openssl/include/openssl/txt_db.h
deleted file mode 100644
index 167621b..0000000
--- a/src/third_party/openssl/openssl/include/openssl/txt_db.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/txt_db/txt_db.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ui.h b/src/third_party/openssl/openssl/include/openssl/ui.h
deleted file mode 100644
index 43dd3ae..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ui.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/ui/ui.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/ui_compat.h b/src/third_party/openssl/openssl/include/openssl/ui_compat.h
deleted file mode 100644
index c83f160..0000000
--- a/src/third_party/openssl/openssl/include/openssl/ui_compat.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/ui/ui_compat.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/whrlpool.h b/src/third_party/openssl/openssl/include/openssl/whrlpool.h
deleted file mode 100644
index e2424fa..0000000
--- a/src/third_party/openssl/openssl/include/openssl/whrlpool.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/whrlpool/whrlpool.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/x509.h b/src/third_party/openssl/openssl/include/openssl/x509.h
deleted file mode 100644
index a4651a2..0000000
--- a/src/third_party/openssl/openssl/include/openssl/x509.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/x509/x509.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/x509_vfy.h b/src/third_party/openssl/openssl/include/openssl/x509_vfy.h
deleted file mode 100644
index b897aa0..0000000
--- a/src/third_party/openssl/openssl/include/openssl/x509_vfy.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/x509/x509_vfy.h"
diff --git a/src/third_party/openssl/openssl/include/openssl/x509v3.h b/src/third_party/openssl/openssl/include/openssl/x509v3.h
deleted file mode 100644
index 363795e..0000000
--- a/src/third_party/openssl/openssl/include/openssl/x509v3.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../crypto/x509v3/x509v3.h"
diff --git a/src/third_party/openssl/openssl/test/bftest.c b/src/third_party/openssl/openssl/test/bftest.c
deleted file mode 120000
index 78b1749..0000000
--- a/src/third_party/openssl/openssl/test/bftest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/bf/bftest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/bntest.c b/src/third_party/openssl/openssl/test/bntest.c
deleted file mode 120000
index 03f54a2..0000000
--- a/src/third_party/openssl/openssl/test/bntest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/bn/bntest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/casttest.c b/src/third_party/openssl/openssl/test/casttest.c
deleted file mode 120000
index ac7ede8..0000000
--- a/src/third_party/openssl/openssl/test/casttest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/cast/casttest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/destest.c b/src/third_party/openssl/openssl/test/destest.c
deleted file mode 120000
index 5988c73..0000000
--- a/src/third_party/openssl/openssl/test/destest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/des/destest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/dhtest.c b/src/third_party/openssl/openssl/test/dhtest.c
deleted file mode 120000
index 9a67f91..0000000
--- a/src/third_party/openssl/openssl/test/dhtest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/dh/dhtest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/dsatest.c b/src/third_party/openssl/openssl/test/dsatest.c
deleted file mode 120000
index 16a1b5a..0000000
--- a/src/third_party/openssl/openssl/test/dsatest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/dsa/dsatest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/ecdhtest.c b/src/third_party/openssl/openssl/test/ecdhtest.c
deleted file mode 120000
index 206d986..0000000
--- a/src/third_party/openssl/openssl/test/ecdhtest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/ecdh/ecdhtest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/ecdsatest.c b/src/third_party/openssl/openssl/test/ecdsatest.c
deleted file mode 120000
index 441082b..0000000
--- a/src/third_party/openssl/openssl/test/ecdsatest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/ecdsa/ecdsatest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/ectest.c b/src/third_party/openssl/openssl/test/ectest.c
deleted file mode 120000
index df1831f..0000000
--- a/src/third_party/openssl/openssl/test/ectest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/ec/ectest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/enginetest.c b/src/third_party/openssl/openssl/test/enginetest.c
deleted file mode 120000
index 5c74a6f..0000000
--- a/src/third_party/openssl/openssl/test/enginetest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/engine/enginetest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/evp_test.c b/src/third_party/openssl/openssl/test/evp_test.c
deleted file mode 120000
index 0741628..0000000
--- a/src/third_party/openssl/openssl/test/evp_test.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/evp/evp_test.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/evptests.txt b/src/third_party/openssl/openssl/test/evptests.txt
deleted file mode 100644
index c273707..0000000
--- a/src/third_party/openssl/openssl/test/evptests.txt
+++ /dev/null
@@ -1,334 +0,0 @@
-#cipher:key:iv:plaintext:ciphertext:0/1(decrypt/encrypt)
-#digest:::input:output
-
-# SHA(1) tests (from shatest.c)
-SHA1:::616263:a9993e364706816aba3e25717850c26c9cd0d89d
-
-# MD5 tests (from md5test.c)
-MD5::::d41d8cd98f00b204e9800998ecf8427e
-MD5:::61:0cc175b9c0f1b6a831c399e269772661
-MD5:::616263:900150983cd24fb0d6963f7d28e17f72
-MD5:::6d65737361676520646967657374:f96b697d7cb7938d525a2f31aaf161d0
-MD5:::6162636465666768696a6b6c6d6e6f707172737475767778797a:c3fcd3d76192e4007dfb496cca67e13b
-MD5:::4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a30313233343536373839:d174ab98d277d9f5a5611c2c9f419d9f
-MD5:::3132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930:57edf4a22be3c955ac49da2e2107b67a
-
-# AES 128 ECB tests (from FIPS-197 test vectors, encrypt)
-
-AES-128-ECB:000102030405060708090A0B0C0D0E0F::00112233445566778899AABBCCDDEEFF:69C4E0D86A7B0430D8CDB78070B4C55A:1
-
-# AES 192 ECB tests (from FIPS-197 test vectors, encrypt)
-
-AES-192-ECB:000102030405060708090A0B0C0D0E0F1011121314151617::00112233445566778899AABBCCDDEEFF:DDA97CA4864CDFE06EAF70A0EC0D7191:1
-
-# AES 256 ECB tests (from FIPS-197 test vectors, encrypt)
-
-AES-256-ECB:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F::00112233445566778899AABBCCDDEEFF:8EA2B7CA516745BFEAFC49904B496089:1
-
-# AES 128 ECB tests (from NIST test vectors, encrypt)
-
-#AES-128-ECB:00000000000000000000000000000000::00000000000000000000000000000000:C34C052CC0DA8D73451AFE5F03BE297F:1
-
-# AES 128 ECB tests (from NIST test vectors, decrypt)
-
-#AES-128-ECB:00000000000000000000000000000000::44416AC2D1F53C583303917E6BE9EBE0:00000000000000000000000000000000:0
-
-# AES 192 ECB tests (from NIST test vectors, decrypt)
-
-#AES-192-ECB:000000000000000000000000000000000000000000000000::48E31E9E256718F29229319C19F15BA4:00000000000000000000000000000000:0
-
-# AES 256 ECB tests (from NIST test vectors, decrypt)
-
-#AES-256-ECB:0000000000000000000000000000000000000000000000000000000000000000::058CCFFDBBCB382D1F6F56585D8A4ADE:00000000000000000000000000000000:0
-
-# AES 128 CBC tests (from NIST test vectors, encrypt)
-
-#AES-128-CBC:00000000000000000000000000000000:00000000000000000000000000000000:00000000000000000000000000000000:8A05FC5E095AF4848A08D328D3688E3D:1
-
-# AES 192 CBC tests (from NIST test vectors, encrypt)
-
-#AES-192-CBC:000000000000000000000000000000000000000000000000:00000000000000000000000000000000:00000000000000000000000000000000:7BD966D53AD8C1BB85D2ADFAE87BB104:1
-
-# AES 256 CBC tests (from NIST test vectors, encrypt)
-
-#AES-256-CBC:0000000000000000000000000000000000000000000000000000000000000000:00000000000000000000000000000000:00000000000000000000000000000000:FE3C53653E2F45B56FCD88B2CC898FF0:1
-
-# AES 128 CBC tests (from NIST test vectors, decrypt)
-
-#AES-128-CBC:00000000000000000000000000000000:00000000000000000000000000000000:FACA37E0B0C85373DF706E73F7C9AF86:00000000000000000000000000000000:0
-
-# AES tests from NIST document SP800-38A
-# For all ECB encrypts and decrypts, the transformed sequence is
-# AES-bits-ECB:key::plaintext:ciphertext:encdec
-# ECB-AES128.Encrypt and ECB-AES128.Decrypt
-AES-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::6BC1BEE22E409F96E93D7E117393172A:3AD77BB40D7A3660A89ECAF32466EF97
-AES-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::AE2D8A571E03AC9C9EB76FAC45AF8E51:F5D3D58503B9699DE785895A96FDBAAF
-AES-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::30C81C46A35CE411E5FBC1191A0A52EF:43B1CD7F598ECE23881B00E3ED030688
-AES-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::F69F2445DF4F9B17AD2B417BE66C3710:7B0C785E27E8AD3F8223207104725DD4
-# ECB-AES192.Encrypt and ECB-AES192.Decrypt
-AES-192-ECB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B::6BC1BEE22E409F96E93D7E117393172A:BD334F1D6E45F25FF712A214571FA5CC
-AES-192-ECB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B::AE2D8A571E03AC9C9EB76FAC45AF8E51:974104846D0AD3AD7734ECB3ECEE4EEF
-AES-192-ECB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B::30C81C46A35CE411E5FBC1191A0A52EF:EF7AFD2270E2E60ADCE0BA2FACE6444E
-AES-192-ECB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B::F69F2445DF4F9B17AD2B417BE66C3710:9A4B41BA738D6C72FB16691603C18E0E
-# ECB-AES256.Encrypt and ECB-AES256.Decrypt
-AES-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::6BC1BEE22E409F96E93D7E117393172A:F3EED1BDB5D2A03C064B5A7E3DB181F8
-AES-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::AE2D8A571E03AC9C9EB76FAC45AF8E51:591CCB10D410ED26DC5BA74A31362870
-AES-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::30C81C46A35CE411E5FBC1191A0A52EF:B6ED21B99CA6F4F9F153E7B1BEAFED1D
-AES-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::F69F2445DF4F9B17AD2B417BE66C3710:23304B7A39F9F3FF067D8D8F9E24ECC7
-# For all CBC encrypts and decrypts, the transformed sequence is
-# AES-bits-CBC:key:IV/ciphertext':plaintext:ciphertext:encdec
-# CBC-AES128.Encrypt and CBC-AES128.Decrypt
-AES-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:7649ABAC8119B246CEE98E9B12E9197D
-AES-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:7649ABAC8119B246CEE98E9B12E9197D:AE2D8A571E03AC9C9EB76FAC45AF8E51:5086CB9B507219EE95DB113A917678B2
-AES-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:5086CB9B507219EE95DB113A917678B2:30C81C46A35CE411E5FBC1191A0A52EF:73BED6B8E3C1743B7116E69E22229516
-AES-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:73BED6B8E3C1743B7116E69E22229516:F69F2445DF4F9B17AD2B417BE66C3710:3FF1CAA1681FAC09120ECA307586E1A7
-# CBC-AES192.Encrypt and CBC-AES192.Decrypt
-AES-192-CBC:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:4F021DB243BC633D7178183A9FA071E8
-AES-192-CBC:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:4F021DB243BC633D7178183A9FA071E8:AE2D8A571E03AC9C9EB76FAC45AF8E51:B4D9ADA9AD7DEDF4E5E738763F69145A
-AES-192-CBC:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:B4D9ADA9AD7DEDF4E5E738763F69145A:30C81C46A35CE411E5FBC1191A0A52EF:571B242012FB7AE07FA9BAAC3DF102E0
-AES-192-CBC:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:571B242012FB7AE07FA9BAAC3DF102E0:F69F2445DF4F9B17AD2B417BE66C3710:08B0E27988598881D920A9E64F5615CD
-# CBC-AES256.Encrypt and CBC-AES256.Decrypt
-AES-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:F58C4C04D6E5F1BA779EABFB5F7BFBD6
-AES-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:F58C4C04D6E5F1BA779EABFB5F7BFBD6:AE2D8A571E03AC9C9EB76FAC45AF8E51:9CFC4E967EDB808D679F777BC6702C7D
-AES-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:9CFC4E967EDB808D679F777BC6702C7D:30C81C46A35CE411E5FBC1191A0A52EF:39F23369A9D9BACFA530E26304231461
-AES-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:39F23369A9D9BACFA530E26304231461:F69F2445DF4F9B17AD2B417BE66C3710:B2EB05E2C39BE9FCDA6C19078C6A9D1B
-# We don't support CFB{1,8}-AESxxx.{En,De}crypt
-# For all CFB128 encrypts and decrypts, the transformed sequence is
-# AES-bits-CFB:key:IV/ciphertext':plaintext:ciphertext:encdec
-# CFB128-AES128.Encrypt
-AES-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:3B3FD92EB72DAD20333449F8E83CFB4A:1
-AES-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:3B3FD92EB72DAD20333449F8E83CFB4A:AE2D8A571E03AC9C9EB76FAC45AF8E51:C8A64537A0B3A93FCDE3CDAD9F1CE58B:1
-AES-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:C8A64537A0B3A93FCDE3CDAD9F1CE58B:30C81C46A35CE411E5FBC1191A0A52EF:26751F67A3CBB140B1808CF187A4F4DF:1
-AES-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:26751F67A3CBB140B1808CF187A4F4DF:F69F2445DF4F9B17AD2B417BE66C3710:C04B05357C5D1C0EEAC4C66F9FF7F2E6:1
-# CFB128-AES128.Decrypt
-AES-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:3B3FD92EB72DAD20333449F8E83CFB4A:0
-AES-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:3B3FD92EB72DAD20333449F8E83CFB4A:AE2D8A571E03AC9C9EB76FAC45AF8E51:C8A64537A0B3A93FCDE3CDAD9F1CE58B:0
-AES-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:C8A64537A0B3A93FCDE3CDAD9F1CE58B:30C81C46A35CE411E5FBC1191A0A52EF:26751F67A3CBB140B1808CF187A4F4DF:0
-AES-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:26751F67A3CBB140B1808CF187A4F4DF:F69F2445DF4F9B17AD2B417BE66C3710:C04B05357C5D1C0EEAC4C66F9FF7F2E6:0
-# CFB128-AES192.Encrypt
-AES-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:CDC80D6FDDF18CAB34C25909C99A4174:1
-AES-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:CDC80D6FDDF18CAB34C25909C99A4174:AE2D8A571E03AC9C9EB76FAC45AF8E51:67CE7F7F81173621961A2B70171D3D7A:1
-AES-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:67CE7F7F81173621961A2B70171D3D7A:30C81C46A35CE411E5FBC1191A0A52EF:2E1E8A1DD59B88B1C8E60FED1EFAC4C9:1
-AES-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:2E1E8A1DD59B88B1C8E60FED1EFAC4C9:F69F2445DF4F9B17AD2B417BE66C3710:C05F9F9CA9834FA042AE8FBA584B09FF:1
-# CFB128-AES192.Decrypt
-AES-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:CDC80D6FDDF18CAB34C25909C99A4174:0
-AES-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:CDC80D6FDDF18CAB34C25909C99A4174:AE2D8A571E03AC9C9EB76FAC45AF8E51:67CE7F7F81173621961A2B70171D3D7A:0
-AES-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:67CE7F7F81173621961A2B70171D3D7A:30C81C46A35CE411E5FBC1191A0A52EF:2E1E8A1DD59B88B1C8E60FED1EFAC4C9:0
-AES-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:2E1E8A1DD59B88B1C8E60FED1EFAC4C9:F69F2445DF4F9B17AD2B417BE66C3710:C05F9F9CA9834FA042AE8FBA584B09FF:0
-# CFB128-AES256.Encrypt
-AES-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:DC7E84BFDA79164B7ECD8486985D3860:1
-AES-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:DC7E84BFDA79164B7ECD8486985D3860:AE2D8A571E03AC9C9EB76FAC45AF8E51:39FFED143B28B1C832113C6331E5407B:1
-AES-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:39FFED143B28B1C832113C6331E5407B:30C81C46A35CE411E5FBC1191A0A52EF:DF10132415E54B92A13ED0A8267AE2F9:1
-AES-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:DF10132415E54B92A13ED0A8267AE2F9:F69F2445DF4F9B17AD2B417BE66C3710:75A385741AB9CEF82031623D55B1E471:1
-# CFB128-AES256.Decrypt
-AES-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:DC7E84BFDA79164B7ECD8486985D3860:0
-AES-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:DC7E84BFDA79164B7ECD8486985D3860:AE2D8A571E03AC9C9EB76FAC45AF8E51:39FFED143B28B1C832113C6331E5407B:0
-AES-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:39FFED143B28B1C832113C6331E5407B:30C81C46A35CE411E5FBC1191A0A52EF:DF10132415E54B92A13ED0A8267AE2F9:0
-AES-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:DF10132415E54B92A13ED0A8267AE2F9:F69F2445DF4F9B17AD2B417BE66C3710:75A385741AB9CEF82031623D55B1E471:0
-# For all OFB encrypts and decrypts, the transformed sequence is
-# AES-bits-CFB:key:IV/output':plaintext:ciphertext:encdec
-# OFB-AES128.Encrypt
-AES-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:3B3FD92EB72DAD20333449F8E83CFB4A:1
-AES-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:50FE67CC996D32B6DA0937E99BAFEC60:AE2D8A571E03AC9C9EB76FAC45AF8E51:7789508D16918F03F53C52DAC54ED825:1
-AES-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:D9A4DADA0892239F6B8B3D7680E15674:30C81C46A35CE411E5FBC1191A0A52EF:9740051E9C5FECF64344F7A82260EDCC:1
-AES-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:A78819583F0308E7A6BF36B1386ABF23:F69F2445DF4F9B17AD2B417BE66C3710:304C6528F659C77866A510D9C1D6AE5E:1
-# OFB-AES128.Decrypt
-AES-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:3B3FD92EB72DAD20333449F8E83CFB4A:0
-AES-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:50FE67CC996D32B6DA0937E99BAFEC60:AE2D8A571E03AC9C9EB76FAC45AF8E51:7789508D16918F03F53C52DAC54ED825:0
-AES-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:D9A4DADA0892239F6B8B3D7680E15674:30C81C46A35CE411E5FBC1191A0A52EF:9740051E9C5FECF64344F7A82260EDCC:0
-AES-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:A78819583F0308E7A6BF36B1386ABF23:F69F2445DF4F9B17AD2B417BE66C3710:304C6528F659C77866A510D9C1D6AE5E:0
-# OFB-AES192.Encrypt
-AES-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:CDC80D6FDDF18CAB34C25909C99A4174:1
-AES-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:A609B38DF3B1133DDDFF2718BA09565E:AE2D8A571E03AC9C9EB76FAC45AF8E51:FCC28B8D4C63837C09E81700C1100401:1
-AES-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:52EF01DA52602FE0975F78AC84BF8A50:30C81C46A35CE411E5FBC1191A0A52EF:8D9A9AEAC0F6596F559C6D4DAF59A5F2:1
-AES-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:BD5286AC63AABD7EB067AC54B553F71D:F69F2445DF4F9B17AD2B417BE66C3710:6D9F200857CA6C3E9CAC524BD9ACC92A:1
-# OFB-AES192.Decrypt
-AES-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:CDC80D6FDDF18CAB34C25909C99A4174:0
-AES-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:A609B38DF3B1133DDDFF2718BA09565E:AE2D8A571E03AC9C9EB76FAC45AF8E51:FCC28B8D4C63837C09E81700C1100401:0
-AES-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:52EF01DA52602FE0975F78AC84BF8A50:30C81C46A35CE411E5FBC1191A0A52EF:8D9A9AEAC0F6596F559C6D4DAF59A5F2:0
-AES-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:BD5286AC63AABD7EB067AC54B553F71D:F69F2445DF4F9B17AD2B417BE66C3710:6D9F200857CA6C3E9CAC524BD9ACC92A:0
-# OFB-AES256.Encrypt
-AES-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:DC7E84BFDA79164B7ECD8486985D3860:1
-AES-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:B7BF3A5DF43989DD97F0FA97EBCE2F4A:AE2D8A571E03AC9C9EB76FAC45AF8E51:4FEBDC6740D20B3AC88F6AD82A4FB08D:1
-AES-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:E1C656305ED1A7A6563805746FE03EDC:30C81C46A35CE411E5FBC1191A0A52EF:71AB47A086E86EEDF39D1C5BBA97C408:1
-AES-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:41635BE625B48AFC1666DD42A09D96E7:F69F2445DF4F9B17AD2B417BE66C3710:0126141D67F37BE8538F5A8BE740E484:1
-# OFB-AES256.Decrypt
-AES-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:DC7E84BFDA79164B7ECD8486985D3860:0
-AES-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:B7BF3A5DF43989DD97F0FA97EBCE2F4A:AE2D8A571E03AC9C9EB76FAC45AF8E51:4FEBDC6740D20B3AC88F6AD82A4FB08D:0
-AES-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:E1C656305ED1A7A6563805746FE03EDC:30C81C46A35CE411E5FBC1191A0A52EF:71AB47A086E86EEDF39D1C5BBA97C408:0
-AES-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:41635BE625B48AFC1666DD42A09D96E7:F69F2445DF4F9B17AD2B417BE66C3710:0126141D67F37BE8538F5A8BE740E484:0
-
-# AES Counter test vectors from RFC3686
-aes-128-ctr:AE6852F8121067CC4BF7A5765577F39E:00000030000000000000000000000001:53696E676C6520626C6F636B206D7367:E4095D4FB7A7B3792D6175A3261311B8:1
-aes-128-ctr:7E24067817FAE0D743D6CE1F32539163:006CB6DBC0543B59DA48D90B00000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:5104A106168A72D9790D41EE8EDAD388EB2E1EFC46DA57C8FCE630DF9141BE28:1
-aes-128-ctr:7691BE035E5020A8AC6E618529F9A0DC:00E0017B27777F3F4A1786F000000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223:C1CF48A89F2FFDD9CF4652E9EFDB72D74540A42BDE6D7836D59A5CEAAEF3105325B2072F:1
-
-aes-192-ctr:16AF5B145FC9F579C175F93E3BFB0EED863D06CCFDB78515:0000004836733C147D6D93CB00000001:53696E676C6520626C6F636B206D7367:4B55384FE259C9C84E7935A003CBE928:1
-aes-192-ctr:7C5CB2401B3DC33C19E7340819E0F69C678C3DB8E6F6A91A:0096B03B020C6EADC2CB500D00000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:453243FC609B23327EDFAAFA7131CD9F8490701C5AD4A79CFC1FE0FF42F4FB00:1
-aes-192-ctr:02BF391EE8ECB159B959617B0965279BF59B60A786D3E0FE:0007BDFD5CBD60278DCC091200000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223:96893FC55E5C722F540B7DD1DDF7E758D288BC95C69165884536C811662F2188ABEE0935:1
-
-aes-256-ctr:776BEFF2851DB06F4C8A0542C8696F6C6A81AF1EEC96B4D37FC1D689E6C1C104:00000060DB5672C97AA8F0B200000001:53696E676C6520626C6F636B206D7367:145AD01DBF824EC7560863DC71E3E0C0:1
-aes-256-ctr:F6D66D6BD52D59BB0796365879EFF886C66DD51A5B6A99744B50590C87A23884:00FAAC24C1585EF15A43D87500000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:F05E231B3894612C49EE000B804EB2A9B8306B508F839D6A5530831D9344AF1C:1
-aes-256-ctr:FF7A617CE69148E4F1726E2F43581DE2AA62D9F805532EDFF1EED687FB54153D:001CC5B751A51D70A1C1114800000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223:EB6C52821D0BBBF7CE7594462ACA4FAAB407DF866569FD07F48CC0B583D6071F1EC0E6B8:1
-
-# DES ECB tests (from destest)
-
-DES-ECB:0000000000000000::0000000000000000:8CA64DE9C1B123A7
-DES-ECB:FFFFFFFFFFFFFFFF::FFFFFFFFFFFFFFFF:7359B2163E4EDC58
-DES-ECB:3000000000000000::1000000000000001:958E6E627A05557B
-DES-ECB:1111111111111111::1111111111111111:F40379AB9E0EC533
-DES-ECB:0123456789ABCDEF::1111111111111111:17668DFC7292532D
-DES-ECB:1111111111111111::0123456789ABCDEF:8A5AE1F81AB8F2DD
-DES-ECB:FEDCBA9876543210::0123456789ABCDEF:ED39D950FA74BCC4
-
-# DESX-CBC tests (from destest)
-DESX-CBC:0123456789abcdeff1e0d3c2b5a49786fedcba9876543210:fedcba9876543210:37363534333231204E6F77206973207468652074696D6520666F722000000000:846B2914851E9A2954732F8AA0A611C115CDC2D7951B1053A63C5E03B21AA3C4
-
-# DES EDE3 CBC tests (from destest)
-DES-EDE3-CBC:0123456789abcdeff1e0d3c2b5a49786fedcba9876543210:fedcba9876543210:37363534333231204E6F77206973207468652074696D6520666F722000000000:3FE301C962AC01D02213763C1CBD4CDC799657C064ECF5D41C673812CFDE9675
-
-# RC4 tests (from rc4test)
-RC4:0123456789abcdef0123456789abcdef::0123456789abcdef:75b7878099e0c596
-RC4:0123456789abcdef0123456789abcdef::0000000000000000:7494c2e7104b0879
-RC4:00000000000000000000000000000000::0000000000000000:de188941a3375d3a
-RC4:ef012345ef012345ef012345ef012345::0000000000000000000000000000000000000000:d6a141a7ec3c38dfbd615a1162e1c7ba36b67858
-RC4:0123456789abcdef0123456789abcdef::123456789ABCDEF0123456789ABCDEF0123456789ABCDEF012345678:66a0949f8af7d6891f7f832ba833c00c892ebe30143ce28740011ecf
-RC4:ef012345ef012345ef012345ef012345::00000000000000000000:d6a141a7ec3c38dfbd61
-
-
-# Camellia tests from RFC3713
-# For all ECB encrypts and decrypts, the transformed sequence is
-# CAMELLIA-bits-ECB:key::plaintext:ciphertext:encdec
-CAMELLIA-128-ECB:0123456789abcdeffedcba9876543210::0123456789abcdeffedcba9876543210:67673138549669730857065648eabe43
-CAMELLIA-192-ECB:0123456789abcdeffedcba98765432100011223344556677::0123456789abcdeffedcba9876543210:b4993401b3e996f84ee5cee7d79b09b9
-CAMELLIA-256-ECB:0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff::0123456789abcdeffedcba9876543210:9acc237dff16d76c20ef7c919e3a7509
-
-# ECB-CAMELLIA128.Encrypt
-CAMELLIA-128-ECB:000102030405060708090A0B0C0D0E0F::00112233445566778899AABBCCDDEEFF:77CF412067AF8270613529149919546F:1
-CAMELLIA-192-ECB:000102030405060708090A0B0C0D0E0F1011121314151617::00112233445566778899AABBCCDDEEFF:B22F3C36B72D31329EEE8ADDC2906C68:1
-CAMELLIA-256-ECB:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F::00112233445566778899AABBCCDDEEFF:2EDF1F3418D53B88841FC8985FB1ECF2:1
-
-# ECB-CAMELLIA128.Encrypt and ECB-CAMELLIA128.Decrypt
-CAMELLIA-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::6BC1BEE22E409F96E93D7E117393172A:432FC5DCD628115B7C388D770B270C96
-CAMELLIA-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::AE2D8A571E03AC9C9EB76FAC45AF8E51:0BE1F14023782A22E8384C5ABB7FAB2B
-CAMELLIA-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::30C81C46A35CE411E5FBC1191A0A52EF:A0A1ABCD1893AB6FE0FE5B65DF5F8636
-CAMELLIA-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::F69F2445DF4F9B17AD2B417BE66C3710:E61925E0D5DFAA9BB29F815B3076E51A
-
-# ECB-CAMELLIA192.Encrypt and ECB-CAMELLIA192.Decrypt
-CAMELLIA-192-ECB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B::6BC1BEE22E409F96E93D7E117393172A:CCCC6C4E138B45848514D48D0D3439D3
-CAMELLIA-192-ECB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B::AE2D8A571E03AC9C9EB76FAC45AF8E51:5713C62C14B2EC0F8393B6AFD6F5785A
-CAMELLIA-192-ECB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B::30C81C46A35CE411E5FBC1191A0A52EF:B40ED2B60EB54D09D030CF511FEEF366
-CAMELLIA-192-ECB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B::F69F2445DF4F9B17AD2B417BE66C3710:909DBD95799096748CB27357E73E1D26
-
-# ECB-CAMELLIA256.Encrypt and ECB-CAMELLIA256.Decrypt
-CAMELLIA-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::6BC1BEE22E409F96E93D7E117393172A:BEFD219B112FA00098919CD101C9CCFA
-CAMELLIA-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::AE2D8A571E03AC9C9EB76FAC45AF8E51:C91D3A8F1AEA08A9386CF4B66C0169EA
-CAMELLIA-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::30C81C46A35CE411E5FBC1191A0A52EF:A623D711DC5F25A51BB8A80D56397D28
-CAMELLIA-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::F69F2445DF4F9B17AD2B417BE66C3710:7960109FB6DC42947FCFE59EA3C5EB6B
-
-# For all CBC encrypts and decrypts, the transformed sequence is
-# CAMELLIA-bits-CBC:key:IV/ciphertext':plaintext:ciphertext:encdec
-# CBC-CAMELLIA128.Encrypt and CBC-CAMELLIA128.Decrypt
-CAMELLIA-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:1607CF494B36BBF00DAEB0B503C831AB
-CAMELLIA-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:1607CF494B36BBF00DAEB0B503C831AB:AE2D8A571E03AC9C9EB76FAC45AF8E51:A2F2CF671629EF7840C5A5DFB5074887
-CAMELLIA-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:A2F2CF671629EF7840C5A5DFB5074887:30C81C46A35CE411E5FBC1191A0A52EF:0F06165008CF8B8B5A63586362543E54
-CAMELLIA-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:36A84CDAFD5F9A85ADA0F0A993D6D577:F69F2445DF4F9B17AD2B417BE66C3710:74C64268CDB8B8FAF5B34E8AF3732980
-
-# CBC-CAMELLIA192.Encrypt and CBC-CAMELLIA192.Decrypt
-CAMELLIA-192-CBC:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:2A4830AB5AC4A1A2405955FD2195CF93
-CAMELLIA-192-CBC:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:2A4830AB5AC4A1A2405955FD2195CF93:AE2D8A571E03AC9C9EB76FAC45AF8E51:5D5A869BD14CE54264F892A6DD2EC3D5
-CAMELLIA-192-CBC:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:5D5A869BD14CE54264F892A6DD2EC3D5:30C81C46A35CE411E5FBC1191A0A52EF:37D359C3349836D884E310ADDF68C449
-CAMELLIA-192-CBC:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:37D359C3349836D884E310ADDF68C449:F69F2445DF4F9B17AD2B417BE66C3710:01FAAA930B4AB9916E9668E1428C6B08
-
-# CBC-CAMELLIA256.Encrypt and CBC-CAMELLIA256.Decrypt
-CAMELLIA-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:E6CFA35FC02B134A4D2C0B6737AC3EDA
-CAMELLIA-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:E6CFA35FC02B134A4D2C0B6737AC3EDA:AE2D8A571E03AC9C9EB76FAC45AF8E51:36CBEB73BD504B4070B1B7DE2B21EB50
-CAMELLIA-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:36CBEB73BD504B4070B1B7DE2B21EB50:30C81C46A35CE411E5FBC1191A0A52EF:E31A6055297D96CA3330CDF1B1860A83
-CAMELLIA-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:E31A6055297D96CA3330CDF1B1860A83:F69F2445DF4F9B17AD2B417BE66C3710:5D563F6D1CCCF236051C0C5C1C58F28F
-
-# We don't support CFB{1,8}-CAMELLIAxxx.{En,De}crypt
-# For all CFB128 encrypts and decrypts, the transformed sequence is
-# CAMELLIA-bits-CFB:key:IV/ciphertext':plaintext:ciphertext:encdec
-# CFB128-CAMELLIA128.Encrypt
-CAMELLIA-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:14F7646187817EB586599146B82BD719:1
-CAMELLIA-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:14F7646187817EB586599146B82BD719:AE2D8A571E03AC9C9EB76FAC45AF8E51:A53D28BB82DF741103EA4F921A44880B:1
-CAMELLIA-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:A53D28BB82DF741103EA4F921A44880B:30C81C46A35CE411E5FBC1191A0A52EF:9C2157A664626D1DEF9EA420FDE69B96:1
-CAMELLIA-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:9C2157A664626D1DEF9EA420FDE69B96:F69F2445DF4F9B17AD2B417BE66C3710:742A25F0542340C7BAEF24CA8482BB09:1
-
-# CFB128-CAMELLIA128.Decrypt
-CAMELLIA-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:14F7646187817EB586599146B82BD719:0
-CAMELLIA-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:14F7646187817EB586599146B82BD719:AE2D8A571E03AC9C9EB76FAC45AF8E51:A53D28BB82DF741103EA4F921A44880B:0
-CAMELLIA-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:A53D28BB82DF741103EA4F921A44880B:30C81C46A35CE411E5FBC1191A0A52EF:9C2157A664626D1DEF9EA420FDE69B96:0
-CAMELLIA-128-CFB:2B7E151628AED2A6ABF7158809CF4F3C:9C2157A664626D1DEF9EA420FDE69B96:F69F2445DF4F9B17AD2B417BE66C3710:742A25F0542340C7BAEF24CA8482BB09:0
-
-# CFB128-CAMELLIA192.Encrypt
-CAMELLIA-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:C832BB9780677DAA82D9B6860DCD565E:1
-CAMELLIA-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:C832BB9780677DAA82D9B6860DCD565E:AE2D8A571E03AC9C9EB76FAC45AF8E51:86F8491627906D780C7A6D46EA331F98:1
-CAMELLIA-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:86F8491627906D780C7A6D46EA331F98:30C81C46A35CE411E5FBC1191A0A52EF:69511CCE594CF710CB98BB63D7221F01:1
-CAMELLIA-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:69511CCE594CF710CB98BB63D7221F01:F69F2445DF4F9B17AD2B417BE66C3710:D5B5378A3ABED55803F25565D8907B84:1
-
-# CFB128-CAMELLIA192.Decrypt
-CAMELLIA-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:C832BB9780677DAA82D9B6860DCD565E:0
-CAMELLIA-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:C832BB9780677DAA82D9B6860DCD565E:AE2D8A571E03AC9C9EB76FAC45AF8E51:86F8491627906D780C7A6D46EA331F98:0
-CAMELLIA-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:86F8491627906D780C7A6D46EA331F98:30C81C46A35CE411E5FBC1191A0A52EF:69511CCE594CF710CB98BB63D7221F01:0
-CAMELLIA-192-CFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:69511CCE594CF710CB98BB63D7221F01:F69F2445DF4F9B17AD2B417BE66C3710:D5B5378A3ABED55803F25565D8907B84:0
-
-# CFB128-CAMELLIA256.Encrypt
-CAMELLIA-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:CF6107BB0CEA7D7FB1BD31F5E7B06C93:1
-CAMELLIA-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:CF6107BB0CEA7D7FB1BD31F5E7B06C93:AE2D8A571E03AC9C9EB76FAC45AF8E51:89BEDB4CCDD864EA11BA4CBE849B5E2B:1
-CAMELLIA-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:89BEDB4CCDD864EA11BA4CBE849B5E2B:30C81C46A35CE411E5FBC1191A0A52EF:555FC3F34BDD2D54C62D9E3BF338C1C4:1
-CAMELLIA-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:555FC3F34BDD2D54C62D9E3BF338C1C4:F69F2445DF4F9B17AD2B417BE66C3710:5953ADCE14DB8C7F39F1BD39F359BFFA:1
-
-# CFB128-CAMELLIA256.Decrypt
-CAMELLIA-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:CF6107BB0CEA7D7FB1BD31F5E7B06C93:0
-CAMELLIA-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:CF6107BB0CEA7D7FB1BD31F5E7B06C93:AE2D8A571E03AC9C9EB76FAC45AF8E51:89BEDB4CCDD864EA11BA4CBE849B5E2B:0
-CAMELLIA-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:89BEDB4CCDD864EA11BA4CBE849B5E2B:30C81C46A35CE411E5FBC1191A0A52EF:555FC3F34BDD2D54C62D9E3BF338C1C4:0
-CAMELLIA-256-CFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:555FC3F34BDD2D54C62D9E3BF338C1C4:F69F2445DF4F9B17AD2B417BE66C3710:5953ADCE14DB8C7F39F1BD39F359BFFA:0
-
-# For all OFB encrypts and decrypts, the transformed sequence is
-# CAMELLIA-bits-OFB:key:IV/output':plaintext:ciphertext:encdec
-# OFB-CAMELLIA128.Encrypt
-CAMELLIA-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:14F7646187817EB586599146B82BD719:1
-CAMELLIA-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:50FE67CC996D32B6DA0937E99BAFEC60:AE2D8A571E03AC9C9EB76FAC45AF8E51:25623DB569CA51E01482649977E28D84:1
-CAMELLIA-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:D9A4DADA0892239F6B8B3D7680E15674:30C81C46A35CE411E5FBC1191A0A52EF:C776634A60729DC657D12B9FCA801E98:1
-CAMELLIA-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:A78819583F0308E7A6BF36B1386ABF23:F69F2445DF4F9B17AD2B417BE66C3710:D776379BE0E50825E681DA1A4C980E8E:1
-
-# OFB-CAMELLIA128.Decrypt
-CAMELLIA-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:14F7646187817EB586599146B82BD719:0
-CAMELLIA-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:50FE67CC996D32B6DA0937E99BAFEC60:AE2D8A571E03AC9C9EB76FAC45AF8E51:25623DB569CA51E01482649977E28D84:0
-CAMELLIA-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:D9A4DADA0892239F6B8B3D7680E15674:30C81C46A35CE411E5FBC1191A0A52EF:C776634A60729DC657D12B9FCA801E98:0
-CAMELLIA-128-OFB:2B7E151628AED2A6ABF7158809CF4F3C:A78819583F0308E7A6BF36B1386ABF23:F69F2445DF4F9B17AD2B417BE66C3710:D776379BE0E50825E681DA1A4C980E8E:0
-
-# OFB-CAMELLIA192.Encrypt
-CAMELLIA-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:C832BB9780677DAA82D9B6860DCD565E:1
-CAMELLIA-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:A609B38DF3B1133DDDFF2718BA09565E:AE2D8A571E03AC9C9EB76FAC45AF8E51:8ECEB7D0350D72C7F78562AEBDF99339:1
-CAMELLIA-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:52EF01DA52602FE0975F78AC84BF8A50:30C81C46A35CE411E5FBC1191A0A52EF:BDD62DBBB9700846C53B507F544696F0:1
-CAMELLIA-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:BD5286AC63AABD7EB067AC54B553F71D:F69F2445DF4F9B17AD2B417BE66C3710:E28014E046B802F385C4C2E13EAD4A72:1
-
-# OFB-CAMELLIA192.Decrypt
-CAMELLIA-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:C832BB9780677DAA82D9B6860DCD565E:0
-CAMELLIA-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:A609B38DF3B1133DDDFF2718BA09565E:AE2D8A571E03AC9C9EB76FAC45AF8E51:8ECEB7D0350D72C7F78562AEBDF99339:0
-CAMELLIA-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:52EF01DA52602FE0975F78AC84BF8A50:30C81C46A35CE411E5FBC1191A0A52EF:BDD62DBBB9700846C53B507F544696F0:0
-CAMELLIA-192-OFB:8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B:BD5286AC63AABD7EB067AC54B553F71D:F69F2445DF4F9B17AD2B417BE66C3710:E28014E046B802F385C4C2E13EAD4A72:0
-
-# OFB-CAMELLIA256.Encrypt
-CAMELLIA-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:CF6107BB0CEA7D7FB1BD31F5E7B06C93:1
-CAMELLIA-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:B7BF3A5DF43989DD97F0FA97EBCE2F4A:AE2D8A571E03AC9C9EB76FAC45AF8E51:127AD97E8E3994E4820027D7BA109368:1
-CAMELLIA-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:E1C656305ED1A7A6563805746FE03EDC:30C81C46A35CE411E5FBC1191A0A52EF:6BFF6265A6A6B7A535BC65A80B17214E:1
-CAMELLIA-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:41635BE625B48AFC1666DD42A09D96E7:F69F2445DF4F9B17AD2B417BE66C3710:0A4A0404E26AA78A27CB271E8BF3CF20:1
-
-# OFB-CAMELLIA256.Decrypt
-CAMELLIA-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:CF6107BB0CEA7D7FB1BD31F5E7B06C93:0
-CAMELLIA-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:B7BF3A5DF43989DD97F0FA97EBCE2F4A:AE2D8A571E03AC9C9EB76FAC45AF8E51:127AD97E8E3994E4820027D7BA109368:0
-CAMELLIA-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:E1C656305ED1A7A6563805746FE03EDC:30C81C46A35CE411E5FBC1191A0A52EF:6BFF6265A6A6B7A535BC65A80B17214E:0
-CAMELLIA-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:41635BE625B48AFC1666DD42A09D96E7:F69F2445DF4F9B17AD2B417BE66C3710:0A4A0404E26AA78A27CB271E8BF3CF20:0
-
-# SEED test vectors from RFC4269
-SEED-ECB:00000000000000000000000000000000::000102030405060708090A0B0C0D0E0F:5EBAC6E0054E166819AFF1CC6D346CDB:0
-SEED-ECB:000102030405060708090A0B0C0D0E0F::00000000000000000000000000000000:C11F22F20140505084483597E4370F43:0
-SEED-ECB:4706480851E61BE85D74BFB3FD956185::83A2F8A288641FB9A4E9A5CC2F131C7D:EE54D13EBCAE706D226BC3142CD40D4A:0
-SEED-ECB:28DBC3BC49FFD87DCFA509B11D422BE7::B41E6BE2EBA84A148E2EED84593C5EC7:9B9B7BFCD1813CB95D0B3618F40F5122:0
-SEED-ECB:00000000000000000000000000000000::000102030405060708090A0B0C0D0E0F:5EBAC6E0054E166819AFF1CC6D346CDB:1
-SEED-ECB:000102030405060708090A0B0C0D0E0F::00000000000000000000000000000000:C11F22F20140505084483597E4370F43:1
-SEED-ECB:4706480851E61BE85D74BFB3FD956185::83A2F8A288641FB9A4E9A5CC2F131C7D:EE54D13EBCAE706D226BC3142CD40D4A:1
-SEED-ECB:28DBC3BC49FFD87DCFA509B11D422BE7::B41E6BE2EBA84A148E2EED84593C5EC7:9B9B7BFCD1813CB95D0B3618F40F5122:1
diff --git a/src/third_party/openssl/openssl/test/exptest.c b/src/third_party/openssl/openssl/test/exptest.c
deleted file mode 120000
index 50ccf71..0000000
--- a/src/third_party/openssl/openssl/test/exptest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/bn/exptest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/fips_aesavs.c b/src/third_party/openssl/openssl/test/fips_aesavs.c
deleted file mode 120000
index 7d9da0e..0000000
--- a/src/third_party/openssl/openssl/test/fips_aesavs.c
+++ /dev/null
@@ -1 +0,0 @@
-../fips/aes/fips_aesavs.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/fips_desmovs.c b/src/third_party/openssl/openssl/test/fips_desmovs.c
deleted file mode 120000
index dd74966..0000000
--- a/src/third_party/openssl/openssl/test/fips_desmovs.c
+++ /dev/null
@@ -1 +0,0 @@
-../fips/des/fips_desmovs.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/fips_dsatest.c b/src/third_party/openssl/openssl/test/fips_dsatest.c
deleted file mode 120000
index e43b79b..0000000
--- a/src/third_party/openssl/openssl/test/fips_dsatest.c
+++ /dev/null
@@ -1 +0,0 @@
-../fips/dsa/fips_dsatest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/fips_dssvs.c b/src/third_party/openssl/openssl/test/fips_dssvs.c
deleted file mode 120000
index 93e05e6..0000000
--- a/src/third_party/openssl/openssl/test/fips_dssvs.c
+++ /dev/null
@@ -1 +0,0 @@
-../fips/dsa/fips_dssvs.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/fips_hmactest.c b/src/third_party/openssl/openssl/test/fips_hmactest.c
deleted file mode 120000
index b674d16..0000000
--- a/src/third_party/openssl/openssl/test/fips_hmactest.c
+++ /dev/null
@@ -1 +0,0 @@
-../fips/hmac/fips_hmactest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/fips_randtest.c b/src/third_party/openssl/openssl/test/fips_randtest.c
deleted file mode 120000
index 8b8f486..0000000
--- a/src/third_party/openssl/openssl/test/fips_randtest.c
+++ /dev/null
@@ -1 +0,0 @@
-../fips/rand/fips_randtest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/fips_rngvs.c b/src/third_party/openssl/openssl/test/fips_rngvs.c
deleted file mode 120000
index 0d6c9be..0000000
--- a/src/third_party/openssl/openssl/test/fips_rngvs.c
+++ /dev/null
@@ -1 +0,0 @@
-../fips/rand/fips_rngvs.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/fips_rsagtest.c b/src/third_party/openssl/openssl/test/fips_rsagtest.c
deleted file mode 120000
index 3ed6b51..0000000
--- a/src/third_party/openssl/openssl/test/fips_rsagtest.c
+++ /dev/null
@@ -1 +0,0 @@
-../fips/rsa/fips_rsagtest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/fips_rsastest.c b/src/third_party/openssl/openssl/test/fips_rsastest.c
deleted file mode 120000
index 2a5f8b0..0000000
--- a/src/third_party/openssl/openssl/test/fips_rsastest.c
+++ /dev/null
@@ -1 +0,0 @@
-../fips/rsa/fips_rsastest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/fips_rsavtest.c b/src/third_party/openssl/openssl/test/fips_rsavtest.c
deleted file mode 120000
index f45aa58..0000000
--- a/src/third_party/openssl/openssl/test/fips_rsavtest.c
+++ /dev/null
@@ -1 +0,0 @@
-../fips/rsa/fips_rsavtest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/fips_shatest.c b/src/third_party/openssl/openssl/test/fips_shatest.c
deleted file mode 120000
index 67c47ca..0000000
--- a/src/third_party/openssl/openssl/test/fips_shatest.c
+++ /dev/null
@@ -1 +0,0 @@
-../fips/sha/fips_shatest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/fips_test_suite.c b/src/third_party/openssl/openssl/test/fips_test_suite.c
deleted file mode 120000
index b538efa..0000000
--- a/src/third_party/openssl/openssl/test/fips_test_suite.c
+++ /dev/null
@@ -1 +0,0 @@
-../fips/fips_test_suite.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/hmactest.c b/src/third_party/openssl/openssl/test/hmactest.c
deleted file mode 120000
index 353ee2c..0000000
--- a/src/third_party/openssl/openssl/test/hmactest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/hmac/hmactest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/ideatest.c b/src/third_party/openssl/openssl/test/ideatest.c
deleted file mode 120000
index a9bfb3d..0000000
--- a/src/third_party/openssl/openssl/test/ideatest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/idea/ideatest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/jpaketest.c b/src/third_party/openssl/openssl/test/jpaketest.c
deleted file mode 120000
index 49f44f8..0000000
--- a/src/third_party/openssl/openssl/test/jpaketest.c
+++ /dev/null
@@ -1 +0,0 @@
-dummytest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/md2test.c b/src/third_party/openssl/openssl/test/md2test.c
deleted file mode 120000
index 49f44f8..0000000
--- a/src/third_party/openssl/openssl/test/md2test.c
+++ /dev/null
@@ -1 +0,0 @@
-dummytest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/md4test.c b/src/third_party/openssl/openssl/test/md4test.c
deleted file mode 120000
index 1509be9..0000000
--- a/src/third_party/openssl/openssl/test/md4test.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/md4/md4test.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/md5test.c b/src/third_party/openssl/openssl/test/md5test.c
deleted file mode 120000
index 20f4aaf..0000000
--- a/src/third_party/openssl/openssl/test/md5test.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/md5/md5test.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/mdc2test.c b/src/third_party/openssl/openssl/test/mdc2test.c
deleted file mode 120000
index c4ffe48..0000000
--- a/src/third_party/openssl/openssl/test/mdc2test.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/mdc2/mdc2test.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/randtest.c b/src/third_party/openssl/openssl/test/randtest.c
deleted file mode 120000
index a2b107a..0000000
--- a/src/third_party/openssl/openssl/test/randtest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/rand/randtest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/rc2test.c b/src/third_party/openssl/openssl/test/rc2test.c
deleted file mode 120000
index 5c53ad9..0000000
--- a/src/third_party/openssl/openssl/test/rc2test.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/rc2/rc2test.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/rc4test.c b/src/third_party/openssl/openssl/test/rc4test.c
deleted file mode 120000
index 061ac37..0000000
--- a/src/third_party/openssl/openssl/test/rc4test.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/rc4/rc4test.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/rc5test.c b/src/third_party/openssl/openssl/test/rc5test.c
deleted file mode 120000
index 49f44f8..0000000
--- a/src/third_party/openssl/openssl/test/rc5test.c
+++ /dev/null
@@ -1 +0,0 @@
-dummytest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/rmdtest.c b/src/third_party/openssl/openssl/test/rmdtest.c
deleted file mode 120000
index ce66460..0000000
--- a/src/third_party/openssl/openssl/test/rmdtest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/ripemd/rmdtest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/rsa_test.c b/src/third_party/openssl/openssl/test/rsa_test.c
deleted file mode 120000
index aaea20d..0000000
--- a/src/third_party/openssl/openssl/test/rsa_test.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/rsa/rsa_test.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/sha1test.c b/src/third_party/openssl/openssl/test/sha1test.c
deleted file mode 120000
index 8d66e9e..0000000
--- a/src/third_party/openssl/openssl/test/sha1test.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/sha/sha1test.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/sha256t.c b/src/third_party/openssl/openssl/test/sha256t.c
deleted file mode 120000
index 952a508..0000000
--- a/src/third_party/openssl/openssl/test/sha256t.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/sha/sha256t.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/sha512t.c b/src/third_party/openssl/openssl/test/sha512t.c
deleted file mode 120000
index c80d152..0000000
--- a/src/third_party/openssl/openssl/test/sha512t.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/sha/sha512t.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/shatest.c b/src/third_party/openssl/openssl/test/shatest.c
deleted file mode 120000
index 43cfda7..0000000
--- a/src/third_party/openssl/openssl/test/shatest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/sha/shatest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/srptest.c b/src/third_party/openssl/openssl/test/srptest.c
deleted file mode 120000
index 9534868..0000000
--- a/src/third_party/openssl/openssl/test/srptest.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/srp/srptest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/ssltest.c b/src/third_party/openssl/openssl/test/ssltest.c
deleted file mode 120000
index 40191f0..0000000
--- a/src/third_party/openssl/openssl/test/ssltest.c
+++ /dev/null
@@ -1 +0,0 @@
-../ssl/ssltest.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/test/testcrl.pem b/src/third_party/openssl/openssl/test/testcrl.pem
deleted file mode 100644
index 0989788..0000000
--- a/src/third_party/openssl/openssl/test/testcrl.pem
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN X509 CRL-----
-MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT
-F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy
-IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw
-MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw
-MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw
-MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw
-MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw
-MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw
-MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw
-NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw
-NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF
-AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ
-wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt
-JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v
------END X509 CRL-----
diff --git a/src/third_party/openssl/openssl/test/testp7.pem b/src/third_party/openssl/openssl/test/testp7.pem
deleted file mode 100644
index e5b7866..0000000
--- a/src/third_party/openssl/openssl/test/testp7.pem
+++ /dev/null
@@ -1,46 +0,0 @@
------BEGIN PKCS7-----
-MIIIGAYJKoZIhvcNAQcCoIIICTCCCAUCAQExADALBgkqhkiG9w0BBwGgggY8MIIE
-cjCCBBygAwIBAgIQeS+OJfWJUZAx6cX0eAiMjzANBgkqhkiG9w0BAQQFADBiMREw
-DwYDVQQHEwhJbnRlcm5ldDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNDAyBgNV
-BAsTK1ZlcmlTaWduIENsYXNzIDEgQ0EgLSBJbmRpdmlkdWFsIFN1YnNjcmliZXIw
-HhcNOTYwNzE5MDAwMDAwWhcNOTcwMzMwMjM1OTU5WjCB1TERMA8GA1UEBxMISW50
-ZXJuZXQxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTQwMgYDVQQLEytWZXJpU2ln
-biBDbGFzcyAxIENBIC0gSW5kaXZpZHVhbCBTdWJzY3JpYmVyMSgwJgYDVQQLEx9E
-aWdpdGFsIElEIENsYXNzIDEgLSBTTUlNRSBUZXN0MUcwRQYDVQQLEz53d3cudmVy
-aXNpZ24uY29tL3JlcG9zaXRvcnkvQ1BTLTEuMCBJbmMuIGJ5IFJlZi4sTElBQi5M
-VEQoYyk5NjBbMA0GCSqGSIb3DQEBAQUAA0oAMEcCQA7LvHEIAiQ5+4gDYvJGnGAq
-UM5GXyG11diEXmIEZTHUZhorooX5sr8IIjSXiPY59YYUFSvAaharFM1xaBN8zNEC
-AwEAAaOCAjkwggI1MAkGA1UdEwQCMAAwggImBgNVHQMEggIdMIICGTCCAhUwggIR
-BgtghkgBhvhFAQcBATCCAgAWggGrVGhpcyBjZXJ0aWZpY2F0ZSBpbmNvcnBvcmF0
-ZXMgYnkgcmVmZXJlbmNlLCBhbmQgaXRzIHVzZSBpcyBzdHJpY3RseSBzdWJqZWN0
-IHRvLCB0aGUgVmVyaVNpZ24gQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1l
-bnQgKENQUyksIGF2YWlsYWJsZSBhdDogaHR0cHM6Ly93d3cudmVyaXNpZ24uY29t
-L0NQUy0xLjA7IGJ5IEUtbWFpbCBhdCBDUFMtcmVxdWVzdHNAdmVyaXNpZ24uY29t
-OyBvciBieSBtYWlsIGF0IFZlcmlTaWduLCBJbmMuLCAyNTkzIENvYXN0IEF2ZS4s
-IE1vdW50YWluIFZpZXcsIENBIDk0MDQzIFVTQSBUZWwuICsxICg0MTUpIDk2MS04
-ODMwIENvcHlyaWdodCAoYykgMTk5NiBWZXJpU2lnbiwgSW5jLiAgQWxsIFJpZ2h0
-cyBSZXNlcnZlZC4gQ0VSVEFJTiBXQVJSQU5USUVTIERJU0NMQUlNRUQgYW5kIExJ
-QUJJTElUWSBMSU1JVEVELqAOBgxghkgBhvhFAQcBAQGhDgYMYIZIAYb4RQEHAQEC
-MC8wLRYraHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvQ1BTLTEu
-AzANBgkqhkiG9w0BAQQFAANBAMCYDuSb/eIlYSxY31nZZTaCZkCSfHjlacMofExr
-cF+A2yHoEuT+eCQkqM0pMNHXddUeoQ9RjV+VuMBNmm63DUYwggHCMIIBbKADAgEC
-AhB8CYTq1bkRFJBYOd67cp9JMA0GCSqGSIb3DQEBAgUAMD4xCzAJBgNVBAYTAlVT
-MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEWMBQGA1UECxMNVEVTVCBSb290IFBD
-QTAeFw05NjA3MTcwMDAwMDBaFw05NzA3MTcyMzU5NTlaMGIxETAPBgNVBAcTCElu
-dGVybmV0MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVyaVNp
-Z24gQ2xhc3MgMSBDQSAtIEluZGl2aWR1YWwgU3Vic2NyaWJlcjBcMA0GCSqGSIb3
-DQEBAQUAA0sAMEgCQQDsVzrNgnDhbAJZrWeLd9g1vMZJA2W67D33TTbga6yMt+ES
-TWEywhS6RNP+fzLGg7utinjH4tL60cXa0G27GDsLAgMBAAGjIjAgMAsGA1UdDwQE
-AwIBBjARBglghkgBhvhCAQEEBAMCAgQwDQYJKoZIhvcNAQECBQADQQAUp6bRwkaD
-2d1MBs/mjUcgTI2fXVmW8tTm/Ud6OzUwpC3vYgybiOOA4f6mOC5dbyUHrLOsrihU
-47ZQ0Jo1DUfboYIBrTCBwTBtMA0GCSqGSIb3DQEBAgUAMD4xCzAJBgNVBAYTAlVT
-MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEWMBQGA1UECxMNVEVTVCBSb290IFBD
-QRcNOTYwNzE3MTc0NDA5WhcNOTgwNzE3MDAwMDAwWjANBgkqhkiG9w0BAQIFAANB
-AHitA0/xAukCjHzeh1AMT/l2oC68N+yFb+aJPHBBMxc6gG2MaKjBNwb5hcXUllMl
-ExONA3ju10f7owIq3s3wx10wgeYwgZEwDQYJKoZIhvcNAQECBQAwYjERMA8GA1UE
-BxMISW50ZXJuZXQxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTQwMgYDVQQLEytW
-ZXJpU2lnbiBDbGFzcyAxIENBIC0gSW5kaXZpZHVhbCBTdWJzY3JpYmVyFw05NjA3
-MTcxNzU5MjlaFw05NzA3MTgwMDAwMDBaMA0GCSqGSIb3DQEBAgUAA0EAubVWYTsW
-sQmste9f+UgMw8BkjDlM25fwQLrCfmmnLxjewey10kSROypUaJLb+r4oRALc0fG9
-XfZsaiiIgotQHjEA
------END PKCS7-----
diff --git a/src/third_party/openssl/openssl/test/testreq2.pem b/src/third_party/openssl/openssl/test/testreq2.pem
deleted file mode 100644
index c3cdcff..0000000
--- a/src/third_party/openssl/openssl/test/testreq2.pem
+++ /dev/null
@@ -1,7 +0,0 @@
------BEGIN CERTIFICATE REQUEST-----
-MIHaMIGFAgEAMA4xDDAKBgNVBAMTA2NuNDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgC
-QQCQsnkyUGDY2R3mYoeTprFJKgWuJ3f1jUjlIuW5+wfAUoeMt35c4vcFZ2mIBpEG
-DtzkNQN1kr2O9ldm9zYnYhyhAgMBAAGgEjAQBgorBgEEAYI3AgEOMQIwADANBgkq
-hkiG9w0BAQQFAANBAAb2szZgVIxg3vK6kYLjGSBISyuzcXJ6IvuPW6M+yzi1Qgoi
-gQhazHTJp91T8ItZEzUJGZSZl2e5iXlnffWB+/U=
------END CERTIFICATE REQUEST-----
diff --git a/src/third_party/openssl/openssl/test/testrsa.pem b/src/third_party/openssl/openssl/test/testrsa.pem
deleted file mode 100644
index aad2106..0000000
--- a/src/third_party/openssl/openssl/test/testrsa.pem
+++ /dev/null
@@ -1,9 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIBPAIBAAJBAKrbeqkuRk8VcRmWFmtP+LviMB3+6dizWW3DwaffznyHGAFwUJ/I
-Tv0XtbsCyl3QoyKGhrOAy3RvPK5M38iuXT0CAwEAAQJAZ3cnzaHXM/bxGaR5CR1R
-rD1qFBAVfoQFiOH9uPJgMaoAuoQEisPHVcZDKcOv4wEg6/TInAIXBnEigtqvRzuy
-oQIhAPcgZzUq3yVooAaoov8UbXPxqHlwo6GBMqnv20xzkf6ZAiEAsP4BnIaQTM8S
-mvcpHZwQJdmdHHkGKAs37Dfxi67HbkUCIQCeZGliHXFa071Fp06ZeWlR2ADonTZz
-rJBhdTe0v5pCeQIhAIZfkiGgGBX4cIuuckzEm43g9WMUjxP/0GlK39vIyihxAiEA
-mymehFRT0MvqW5xAKAx7Pgkt8HVKwVhc2LwGKHE0DZM=
------END RSA PRIVATE KEY-----
diff --git a/src/third_party/openssl/openssl/test/testsid.pem b/src/third_party/openssl/openssl/test/testsid.pem
deleted file mode 100644
index 7ffd008..0000000
--- a/src/third_party/openssl/openssl/test/testsid.pem
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN SSL SESSION PARAMETERS-----
-MIIB1gIBAQIBAgQDAQCABBCi11xa5qkOP8xrr02K/NQCBBBkIYQZM0Bt95W0EHNV
-bA58oQYCBDIBr7WiBAICASyjggGGMIIBgjCCASwCAQMwDQYJKoZIhvcNAQEEBQAw
-ODELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3Jz
-YSB0ZXN0IENBMB4XDTk1MTAwOTIzMzEzNFoXDTk4MDcwNTIzMzEzNFowYDELMAkG
-A1UEBhMCQVUxDDAKBgNVBAgTA1FMRDEZMBcGA1UEChMQTWluY29tIFB0eS4gTHRk
-LjELMAkGA1UECxMCQ1MxGzAZBgNVBAMTElNTTGVheSBkZW1vIGNsaWVudDBcMA0G
-CSqGSIb3DQEBAQUAA0sAMEgCQQC4pcXEL1lgVA+B5Q3TcuW/O3LZHoA73IYm8oFD
-TezgCDhL2RTMn+seKWF36UtJKRIOBU9jZHCVVd0Me5ls6BEjAgMBAAEwDQYJKoZI
-hvcNAQEEBQADQQBoIpOcwUY1qlVF7j3ROSGvUsbvByOBFmYWkIBgsCqR+9qo1A7L
-CrWF5i8LWt/vLwAHaxWNx2YuBJMFyuK81fTvpA0EC3Rlc3Rjb250ZXh0
------END SSL SESSION PARAMETERS-----
diff --git a/src/third_party/openssl/openssl/test/testx509.pem b/src/third_party/openssl/openssl/test/testx509.pem
deleted file mode 100644
index 8a85d14..0000000
--- a/src/third_party/openssl/openssl/test/testx509.pem
+++ /dev/null
@@ -1,10 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBWzCCAQYCARgwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV
-BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MDYxOTIz
-MzMxMloXDTk1MDcxNzIzMzMxMlowOjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM
-RDEdMBsGA1UEAxMUU1NMZWF5L3JzYSB0ZXN0IGNlcnQwXDANBgkqhkiG9w0BAQEF
-AANLADBIAkEAqtt6qS5GTxVxGZYWa0/4u+IwHf7p2LNZbcPBp9/OfIcYAXBQn8hO
-/Re1uwLKXdCjIoaGs4DLdG88rkzfyK5dPQIDAQABMAwGCCqGSIb3DQIFBQADQQAE
-Wc7EcF8po2/ZO6kNCwK/ICH6DobgLekA5lSLr5EvuioZniZp5lFzAw4+YzPQ7XKJ
-zl9HYIMxATFyqSiD9jsx
------END CERTIFICATE-----
diff --git a/src/third_party/openssl/openssl/test/wp_test.c b/src/third_party/openssl/openssl/test/wp_test.c
deleted file mode 120000
index 81b2021..0000000
--- a/src/third_party/openssl/openssl/test/wp_test.c
+++ /dev/null
@@ -1 +0,0 @@
-../crypto/whrlpool/wp_test.c
\ No newline at end of file
diff --git a/src/third_party/openssl/openssl/tools/c_rehash b/src/third_party/openssl/openssl/tools/c_rehash
deleted file mode 100644
index 6a20011..0000000
--- a/src/third_party/openssl/openssl/tools/c_rehash
+++ /dev/null
@@ -1,180 +0,0 @@
-#!/usr/bin/perl
-
-
-# Perl c_rehash script, scan all files in a directory
-# and add symbolic links to their hash values.
-
-my $openssl;
-
-my $dir = "/usr/local/ssl";
-my $prefix = "/usr/local/ssl";
-
-if(defined $ENV{OPENSSL}) {
- $openssl = $ENV{OPENSSL};
-} else {
- $openssl = "openssl";
- $ENV{OPENSSL} = $openssl;
-}
-
-my $pwd;
-eval "require Cwd";
-if (defined(&Cwd::getcwd)) {
- $pwd=Cwd::getcwd();
-} else {
- $pwd=`pwd`; chomp($pwd);
-}
-my $path_delim = ($pwd =~ /^[a-z]\:/i) ? ';' : ':'; # DOS/Win32 or Unix delimiter?
-
-$ENV{PATH} = "$prefix/bin" . ($ENV{PATH} ? $path_delim . $ENV{PATH} : ""); # prefix our path
-
-if(! -x $openssl) {
- my $found = 0;
- foreach (split /$path_delim/, $ENV{PATH}) {
- if(-x "$_/$openssl") {
- $found = 1;
- $openssl = "$_/$openssl";
- last;
- }
- }
- if($found == 0) {
- print STDERR "c_rehash: rehashing skipped ('openssl' program not available)\n";
- exit 0;
- }
-}
-
-if(@ARGV) {
- @dirlist = @ARGV;
-} elsif($ENV{SSL_CERT_DIR}) {
- @dirlist = split /$path_delim/, $ENV{SSL_CERT_DIR};
-} else {
- $dirlist[0] = "$dir/certs";
-}
-
-if (-d $dirlist[0]) {
- chdir $dirlist[0];
- $openssl="$pwd/$openssl" if (!-x $openssl);
- chdir $pwd;
-}
-
-foreach (@dirlist) {
- if(-d $_ and -w $_) {
- hash_dir($_);
- }
-}
-
-sub hash_dir {
- my %hashlist;
- print "Doing $_[0]\n";
- chdir $_[0];
- opendir(DIR, ".");
- my @flist = readdir(DIR);
- # Delete any existing symbolic links
- foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) {
- if(-l $_) {
- unlink $_;
- }
- }
- closedir DIR;
- FILE: foreach $fname (grep {/\.pem$/} @flist) {
- # Check to see if certificates and/or CRLs present.
- my ($cert, $crl) = check_file($fname);
- if(!$cert && !$crl) {
- print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n";
- next;
- }
- link_hash_cert($fname) if($cert);
- link_hash_crl($fname) if($crl);
- }
-}
-
-sub check_file {
- my ($is_cert, $is_crl) = (0,0);
- my $fname = $_[0];
- open IN, $fname;
- while(<IN>) {
- if(/^-----BEGIN (.*)-----/) {
- my $hdr = $1;
- if($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) {
- $is_cert = 1;
- last if($is_crl);
- } elsif($hdr eq "X509 CRL") {
- $is_crl = 1;
- last if($is_cert);
- }
- }
- }
- close IN;
- return ($is_cert, $is_crl);
-}
-
-
-# Link a certificate to its subject name hash value, each hash is of
-# the form <hash>.<n> where n is an integer. If the hash value already exists
-# then we need to up the value of n, unless its a duplicate in which
-# case we skip the link. We check for duplicates by comparing the
-# certificate fingerprints
-
-sub link_hash_cert {
- my $fname = $_[0];
- $fname =~ s/'/'\\''/g;
- my ($hash, $fprint) = `"$openssl" x509 -hash -fingerprint -noout -in "$fname"`;
- chomp $hash;
- chomp $fprint;
- $fprint =~ s/^.*=//;
- $fprint =~ tr/://d;
- my $suffix = 0;
- # Search for an unused hash filename
- while(exists $hashlist{"$hash.$suffix"}) {
- # Hash matches: if fingerprint matches its a duplicate cert
- if($hashlist{"$hash.$suffix"} eq $fprint) {
- print STDERR "WARNING: Skipping duplicate certificate $fname\n";
- return;
- }
- $suffix++;
- }
- $hash .= ".$suffix";
- print "$fname => $hash\n";
- $symlink_exists=eval {symlink("",""); 1};
- if ($symlink_exists) {
- symlink $fname, $hash;
- } else {
- open IN,"<$fname" or die "can't open $fname for read";
- open OUT,">$hash" or die "can't open $hash for write";
- print OUT <IN>; # does the job for small text files
- close OUT;
- close IN;
- }
- $hashlist{$hash} = $fprint;
-}
-
-# Same as above except for a CRL. CRL links are of the form <hash>.r<n>
-
-sub link_hash_crl {
- my $fname = $_[0];
- $fname =~ s/'/'\\''/g;
- my ($hash, $fprint) = `"$openssl" crl -hash -fingerprint -noout -in '$fname'`;
- chomp $hash;
- chomp $fprint;
- $fprint =~ s/^.*=//;
- $fprint =~ tr/://d;
- my $suffix = 0;
- # Search for an unused hash filename
- while(exists $hashlist{"$hash.r$suffix"}) {
- # Hash matches: if fingerprint matches its a duplicate cert
- if($hashlist{"$hash.r$suffix"} eq $fprint) {
- print STDERR "WARNING: Skipping duplicate CRL $fname\n";
- return;
- }
- $suffix++;
- }
- $hash .= ".r$suffix";
- print "$fname => $hash\n";
- $symlink_exists=eval {symlink("",""); 1};
- if ($symlink_exists) {
- symlink $fname, $hash;
- } else {
- system ("cp", $fname, $hash);
- }
- $hashlist{$hash} = $fprint;
-}
-