Index: components/dom_distiller/ios/distiller_page_ios.mm |
diff --git a/components/dom_distiller/ios/distiller_page_ios.mm b/components/dom_distiller/ios/distiller_page_ios.mm |
index a20326d2b7e9152d4586bf6b66baded77b1e2646..11922493161cc741845837f3d08253bea4836be1 100644 |
--- a/components/dom_distiller/ios/distiller_page_ios.mm |
+++ b/components/dom_distiller/ios/distiller_page_ios.mm |
@@ -10,6 +10,7 @@ |
#include "base/json/json_reader.h" |
#include "base/logging.h" |
+#include "base/memory/ptr_util.h" |
#include "base/strings/sys_string_conversions.h" |
#include "base/values.h" |
#include "ios/public/provider/web/web_controller_provider.h" |
@@ -54,8 +55,7 @@ DistillerPageIOS::~DistillerPageIOS() { |
} |
bool DistillerPageIOS::StringifyOutput() { |
- // UIWebView requires JavaScript to return a single string value. |
- return true; |
+ return false; |
} |
void DistillerPageIOS::DistillPageImpl(const GURL& url, |
@@ -89,30 +89,79 @@ void DistillerPageIOS::OnLoadURLDone( |
// provider. |
if (load_completion_status == web::PageLoadCompletionStatus::FAILURE || |
!provider_) { |
- HandleJavaScriptResultString(@""); |
+ HandleJavaScriptResult(nil); |
return; |
} |
// Inject the script. |
base::WeakPtr<DistillerPageIOS> weak_this = weak_ptr_factory_.GetWeakPtr(); |
- provider_->InjectScript(script_, ^(NSString* string, NSError* error) { |
+ provider_->InjectScript(script_, ^(id result, NSError* error) { |
DistillerPageIOS* distiller_page = weak_this.get(); |
if (distiller_page) |
- distiller_page->HandleJavaScriptResultString(string); |
+ distiller_page->HandleJavaScriptResult(result); |
}); |
} |
-void DistillerPageIOS::HandleJavaScriptResultString(NSString* result) { |
+void DistillerPageIOS::HandleJavaScriptResult(id result) { |
std::unique_ptr<base::Value> resultValue = base::Value::CreateNullValue(); |
- if (result.length) { |
- std::unique_ptr<base::Value> dictionaryValue = |
- base::JSONReader::Read(base::SysNSStringToUTF8(result)); |
- if (dictionaryValue && |
- dictionaryValue->IsType(base::Value::TYPE_DICTIONARY)) { |
- resultValue = std::move(dictionaryValue); |
- } |
+ if (result) { |
+ resultValue = ValueResultFromWKResult(result); |
} |
OnDistillationDone(url_, resultValue.get()); |
} |
+// This is duplicated here from ios/web/web_state/ui/web_view_js_utils.mm in |
+// order to handle numbers. The dom distiller proto expects integers and the |
+// generated JSON deserializer does not accept doubles in the place of ints. |
+// However WKWebView only allows us to return "numbers." We need to create |
+// integers and doubles as expected by the proto, which is done by checking if |
+// the number has a fraction or not; since this is a hacky method it's isolated |
+// to this file so as to limit the risk of broken JS calls. |
+std::unique_ptr<base::Value> DistillerPageIOS::ValueResultFromWKResult( |
+ id wk_result) { |
+ if (!wk_result) |
+ return nullptr; |
Eugene But (OOO till 7-30)
2016/09/09 15:28:28
Optional NIT: You can return |base::Value::CreateN
lody
2016/09/19 15:34:36
I'd rather not have any part of this be different
|
+ |
+ std::unique_ptr<base::Value> result; |
+ CFTypeID result_type = CFGetTypeID(wk_result); |
+ if (result_type == CFStringGetTypeID()) { |
+ result.reset(new base::StringValue(base::SysNSStringToUTF16(wk_result))); |
+ DCHECK(result->IsType(base::Value::TYPE_STRING)); |
+ } else if (result_type == CFNumberGetTypeID()) { |
+ if ([wk_result intValue] != [wk_result doubleValue]) { |
+ result.reset(new base::FundamentalValue([wk_result doubleValue])); |
+ DCHECK(result->IsType(base::Value::TYPE_DOUBLE)); |
+ } else { |
+ result.reset(new base::FundamentalValue([wk_result intValue])); |
+ DCHECK(result->IsType(base::Value::TYPE_INTEGER)); |
+ } |
+ } else if (result_type == CFBooleanGetTypeID()) { |
+ result.reset( |
+ new base::FundamentalValue(static_cast<bool>([wk_result boolValue]))); |
+ DCHECK(result->IsType(base::Value::TYPE_BOOLEAN)); |
+ } else if (result_type == CFNullGetTypeID()) { |
+ result = base::Value::CreateNullValue(); |
+ DCHECK(result->IsType(base::Value::TYPE_NULL)); |
+ } else if (result_type == CFDictionaryGetTypeID()) { |
+ std::unique_ptr<base::DictionaryValue> dictionary = |
+ base::MakeUnique<base::DictionaryValue>(); |
+ for (id key in wk_result) { |
+ DCHECK([key respondsToSelector:@selector(UTF8String)]); |
+ const std::string& path([key UTF8String]); |
Eugene But (OOO till 7-30)
2016/09/09 15:28:28
Please use sys_string_conversions instead of |UTF8
lody
2016/09/19 15:34:36
Done.
|
+ dictionary->Set(path, |
+ ValueResultFromWKResult([wk_result objectForKey:key])); |
Eugene But (OOO till 7-30)
2016/09/09 15:28:28
Can this recursion cause a stack overflow?
Eugene But (OOO till 7-30)
2016/09/09 15:28:28
NIT: s/[wk_result objectForKey:key]/wk_result[key]
Eugene But (OOO till 7-30)
2016/09/10 00:23:40
JsonParser measures stack depth: https://cs.chromi
lody
2016/09/19 15:34:36
Duplicated code fixed by jif.
|
+ } |
+ result = std::move(dictionary); |
+ } else if (result_type == CFArrayGetTypeID()) { |
+ std::unique_ptr<base::ListValue> list = base::MakeUnique<base::ListValue>(); |
+ for (id value in wk_result) { |
+ list->Append(ValueResultFromWKResult(value)); |
Eugene But (OOO till 7-30)
2016/09/09 15:28:28
Same question here
lody
2016/09/19 15:34:35
Acknowledged.
|
+ } |
+ result = std::move(list); |
+ } else { |
+ NOTREACHED(); // Convert other types as needed. |
+ } |
+ return result; |
+} |
+ |
} // namespace dom_distiller |